I am implementing an OTA update system for the STM32G4, and want to use the dual flash banks to make it safe. That is, write the new firmware in the inactive flash bank while the main program is still running from the active bank, and reboot only after checking the integrity of the newly installed firmware.
To do this, I'm setting the BFB2
bit from the option bytes to 1, which, according to AN2606 (section 45.2) and this presentation (page 8), tells the MCU to first attempt booting from flash bank 2 if the stack address located at offset 0x0 of the flash bank 2 is a valid SRAM address. Otherwise the MCU boots from flash bank 1. This fits my use case, as I can write the new firmware to the flash bank 2, except for the stack address which is written only after an integrity check to commit the change.
However, it seems the flash banks addresses aren't swapped when booting from the flash bank 2. According to the programming manual (section 10.2.1), swapping the flash banks addresses is done by setting the FB_MODE
bit, which is cleared on reset and does not seem to be set when booting from flash bank 2. Not having the flash banks addresses swapped automatically is problematic because it means the firmware cannot be linked assuming a flash address of 0x08000000.
The workaround I can think of is to integrate a bootloader that checks which bank is in use, set the FB_MODE
bit accordingly, then jump to the actual firmware entry point. This bootloader would be flashed in both banks, and not updated during an OTA update.
Is there really no way to swap flash banks addresses automatically when booting from flash bank 2? Or is there another solution which wouldn't involve a bootloader?
Edit: after reading this thread on the ST forums, I am not sure anymore my understanding is correct. If this user is right, then setting BFB2
swaps the banks and their addresses, and setting FB_MODE
on top of that would "cancel" the swap.
I finally got this to work after a lot of trial and error. Some of my assumptions were wrong. Here's what the update process looks like:
FB_MODE
bit to know which bank the firmware is currently running from.MER2
bit if FB_MODE
is 0, MER1
otherwise).FB_MODE
.BFB2
bit in the option bytes if FB_MODE
is 0, or clear it otherwise. Do not blindly toggle BFB2
, because it does not necessarily reflect which bank is active.LAUNCH
bit, which also resets the MCU.Some notes: