bootloader: flash page erase is on-demand, now fits in 2K

Flash pages are only erased as needed during the flash routine, which makes flashing faster as well as making the transfer consistent.

Later datasheets have the flash clock set to 2MHz. I've set it to 2MHz here. I may undo this change later depending on how slow loading a 14K firmware feels.

Was able to save enough space to reduce bootloader size from almost 2.5K to 2K exactly. Adjusted flash offsets to start from 0x800.

GPIO values are now mostly reset to power-on defaults.

Fixed some formatting. Removed dead code.
This commit is contained in:
true 2023-06-25 05:01:16 -07:00
parent d5cbabf830
commit 46a3ab6007
15 changed files with 336 additions and 249 deletions

View File

@ -22,7 +22,7 @@
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid.241230391" name="Core" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid" useByScannerDiscovery="false" value="0" valueType="string"/>
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex.1728678093" name="Convert to Intel Hex file (-O ihex)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.converthex" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.698382755" name="Toolchain" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain" useByScannerDiscovery="false" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace" valueType="string"/>
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary.1163999831" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary" value="true" valueType="boolean"/>
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary.1163999831" name="Convert to binary file (-O binary)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.convertbinary" useByScannerDiscovery="false" value="true" valueType="boolean"/>
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.1731985094" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
<builder buildPath="${workspace_loc:/HK32F030}/Debug" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.2105898051" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1554269278" name="MCU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">

View File

