2019-10-25 07:13 AM
I am trying to implement a procedure to update firmware in a STM32L476 by jumping to the bootloader from user code. I am able to connect Boot0 to 3,3V and enter the bootloader just fine. But trying to jump there from user code seems to be giving some problems.
It seems that when I execute my code, the device does a soft reset, and just restarts the application. I believe it may have something to do with the dual bank management. Even when I jump to the bootloader, I think it is checking both ram locations and finding valid code, thus not staying in the bootloader. Here is my code:
void JumpToBootloader(void)
{
void (*SysMemBootJump)(void);
// Step: Set system memory address
// See AN2606 rev 38, Table 118
volatile uint32_t addr = 0x1FFF0000;
// Step: Disable RCC, set it to default (after reset) settings
// Internal clock, no PLL, etc.
HAL_RCC_DeInit();
// 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: ARM Cortex-M Programming Guide to Memory Barrier Instructions
__DSB();
// Step: Remap system memory to address 0x0000 0000 in address space
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); // Call HAL macro to do this for you
// Step: Remap is not visible at once. Execute some unrelated command! */
__DSB();
__ISB();
// Step: Set jump memory location for system memory
// Use address with 4 bytes offset which specifies jump location where program starts
uint32_t a = 0x1FFF0000 + 4;
SysMemBootJump = (void (*)(void)) (*((uint32_t *)(a)));
// 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
uint32_t p = *(uint32_t *)0x1FFF0000;
__set_MSP(p);
// Step: Actually call our function to jump to set location
// This will start system memory execution
SysMemBootJump();
while(1);
// Step: Use STM32CubeProgrammer or custom application to update firmware.
}
For testing purposes, I am just calling this function right after main() starts. One other thing I will need to be able to do is activate a GPIO to enable my RS232 chip that is connected to USART2. So I need that G?PIO to stay in the state I put it in instead of the reset state, is this possible
2019-10-25 08:02 AM
I seem to have to repeat this a lot, but this is like throwing your keys in the lake when you've asked the mechanic to work on the car, its unhelpful.
// Step: Disable all interrupts
__disable_irq();
You need to disable the sources, not the processor. The loader will not re-enable this.
The L4 loader may also quite likely bounce back if it finds executable code in FLASH.
No, you're not going to be able to fiddle with GPIO or clocks and expect the loader to honour them.
If you have custom hardware that needs special conditions you will either need to write your own loader, or find a way to leverage entry points into the ROM.
2019-10-25 08:12 AM
I understand that disabling the interrupts this way isn't the cleanest, but I am just using this procedure as a test to try to see if I can jump to the bootloader successfully. I am calling this function before I've even enabled any interrupts. When I get to where I can enter the bootloader, I will do this procedure more elegantly and disable all individual interrupts.
So, to the real problem, is it not possible to use the bootloader on the L4 from code since it just bounces back if there is already code in FLASH?
Lastly, if I configure the GPIO before jumping to the bootloader, will it lose its state upon entering it? I dont need to change them while in the bootloader, just need to make sure my RS232 chip stays enabled in order to communicate to the USART2 peripheral.
2019-11-02 01:33 PM
> The L4 loader may also quite likely bounce back if it finds executable code in FLASH.
At least STM32L432KB starts the system bootloader after reset under these conditions:
> just need to make sure my RS232 chip stays enabled in order to communicate to the USART2 peripheral
Reverse the hardware logic - make that chip enabled by default (with MCU pin at reset state) and disable it in your firmware.
2020-07-31 05:03 AM
In my code, it was also required to suspend the HAL Tick after HAL_RCC_DeInit() and HAL_DeInit() to make it working:
HAL_SuspendTick();