Tutorial – Jump to system memory from software on STM32
One of you are already familiar with STM32 feature of embedded bootloader for software download to flash.
This memory is called system memory and is normally accessible with BOOT configuration (either pin hardware or option bytes (later OB) in flash software).
Normally, if you want to jump to system memory, you have to setup pin/OB and reset device. If you have OB setup, this is ok, but since you need at least one BOOT pin in hardware, this can lead to hardware problems.
This tutorial will cover, how to jump to system memory from current program in STM32. This is a way, how to start STM32 internal bootloader for software update.
Tutorial
This tutorial will cover STM32F4 family, but the same principle works for any other family.
In application note for hardware start for STM32F4 (AN4488) you can find a table showing you how to setup boot pins for different configuration.
BOOT0 pin is dedicated on device, while BOOT1 is shared with PB2. When (normally) main flash memory is used, only BOOT0 configuration is required, BOOT1 pin does not care. To make hardware development easier, we can set BOOT0 pin to GND and force device to always jump to main flash memory.
Since we know system memory is available, we also know that it is somewhere in memory on specific memory location. Now, each device has this on different address, but on STM32F429, which I use, it is available on memory location 0x1FFF0000.
Application note (AN2606)describe bootloader in details and also gives you information on where is memory location for specific device [Table 110].
Since now we know where our memory address is, we have to perform jump to that location and if possible, reflect system memory to 0x00000000 address so that MCU sees this at start address.
Steps for jumping to system memory
If you wish to just from main program to system memory at anytime, some important steps needs to be performed first:
- Find system memory location for specific STM32 in AN2606
- Set RCC to default values (the same as on startup) [Internal clock, no PLL, etc.)
- Disable SysTick interrupt and reset it to default
- Disable all interrupts
- Map system memory to 0x00000000 location
- Set jump location to memory location + 4 bytes offset
- Set main stack pointer to value stored at system memory location address
- Call virtual function assigned before
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
/** * Function to perform jump to system memory boot from user application * * Call function when you want to jump to system memory */ void JumpToBootloader(void) { void (*SysMemBootJump)(void); /** * Step: Set system memory address. * * For STM32F429, system memory is on 0x1FFF 0000 * For other families, check AN2606 document table 110 with descriptions of memory addresses */ volatile uint32_t addr = 0x1FFF0000; /** * Step: Disable RCC, set it to default (after reset) settings * Internal clock, no PLL, etc. */ #if defined(USE_HAL_DRIVER) HAL_RCC_DeInit(); #endif /* defined(USE_HAL_DRIVER) */ #if defined(USE_STDPERIPH_DRIVER) RCC_DeInit(); #endif /* defined(USE_STDPERIPH_DRIVER) */ /** * Step: Disable systick timer and reset it to default values */ SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; /** * Step: Disable all interrupts */ __disable_irq(); /** * Step: Remap system memory to address 0x0000 0000 in address space * For each family registers may be different. * Check reference manual for each family. * * For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0]) * For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0]) * For others, check family reference manual */ //Remap by hand... { #if defined(STM32F4) SYSCFG->MEMRMP = 0x01; #endif #if defined(STM32F0) SYSCFG->CFGR1 = 0x01; #endif //} ...or if you use HAL drivers //__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); //Call HAL macro to do this for you /** * Step: Set jump memory location for system memory * Use address with 4 bytes offset which specifies jump location where program starts */ SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4))); /** * Step: Set main stack pointer. * This step must be done last otherwise local variables in this function * don't have proper value since stack pointer is located on different position * * Set direct address location which specifies stack pointer in SRAM location */ __set_MSP(*(uint32_t *)addr); /** * Step: Actually call our function to jump to set location * This will start system memory execution */ SysMemBootJump(); /** * Step: Connect USB<->UART converter to dedicated USART pins and test * and test with bootloader works with STM32 Flash Loader Demonstrator software */ } |
To test this code, set boot configuration to main flash memory (default on all STM32 evaluation boards) and run program and call function above when desired.
To test, if jump was successful, open STM32 Flash loader demonstrator software and try to connect via UART with external USB<->UART transceiver.
Recent comments