@ -0,0 +1,134 @@
:020000040800F2
:100000000010002091060008E0060008E006000845
:1000100000000000000000000000000000000000E0
:10002000000000000000000000000000E0060008E2
:100030000000000000000000E006000805000020AD
:1000400010B5064C2378002B07D1054B002B02D0AE
:10005000044800E000BF0123237010BD28000020E9
:10006000000000002C070008044B10B5002B03D043
:100070000349044800E000BF10BDC0460000000076
:100080002C0000202C07000870B5002220250B4C06
:1000900093B299420AD8002070BD013B9BB2E66939
:1000A0002E4205D1002BF8D1FF20F5E7044BF6E7EF
:1000B000002BF9D0636A83540132E9E7003801402C
:1000C000FFFF0000044B1A69120603D5034A5A6069
:1000D000034A5A607047C04600200240230167452A
:1000E000AB89EFCD0120054BDA68024204D1DB6811
:1000F0000018DB0600D402307047C04600200240E2
:1001000010B5B024FFF7EEFF2403012807D1002C1F
:1001100001D1043010BDFFF7E5FF013CF5E7002CED
:10012000F8D10520F6E7F0B56B4CA544012826D0A0
:10013000022827D00027FF24022105A8FFF7A4FFEB
:100140003900050006A8FFF79FFF0221054304A818
:10015000FFF79AFFEDB20543EBB29C4606AB1800E1
:1001600000933A0000235D4D002A0ED16246002A1A
:100170001DD004231C432000594B9D44F0BD802713
:100180000024D9E78027FF00FAE70178013A090245
:100190004B40082192B21EB25B009BB2002E00DAE7
:1001A0006B400139C9B20029F5D10130DCE7002CE0
:1001B00000D089E001204B4904AA08704A4804A9EC
:1001C0000078097912880190814200D0023404A895
:1001D000407952BA411892B20291FF2978D19A42DD
:1001E00001D00123C6E70026B442C4D1B74218D8D3
:1001F000002CC0D13B4B5D68FFF764FF7F19AF4215
:1002000001D0002C37D08023384A11690B43136189
:10021000002C5BD1019B344A01331370314B5F607A
:10022000A9E7304B314D5B680393FFF74BFFFFF7B6
:1002300067FF029B042815D102222B6913432B610F
:10024000039B9B196B6140232A6913432B61FFF7C2
:1002500057FF02222B6993432B61031F5A1E9341C0
:100260005B42DBB2802229690A432A61002B00D05D
:1002700008248036BAE71E4B9D4223D8009B1B788A
:100280000293FFF73DFF04280CD00224009A2B783C
:1002900012789A4201D004231C43009B013501339C
:1002A0000093ACE70122114E336F13433367029B77
:1002B0002B70FFF725FF0122336F93433367042828
:1002C000E4D0E2E701249EE7FF2454E7082452E744
:1002D00002249A4285D14EE7E4FBFFFF2110000083
:1002E0001C04000044000020000000200020024008
:1002F000FF3F00088022034B9862D9691142FCD06D
:100300007047C0460038014010B503780133DBB2B6
:100310000370022B07D91820FFF7ECFF1820FFF716
:10032000E9FFFF2010BD1520FFF7E4FF0020F9E7EB
:1003300070B5050000F09EF8002486B2A64205D8EC
:1003400040230549CA691A42FCD070BD285D0134BA
:10035000FFF7D0FFE4B2F1E70038014001223D4B46
:1003600010B5196886B00A431A605A683A490A40BB
:1003700013215A601A6B8A431A6300229A60374A23
:100380001168080C8AB201420BD1FC24D200A401EE
:100390002240FF24C9001868214018680A4302431C
:1003A0001A60002201920292039204920592196847
:1003B00001320A431A602A4A2A4811680140116032
:1003C00080211068C90101430220116026491A6882
:1003D00002400292019A01320192029A002A02D14D
:1003E000019A8A42F3D11968022208001040114292
:1003F0002DD0013A029202991C4A012923D10720EB
:10040000116803910399814303910399E9301160C5
:1004100059680491049981430491902104980143FF
:1004200059605968124805910599014003200591CA
:1004300005995960596881435960596859600C2180
:1004400058680842FCD10023536706B010BD0290E3
:10045000D1E7C046001002401CB8FFF820F8FF1F8B
:10046000E8100240FF81FFFFFFFF00000020024074
:10047000FFF8FFFF0023C25C0133002AFBD1581EA6
:1004800070470000B0236D495B034A69F0B5134320
:1004900090224B6104200023D2051360684DD06088
:1004A00068486B60AB602860A020E024664E0001C5
:1004B00030601269654A664F1268664A66487A601B
:1004C000026A24061202120A224302620722F02064
:1004D000BB603A602A6A614C82432A621022286A11
:1004E00085B002432A62326A5D480240326280224D
:1004F000306A52020243326280228869D20102438A
:100500008A610C22236022606360A3604533E3604C
:100510002268443B13430D202360FFF7EBFE0A20C3
:10052000FFF7E8FE1F263D20013EFFF7E3FE002E09
:10053000F9D14C48FFF7FCFE1F363D20013EFFF786
:10054000D9FE002EF9D14848FFF7F2FE02AB5E1D3E
:10055000002302AA9371454A337013700122444B61
:100560001A70424B394A5A603378002B06D03378E0
:10057000002B40D03F48FFF7DBFEE4E702AA012151
:10058000D01DD371FFF780FD0190002806D0374BB6
:100590001B78002B0FD14320FFF7ACFE02ABD879BC
:1005A000042825D00DD8431E012B0FD9019B002B09
:1005B000DAD102AB17E002AB981DFFF7A5FE307051
:1005C000ECE71828F2D1FF233370CDE7FFF7ABFD3E
:1005D000002803D10630FFF78DFEC5E702AB0828DF
:1005E00001D103229A71981DFFF78EFE3070BBE790
:1005F0000620FFF77FFE00261F48FFF799FE1F4BDE
:100600003E607B60BB6090231D4ADB052660266050
:10061000E660DA601A601B4B0B4A13602B600B4AD2
:10062000194B1B68126882F308888021174A090158
:1006300051679847300005B0F0BDC0460010024039
:10064000000C0048084800000004004800080008AA
:1006500010E000E07F1A060000ED00E000380140E5
:10066000FFFFF0FF4407000868070008440000206F
:1006700000000020AE07000890070008FFFFFF0001
:10068000FFFF0000FFFB00000408000800200240FC
:100690000D4885460D480E490E4A002302E0D45805
:1006A000C4500433C4188C42F9D30B4A0B4C0023BA
:1006B00001E013600432A242FBD3FFF74FFE00F0CB
:1006C00011F8FFF7DFFEFEE7001000200000002019
:1006D00028000020D8070008280000205000002033
:1006E000FEE7000070B500260C4D0D4C641BA410F5
:1006F000A64209D1002600F019F80A4D0A4C641BE5
:10070000A410A64205D170BDB300EB58984701363E
:10071000EEE7B300EB5898470136F2E7D007000840
:10072000D0070008D0070008D4070008F8B5C04675
:10073000F8BC08BC9E467047F8B5C046F8BC08BC7B
:040740009E4670471A
:100744000D0A74727565436F6E74726F6C20484B3A
:10075400333246204C6F616465722076302E302E21
:10076400320D0A000D0A0D0A73656E642066697203
:100774006D776172652066696C65207573696E6753
:1007840020584D4F44454D0D0A0D0A000D0A666C64
:1007940061736820757064617465643B20626F6F77
:1007A40074696E672E0D0A0D0A000D0A6661696C84
:1007B400656420746F207570646174653B20747285
:0C07C4007920616761696E2E0D0A00004B
:0407D00069000008B4
:0407D40041000008D8
:1007D800010000000123064A117A4B40137280225F
:1007E800044B012901D09A6270479A61FCE7C04620
:0807F80044000020000C004841
:040000050800069158
:00000001FF

View File

