cgcclinkerembeddedbootloader

Bootloader Strategies for Dynamic Firmware Updates in Dual-Sector STM32


I am developing a firmware update system for an STM32 microcontroller with a memory layout that includes a bootloader and two application sectors (APP1 and APP2). Each sector holds the same application but with potentially different versions. During an OTA update, the new firmware version is written to APP2 if the current execution is from APP1, and vice versa. The bootloader, after a reset, reads metadata (located just above APP1 and APP2) to determine which application version is newer and then jumps to it.

The challenge is that my STM32 application project only compiles a single firmware image, and I can't predict which sector it will be loaded into during OTA updates. The linker script is hardcoded to either APP1 or APP2, which means the application is tied to one specific memory region, is not it? How can I effectively manage this so the firmware can dynamically adjust based on its location?

My Thoughts: I am considering compiling the application twice with different linker scripts and before OTA, STM32 will require the correct version for it. Is there a way for the bootloader to configure the application dynamically, or a better approach to maintain a single firmware image that can adapt to being executed from either sector?

My Memory MAP:

/* Specify the memory areas */
MEMORY
{
   /* Bootloader region */
    FLASH_BOOTLOADER(rx) : ORIGIN = 0x08000000, LENGTH = 32K

    /* METADATA region for App1 */
    FLASH_METADATA_APP1 (r) : ORIGIN = 0x08008000, LENGTH = 1K 

    /* Application 1 region */
    FLASH_APP1 (rx) : ORIGIN = 0x08008400, LENGTH = 363K

    /* METADATA region for App2 */
    FLASH_METADATA_APP2 (rx) : ORIGIN = 0x08063000, LENGTH = 1K

    /* Application 2 region */
    FLASH_APP2 (rx) : ORIGIN = 0x08063400, LENGTH = 363K

    /* Eeprom section */
    FLASH_EEPROM (rx) : ORIGIN = 0x080BE000, LENGTH = 8K

    /* Reserved region */
    FLASH_RESERVED (r) : ORIGIN = 0x080BF000, LENGTH = 60K

    /* Wireless stack region */
    FLASH_BLE_STACK (x) : ORIGIN = 0x080CE000, LENGTH = 120K

    /* FUS region */
    FLASH_FUS (rx) : ORIGIN = 0x080EC000, LENGTH = 16K

    /* RAM region */
    RAM (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
   
      RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
}

and all areas in linker script are tied to sectors like that:

/* The startup code goes first into FLASH */
.isr_vector :
{
  . = ALIGN(4);
  KEEP(*(.isr_vector)) /* Startup code */
  . = ALIGN(4);
    
} >FLASH_APP1

Thank you ver much


Solution

  • Change the design so that the application runs from only one location. When receiving the OTA update, store it in a temporary location. Then verify the OTA update in the temporary location before copying the OTA update to the final location where it will run. The old application can't erase itself so do a soft reset after receiving the update and use the bootloader to erase the old application and copy the new application from the temporary location to the final location.