@ -2,12 +2,13 @@
<launchConfiguration type="com.st.stm32cube.ide.mcu.debug.launch.launchConfigurationType">
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.device" value="HK32F030MF4P6"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.endian" value="little"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.init_speed" value="4000"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.init_speed" value="2000"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.jlink_check_serial_number" value="false"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.jlink_script_path" value=""/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.jlink_script_used" value="false"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.jlink_txt_serial_number" value=""/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.reset_strategy" value="type_0_normal"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.restart_configurations" value="{&quot;fVersion&quot;:1,&quot;fItems&quot;:[{&quot;fDisplayName&quot;:&quot;Type 0: Normal&quot;,&quot;fIsSuppressible&quot;:false,&quot;fResetAttribute&quot;:&quot;Type 0: Normal&quot;,&quot;fResetStrategies&quot;:[{&quot;fDisplayName&quot;:&quot;None&quot;,&quot;fLaunchAttribute&quot;:&quot;no_reset&quot;,&quot;fGdbCommands&quot;:[],&quot;fCmdOptions&quot;:[]},{&quot;fDisplayName&quot;:&quot;Type 0: Normal&quot;,&quot;fLaunchAttribute&quot;:&quot;type_0_normal&quot;,&quot;fGdbCommands&quot;:[&quot;monitor reset\r\n&quot;],&quot;fCmdOptions&quot;:[]}],&quot;fGdbCommandGroup&quot;:{&quot;name&quot;:&quot;Additional commands&quot;,&quot;commands&quot;:[]},&quot;fStartApplication&quot;:true}]}"/>
<intAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.rtos_implementation" value="1"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.scan_chain_auto" value="true"/>
<intAttribute key="com.st.stm32cube.ide.mcu.debug.jlink.scan_chain_irpre" value="0"/>
@ -22,7 +23,7 @@
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.ip_address_local" value="localhost"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.launch.limit_swo_clock.enabled" value="false"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.limit_swo_clock.value" value=""/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.loadList" value="{&quot;fItems&quot;:[{&quot;fIsFromMainTab&quot;:true,&quot;fPath&quot;:&quot;_dbg/hk32f030m_xmodem_bl.elf&quot;,&quot;fProjectName&quot;:&quot;bootloader_hk32f030m_uart_xmodem&quot;,&quot;fPerformBuild&quot;:true,&quot;fDownload&quot;:true,&quot;fLoadSymbols&quot;:true}]}"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.loadList" value="{&quot;fItems&quot;:[{&quot;fIsFromMainTab&quot;:true,&quot;fPath&quot;:&quot;_dbg/bootloader_hk32f030m_uart_xmodem.elf&quot;,&quot;fProjectName&quot;:&quot;bootloader_hk32f030m_uart_xmodem&quot;,&quot;fPerformBuild&quot;:true,&quot;fDownload&quot;:true,&quot;fLoadSymbols&quot;:true}]}"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.override_start_address_mode" value="default"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.remoteCommand" value="target extended-remote"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.launch.startServer" value="true"/>
@ -34,7 +35,7 @@
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.swv_trace_hclk" value="8000000"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.launch.useRemoteTarget" value="true"/>
<stringAttribute key="com.st.stm32cube.ide.mcu.debug.launch.vector_table" value=""/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.launch.verify_flash_download" value="true"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.launch.verify_flash_download" value="false"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.stlink.cti_allow_halt" value="false"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.stlink.cti_signal_halt" value="false"/>
<booleanAttribute key="com.st.stm32cube.ide.mcu.debug.stlink.enable_logging" value="false"/>
@ -76,7 +77,7 @@
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="remote"/>
<booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="true"/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="_dbg/hk32f030m_xmodem_bl.elf"/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="_dbg/bootloader_hk32f030m_uart_xmodem.elf"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="bootloader_hk32f030m_uart_xmodem"/>
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.debug.1673231411"/>
@ -86,5 +87,6 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&lt;memoryBlockExpressionList context=&quot;reserved-for-future-use&quot;/&gt;"/>
<stringAttribute key="process_factory_id" value="com.st.stm32cube.ide.mcu.debug.launch.HardwareDebugProcessFactory"/>
</launchConfiguration>

View File

@ -15,8 +15,9 @@
#define FLASH_SIZE 16384 // size of overall flash available on MCU
#define FLASH_ERASE_PAGE_SIZE ((uint16_t)0x80) // erase page size
#define FLASH_ERASE_PAGE_MASK 0x7f // bitmask of page size
#define USER_APP_START_ADDR ((uint32_t)FLASH_BASE + 0xa00) // 2560 bytes (20 pages) rsvd for bootloader
#define USER_APP_START_ADDR ((uint32_t)FLASH_BASE + 0x800) // 2048 bytes (16 pages) rsvd for bootloader
#define USER_APP_END_ADDR ((uint32_t)FLASH_BASE + FLASH_SIZE)
@ -32,7 +33,7 @@ typedef enum {
BL_flash_status flash_erase_user_app();
BL_flash_status flash_erase_page(uint32_t addr);
BL_flash_status flash_write(uint32_t addr, uint8_t *data, uint16_t length);
void jump_to_user_app();

View File

@ -9,7 +9,7 @@
#define CODE_INC_USART_H_
#define COMM_TIMEOUT 512000;
#define COMM_TIMEOUT 0xffff;
@ -24,7 +24,7 @@ typedef enum {
void comm_init();
BL_comm_status comm_rx(uint8_t *data, uint16_t length);
BL_comm_status comm_tx_str(uint8_t *data);
BL_comm_status comm_tx_str(char *data);
BL_comm_status comm_tx_byte(uint8_t data);

View File

@ -29,7 +29,6 @@
void user_io_init();
void user_led_init();
void user_led_set(uint8_t lit);

View File

@ -72,7 +72,9 @@ typedef enum {
X_ERROR = 0xFFu /**< Generic error. */
} BL_xmodem_status;
void xmodem_receive(void);
BL_xmodem_status xmodem_receive(void);

View File

@ -11,49 +11,22 @@
/**
* @brief This function erases the user application area, from start to end of flash.
* @brief This function erases a single flash page.
* @return status: Report about the success of the erasing.
*/
__attribute__ ((long_call, section(".ramfunc"))) BL_flash_status flash_erase_user_app()
__attribute__ ((long_call, section(".ramfunc"))) BL_flash_status flash_erase_page(uint32_t addr)
{
// uint32_t timeout;
uint32_t page;
BL_flash_status status = FLASH_ERROR;
FLASH_Unlock();
for (page = USER_APP_START_ADDR; page < USER_APP_END_ADDR; page += FLASH_ERASE_PAGE_SIZE) {
if (FLASH_ErasePage(page) != FLASH_COMPLETE) {
FLASH_Lock();
return FLASH_ERROR;
}
/*
// clear end of operation bit
FLASH->SR &= ~FLASH_FLAG_EOP;
// start erasing page
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = page;
FLASH->CR |= FLASH_CR_STRT;
// wait wait for operation to complete
timeout = FLASH_ER_PRG_TIMEOUT;
while ((FLASH->SR & FLASH_FLAG_BSY)) {
timeout--;
if (!timeout) {
FLASH_Lock();
return FLASH_ERROR;
}
}
// disable page erase bit
FLASH->CR &= ~FLASH_CR_PER;
*/
if (FLASH_ErasePage(addr) == FLASH_COMPLETE) {
status = FLASH_OK;
}
FLASH_Lock();
return FLASH_OK;
return status;
}
/**
@ -71,23 +44,23 @@ __attribute__ ((long_call, section(".ramfunc"))) BL_flash_status flash_write(uin
/* Loop through the data. */
for (uint32_t i = 0u; (i < length) && (status == FLASH_OK); i++) {
if (addr >= USER_APP_END_ADDR) {
status = FLASH_ERROR_SIZE;
break;
} else {
/* The actual flashing. If there is an error, then report it. */
if (FLASH_ProgramByte(addr, data[i]) != FLASH_COMPLETE) {
status |= FLASH_ERROR_WRITE;
}
if (addr >= USER_APP_END_ADDR) {
status = FLASH_ERROR_SIZE;
break;
} else {
/* The actual flashing. If there is an error, then report it. */
if (FLASH_ProgramByte(addr, data[i]) != FLASH_COMPLETE) {
status |= FLASH_ERROR_WRITE;
}
/* Read back the content of the memory. If it is wrong, then report an error. */
if (data[i] != (*(volatile uint8_t *)addr)) {
status |= FLASH_ERROR_VERIFY;
}
/* Read back the content of the memory. If it is wrong, then report an error. */
if (data[i] != (*(volatile uint8_t *)addr)) {
status |= FLASH_ERROR_VERIFY;
}
/* Shift the address by a word. */
addr++;
}
/* Shift the address by a word. */
addr++;
}
}
FLASH_Lock();
@ -109,6 +82,12 @@ void jump_to_user_app()
USART1->CR1 = 0;
USART1->BRR = 0;
// configure GPIO back to default
GPIOA->PUPDR = (uint32_t)0xffff; // although marked as reserved, it is the default per datasheet
GPIOA->MODER = (uint32_t)0xffff;
GPIOB->MODER = (uint32_t)0xfbff;
GPIOD->MODER = (uint32_t)0xfbff;
// disable configured interrupts
// NVIC->ICER[0] = 0;

View File

@ -22,8 +22,8 @@
int main(void)
{
uint8_t btn;
//volatile uint16_t timeout = 0xffff;
uint32_t i;
uint32_t btn;
// ensure the bootloader is write protected
// TODO
@ -31,9 +31,6 @@ int main(void)
// configure button and LED
user_io_init();
// need a small delay to ensure the button pullup/down will charge/discharge pin capacitance
//while (--timeout);
// get button state
btn = BTN_PORT->IDR & (1 << BTN_PIN);
#if BTN_ACT_DIR == 0
@ -41,34 +38,45 @@ int main(void)
#endif
// bootloader activation methods
if (btn // button pushed
|| (*(volatile uint32_t *)USER_APP_START_ADDR) == 0x00000000 // flash empty
|| (*(volatile uint32_t *)USER_APP_START_ADDR) == 0xFFFFFFFF) { // flash empty
// bootloader is activated, show it
i = *(volatile uint32_t *)USER_APP_START_ADDR; // first byte of user flash
if (btn || (i == 0x00000000) || (i = 0xffffffff)) { // is button pushed, or flash empty?
// bootloader is activated; configure systick to flash LED
user_led_init();
// configure serial comms and print welcome banner
// todo: implement autobaud?
comm_init();
const uint8_t *banner_bar = (uint8_t *)"\r\n================================================\r\n";
comm_tx_str((uint8_t *)banner_bar);
comm_tx_str((uint8_t *)"trueControl HK32F XMODEM Flash Bootloader v0.0.1");
comm_tx_str((uint8_t *)banner_bar);
comm_tx_byte('\r');
comm_tx_byte('\n');
for (i = 0; i < 31; i++) {
comm_tx_byte('=');
}
comm_tx_str("\r\ntrueControl HK32F Loader v0.0.2\r\n");
for (i = 0; i < 31; i++) {
comm_tx_byte('=');
}
// wait for firmware load or reset
while(1) {
comm_tx_str((uint8_t*)"\r\nsend binary file using XMODEM to update firmware");
comm_tx_str((uint8_t*)"\r\nthe first data block will take time. it's normal\r\n\r\n");
xmodem_receive();
// announce bootloader start
comm_tx_str("\r\n\r\nsend firmware file using XMODEM\r\n\r\n");
// start listening for data and letting user know to send XMODEM data
if (xmodem_receive() == X_OK) {
comm_tx_str("\r\nflash updated; booting.\r\n\r\n");
break;
}
// if xmodem exits, there was a failure. repeat the process.
comm_tx_str((uint8_t*)"\r\nfailed to update. try again.\r\n");
comm_tx_str("\r\nfailed to update; try again.\r\n");
}
}
// bootloader is not activated; jump to user code
// bootloader is either done not activated; jump to user code
jump_to_user_app();
}

View File

@ -41,16 +41,14 @@ uint16_t rxlen = 0;
*/
void comm_init()
{
// USART_InitTypeDef usart;
// NVIC_InitTypeDef nvic;
// enable GPIO clock
RCC_AHBPeriphClockCmd(USART_TX_GPIO_CLK | USART_RX_GPIO_CLK, ENABLE);
// RCC_AHBPeriphClockCmd(USART_TX_GPIO_CLK | USART_RX_GPIO_CLK, ENABLE);
// configure USART GPIO
GPIO_PinAFConfig(USART_TX_PORT, USART_TX_PINSRC, GPIO_AF_1);
GPIO_PinAFConfig(USART_RX_PORT, USART_RX_PINSRC, GPIO_AF_1);
/* these have been configured in user_io.c to save space
USART_RX_PORT->MODER &= ~(GPIO_MODER_MODER0 << 2 * USART_RX_PIN);
USART_RX_PORT->MODER |= (GPIO_Mode_AF << 2 * USART_RX_PIN); // alt function
@ -58,46 +56,25 @@ void comm_init()
USART_TX_PORT->OTYPER &= ~(GPIO_OTYPER_OT_0 << USART_TX_PIN); // push pull
USART_TX_PORT->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEEDR0 << 2 * USART_TX_PIN); // slow
USART_TX_PORT->MODER |= (GPIO_Mode_AF << 2 * USART_TX_PIN); // alt function
// configure NVIC
/*
nvic.NVIC_IRQChannel = USART1_IRQn;
nvic.NVIC_IRQChannelPriority = 1;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
*/
// enable USART clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*
// configure USART peripheral
usart.USART_BaudRate = BAUDRATE;
usart.USART_WordLength = USART_WordLength_8b;
usart.USART_StopBits = USART_StopBits_1;
usart.USART_Parity = USART_Parity_No;
usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &usart);
*/
// configure USART peripheral manually
// we do this as the library uses division which bloats flash space
// we do this as the library bloats flash space (division, verbose, ...)
USART1->CR1 = 0; // disable USART
USART1->CR1 = USART_Mode_Rx | USART_Mode_Tx; // 8 bits, no parity, tx/rx enabled
USART1->CR2 = 0; // 1 stop bit
USART1->CR3 = 0;
USART1->BRR = 0x45; // 115200 baud rate @8MHz (per datasheet)
// enable USART interrupts
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// enable USART
USART1->CR1 |= USART_CR1_UE;
}
/**
* @brief Receives data from USART.
* @brief Receives data from USART in a polling manner.
* @param *data: Array to save the received data.
* @param length: Size of the data.
* @return status: Report about the success of the receiving.
@ -107,24 +84,8 @@ BL_comm_status comm_rx(uint8_t *data, uint16_t length)
uint16_t i;
uint16_t timeout;
/*
// wait for more data to arrive
timeout = COMM_TIMEOUT;
while (rxlen < length) {
timeout--;
if (!timeout) return COMM_RX_TIMEOUT;
}
// copy data to final buffer
for (i = 0; i < length; i++) {
data[i] = rxbuf[rxptr++];
if (rxptr >= RX_BUF_LEN) rxptr = 0;
rxlen--;
}
*/
for (i = 0; i < length; i++) {
timeout = 0xffff;
timeout = COMM_TIMEOUT;
while (!(USART1->ISR & USART_ISR_RXNE_Msk) && timeout) {
timeout--;
}
@ -160,40 +121,19 @@ BL_comm_status comm_tx_byte(uint8_t data)
* @param *data: String array.
* @return status: Report about the success of the transmission.
*/
BL_comm_status comm_tx_str(uint8_t *data)
BL_comm_status comm_tx_str(char *data)
{
uint8_t i;
uint16_t len = 0;
len = strlen((const char *)data);
for(i = 0; i < len; i++) {
for (i = 0; i < len; i++) {
comm_tx_byte(data[i]);
}
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return COMM_OK;
}
/*
void USART1_IRQHandler()
{
uint8_t data;
if (USART1->ISR & USART_ISR_RXNE_Msk) {
// read data
data = USART1->RDR;
// only add data if there is room
if (rxlen >= RX_BUF_LEN) return;
rxlen++;
// next position
if (++rxptr >= RX_BUF_LEN) rxptr = 0;
// save data
rxbuf[rxptr] = data;
}
}
*/

View File

@ -14,8 +14,9 @@
void user_io_init()
{
// enable gpio clocks
RCC_AHBPeriphClockCmd(BTN_CLK | LED_CLK, ENABLE);
RCC_AHBPeriphClockCmd(BTN_CLK | LED_CLK | RCC_AHBPeriph_GPIOB, ENABLE);
/* --original method, not space efficient
// configure led
#if LED_ACT_DIR == 0
LED_PORT->BSRR = (1 << LED_PIN); // idle high
@ -25,16 +26,44 @@ void user_io_init()
LED_PORT->OTYPER &= ~(GPIO_OTYPER_OT_0 << LED_PIN); // push pull
LED_PORT->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEEDR0 << 2 * LED_PIN); // slow
LED_PORT->MODER &= ~(GPIO_MODER_MODER0 << 2 * LED_PIN);
LED_PORT->MODER |= (GPIO_Mode_OUT << 2 * LED_PIN); // output
LED_PORT->MODER = (GPIO_Mode_OUT << 2 * LED_PIN); // output
// configure button
BTN_PORT->MODER &= ~(GPIO_MODER_MODER0 << 2 * BTN_PIN); // input
BTN_PORT->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << 2 * BTN_PIN);
#if BTN_ACT_DIR == 0
BTN_PORT->PUPDR |= (GPIO_PuPd_UP << 2 * BTN_PIN); // pulled high
//BTN_PORT->PUPDR |= (GPIO_PuPd_UP << 2 * BTN_PIN); // pulled high
BTN_PORT->PUPDR = (GPIO_PuPd_UP << 2 * BTN_PIN); // pulled high
#else
BTN_PORT->PUPDR |= (GPIO_PuPd_DOWN << 2 * BTN_PIN); // pulled low
//BTN_PORT->PUPDR |= (GPIO_PuPd_DOWN << 2 * BTN_PIN); // pulled low
BTN_PORT->PUPDR = (GPIO_PuPd_DOWN << 2 * BTN_PIN); // pulled low
#endif
*/
/* new method, configure USART pins at the same time as LED and btn
* at they are on the same ports
*/
// default MODER for GPIOB and GPIOD are 0xFBFF
// pin 5 _must_ be configured as AF, otherwise you'll kill debugging!
// configure button as input
BTN_PORT->MODER = 0x0;
#if BTN_ACT_DIR == 0
//BTN_PORT->PUPDR |= (GPIO_PuPd_UP << 2 * BTN_PIN); // pulled high
BTN_PORT->PUPDR = (GPIO_PuPd_UP << 2 * BTN_PIN); // pulled high
#else
//BTN_PORT->PUPDR |= (GPIO_PuPd_DOWN << 2 * BTN_PIN); // pulled low
BTN_PORT->PUPDR = (GPIO_PuPd_DOWN << 2 * BTN_PIN); // pulled low
#endif
// configure LED as PP output, USART TX as AF
LED_PORT->OTYPER = 0;
LED_PORT->OSPEEDR = 0;
LED_PORT->MODER = 0x800 | (GPIO_Mode_OUT << (2 * LED_PIN)) | (GPIO_Mode_AF << (2 * 1));
// configure USART RX as AF
GPIOB->MODER = 0x800 | (GPIO_Mode_AF << (2 * 4));
}
void user_led_init()
@ -43,14 +72,3 @@ void user_led_init()
SysTick_Config(8000000 / 20);
}
void user_led_set(uint8_t lit)
{
#if LED_ACT_DIR == 0
if (lit) LED_PORT->BRR = (1 << LED_PIN);
else LED_PORT->BSRR = (1 << LED_PIN);
#else
if (lit) LED_PORT->BSRR = (1 << LED_PIN);
else LED_PORT->BRR = (1 << LED_PIN);
#endif
}

View File

@ -34,7 +34,7 @@ static BL_xmodem_status xmodem_error_handler(uint8_t *error_number, uint8_t max_
* @param void
* @return void
*/
void xmodem_receive(void)
BL_xmodem_status xmodem_receive(void)
{
volatile BL_xmodem_status status = X_OK;
uint8_t error_number = 0u;
@ -51,7 +51,7 @@ void xmodem_receive(void)
BL_comm_status status_c = comm_rx(&header, 1);
/* Spam the host (until we receive something) with ACSII "C", to notify it, we want to use CRC-16. */
if ((status_c != COMM_OK) && (x_first_packet_rcvd == false)) {
if ((status_c != COMM_OK) && (x_first_packet_rcvd == 0)) {
comm_tx_byte(X_C);
}
@ -96,9 +96,7 @@ void xmodem_receive(void)
case X_EOT: {
/* ACK, feedback to user (as a text), then jump to user application. */
comm_tx_byte(X_ACK);
comm_tx_str((uint8_t*)"\r\nfirmware updated.\r\nstarting firmware.\r\n\r\n");
jump_to_user_app();
break;
return X_OK;
}
/* Abort from host. */
@ -116,6 +114,8 @@ void xmodem_receive(void)
}
}
}
return status;
}
/**
@ -127,22 +127,19 @@ void xmodem_receive(void)
static uint16_t xmodem_calc_crc(uint8_t *data, uint16_t length)
{
uint16_t crc = 0u;
while (length)
{
while (length) {
length--;
crc = crc ^ ((uint16_t)*data++ << 8u);
for (uint8_t i = 0u; i < 8u; i++)
{
if (crc & 0x8000u)
{
for (uint8_t i = 0u; i < 8u; i++) {
if (crc & 0x8000u) {
crc = (crc << 1u) ^ 0x1021u;
}
else
{
} else {
crc = crc << 1u;
}
}
}
return crc;
}
@ -154,7 +151,8 @@ static uint16_t xmodem_calc_crc(uint8_t *data, uint16_t length)
static BL_xmodem_status xmodem_handle_packet(uint8_t header)
{
BL_xmodem_status status = X_OK;
uint16_t size = 0u;
uint16_t size = 0;
uint32_t i;
/* 2 bytes for packet number, 1024 for data, 2 for CRC*/
uint8_t rcvd_packet_number[X_PACKET_NUMBER_SIZE];
@ -190,13 +188,9 @@ static BL_xmodem_status xmodem_handle_packet(uint8_t header)
status |= X_ERROR_UART;
}
/* If it is the first packet, then erase the memory. */
if ((status == X_OK) && (x_first_packet_rcvd == false)) {
if (flash_erase_user_app() == FLASH_OK) {
x_first_packet_rcvd = true;
} else {
status |= X_ERROR_FLASH;
}
/* If it is the first packet, then mark it. If you want to erase all flash, do it here. */
if ((status == X_OK)) { // && (x_first_packet_rcvd == 0)) {
x_first_packet_rcvd = 1;
}
/* Error handling and flashing. */
@ -219,11 +213,22 @@ static BL_xmodem_status xmodem_handle_packet(uint8_t header)
}
/* Do the actual flashing if there weren't any errors. */
if ((status == X_OK) &&
(flash_write(xmodem_flash_w_addr, rcvd_packet_data, size)) != FLASH_OK) {
if (status == X_OK) {
/* first, erase pages depending on size */
for (i = 0; i < size; i += FLASH_ERASE_PAGE_SIZE) {
if (flash_erase_page(xmodem_flash_w_addr + i) != FLASH_OK) {
/* Flashing error. */
status |= X_ERROR_FLASH;
}
}
/* Flashing error. */
status |= X_ERROR_FLASH;
/* then write data to these cleared pages */
if (status == X_OK) {
if (flash_write(xmodem_flash_w_addr, rcvd_packet_data, size) != FLASH_OK) {
/* Flashing error. */
status |= X_ERROR_FLASH;
}
}
}
/* Raise the packet number and the address counters (if there weren't any errors). */

View File

@ -112,8 +112,8 @@ Infinite_Loop:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word Default_Handler // NMI_Handler
.word Default_Handler // HardFault_Handler
.word 0
.word 0
.word 0
@ -121,43 +121,43 @@ g_pfnVectors:
.word 0
.word 0
.word 0
.word SVC_Handler
.word Default_Handler // SVC_Handler
.word 0
.word 0
.word PendSV_Handler
.word Default_Handler // PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler /* Window WatchDog */
.word 0 /* Reserved */
.word EXTI11_IRQHandler /* EXTI Line 11 interrupt(AWU_WKP) */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
.word EXTI0_IRQHandler /* EXTI Line 0 */
.word EXTI1_IRQHandler /* EXTI Line 1 */
.word EXTI2_IRQHandler /* EXTI Line 2 */
.word EXTI3_IRQHandler /* EXTI Line 3 */
.word EXTI4_IRQHandler /* EXTI Line 4 */
.word EXTI5_IRQHandler /* EXTI Line 5 */
.word TIM1_BRK_IRQHandler /* TIM1 break interrupt */
.word ADC1_IRQHandler /* ADC1 interrupt, combined with EXTI line 8 */
.word TIM1_UP_TRG_COM_IRQHandler /* TIM1 Update, Trigger and Commutation */
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
.word TIM2_IRQHandler /* TIM2 */
.word 0 /* Reserved */
.word TIM6_IRQHandler /* TIM6 */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word EXTI6_IRQHandler /* EXTI Line 6 */
.word EXTI7_IRQHandler /* EXTI Line 7 */
.word I2C1_IRQHandler /* I2C1 global interrupt, combined with EXTI Line 10 */
.word 0 /* Reserved */
.word SPI1_IRQHandler /* SPI1 */
.word 0 /* Reserved */
.word USART1_IRQHandler /* USART1 global interrupt, combined with EXTI Line 9 */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word 0 /* Reserved */
.word 0 /* Reserved */
// .word WWDG_IRQHandler /* Window WatchDog */
// .word 0 /* Reserved */
// .word EXTI11_IRQHandler /* EXTI Line 11 interrupt(AWU_WKP) */
// .word FLASH_IRQHandler /* FLASH */
// .word RCC_IRQHandler /* RCC */
// .word EXTI0_IRQHandler /* EXTI Line 0 */
// .word EXTI1_IRQHandler /* EXTI Line 1 */
// .word EXTI2_IRQHandler /* EXTI Line 2 */
// .word EXTI3_IRQHandler /* EXTI Line 3 */
// .word EXTI4_IRQHandler /* EXTI Line 4 */
// .word EXTI5_IRQHandler /* EXTI Line 5 */
// .word TIM1_BRK_IRQHandler /* TIM1 break interrupt */
// .word ADC1_IRQHandler /* ADC1 interrupt, combined with EXTI line 8 */
// .word TIM1_UP_TRG_COM_IRQHandler /* TIM1 Update, Trigger and Commutation */
// .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
// .word TIM2_IRQHandler /* TIM2 */
// .word 0 /* Reserved */
// .word TIM6_IRQHandler /* TIM6 */
// .word 0 /* Reserved */
// .word 0 /* Reserved */
// .word 0 /* Reserved */
// .word EXTI6_IRQHandler /* EXTI Line 6 */
// .word EXTI7_IRQHandler /* EXTI Line 7 */
// .word I2C1_IRQHandler /* I2C1 global interrupt, combined with EXTI Line 10 */
// .word 0 /* Reserved */
// .word SPI1_IRQHandler /* SPI1 */
// .word 0 /* Reserved */
// .word USART1_IRQHandler /* USART1 global interrupt, combined with EXTI Line 9 */
// .word 0 /* Reserved */
// .word 0 /* Reserved */
// .word 0 /* Reserved */
// .word 0 /* Reserved */
/*******************************************************************************
*
@ -182,6 +182,7 @@ g_pfnVectors:
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
/*
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
@ -244,3 +245,4 @@ g_pfnVectors:
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
*/

View File

@ -170,7 +170,7 @@ static void SetSysClockToHSI(void)
* Datasheet and RM was updated in 2023 which derated flash programming from 4MHz
* 0x07 = 4MHz, 0x08 = 2MHz. change as you see fit */
RCC->CFGR4 &= ~(RCC_RCC_CFGR4_FLITFCLK_PRE | RCC_RCC_CFGR4_FLITFCLK_SE);
RCC->CFGR4 |= (((uint32_t)0x07) << RCC_RCC_CFGR4_FLITFCLK_PRE_Pos);
RCC->CFGR4 |= (((uint32_t)0x08) << RCC_RCC_CFGR4_FLITFCLK_PRE_Pos);
/* Wait until HSI is ready; if timeout is reached, then exit */
do {
@ -386,33 +386,30 @@ static void SetSysClockToEXTCLK(void)
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, presc = 0;
uint32_t tmp = 0, presc = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
SystemCoreClock = HCLK_FREQ;
break;
case RCC_CFGR_SWS_EXTCLK: /* EXTCLK used as system clock */
SystemCoreClock = EXTCLK_VALUE;
break;
case RCC_CFGR_SWS_LSI: /* LSI used as system clock */
SystemCoreClock = LSI_VALUE;
break;
switch (tmp) {
case RCC_CFGR_SWS_EXTCLK: // EXTCLK used as system clock
SystemCoreClock = EXTCLK_VALUE;
break;
case RCC_CFGR_SWS_LSI: // LSI used as system clock
SystemCoreClock = LSI_VALUE;
break;
default: /* HSI used as system clock */
SystemCoreClock = HCLK_FREQ;
break;
}
case RCC_CFGR_SWS_HSI: // HSI used as system clock
default:
SystemCoreClock = HCLK_FREQ;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = RCC->CFGR & RCC_CFGR_HPRE;
tmp = tmp >> 4;
presc = AHBPrescTable[tmp];
/* HCLK clock frequency */
SystemCoreClock = SystemCoreClock/presc;
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = RCC->CFGR & RCC_CFGR_HPRE;
tmp = tmp >> 4;
presc = AHBPrescTable[tmp];
/* HCLK clock frequency */
SystemCoreClock = SystemCoreClock/presc;
}