cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401 reserving flash sector for config

mrx23
Associate III

On STM32F401CCU6

I'm trying to reserve these 2sectors for user config in gcc linker script:

 

 

Sector - Address ini ~ Address end - Size
Sector 0 - 0x0800 0000 ~ 0x0800 3FFF - 16 Kbytes
Sector 1 - 0x0800 4000 ~ 0x0800 7FFF - 16 Kbytes    RESERVE
Sector 2 - 0x0800 8000 ~ 0x0800 BFFF - 16 Kbytes   RESERVE
Sector 3 - 0x0800 C000 ~ 0x0800 FFFF - 16 Kbytes
Sector 4 - 0x0801 0000 ~ 0x0801 FFFF - 64 Kbytes
Sector 5 - 0x0802 0000 ~ 0x0803 FFFF - 128 Kbytes

 

 

But the code posted somewhere else on the forum is not working.

Looking at the generated .bin at address 4000h seems to hold data, it's not FF/00

 

 

 

static const uint8_t __attribute__((section (".myDataStorage"))) memoryReserve[32768];

 

 

 

 

 

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20010000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x0;      /* required amount of heap  */
_Min_Stack_Size = 0xF00; /* required amount of stack */

/* Specify the memory areas */
/* STM32F401CCU6: 4x16K,64K,128K==256K */
MEMORY
{
FLASH_ISR (rx)      : ORIGIN = 0x08000000, LENGTH = 16K
FLASH_HOLE (rx): ORIGIN = 0x08004000, LENGTH = 32K
FLASH (rx)      : ORIGIN = 0x080C0000, LENGTH = 256K-32K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 64K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH_ISR

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH_ISR

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH_ISR

  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH_ISR

  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH_ISR

  /* Reserve section 3 from flash memory. */
  .myDataStorage :
  {
    . = ALIGN(4);
    KEEP(*(.myDataStorage)) ;
    . = ALIGN(4);
  } > FLASH_HOLE

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data :
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

 

 

map file also agrees

 

 .text.HAL_RCC_OscConfig
                0x08004020      0x7bc obj\stm32f4xx_hal_rcc.o
                0x08004020                HAL_RCC_OscConfig
 .text.HAL_RCC_ClockConfig
                0x080047dc      0x560 obj\stm32f4xx_hal_rcc.o
                0x080047dc                HAL_RCC_ClockConfig

 

1 ACCEPTED SOLUTION

Accepted Solutions

FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 256K-48K

Perhaps don't describe or put anything in the hole? Refer to it via a pointer.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

4 REPLIES 4

FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 256K-48K

Perhaps don't describe or put anything in the hole? Refer to it via a pointer.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

> Looking at the generated .bin at address 4000h seems to hold data, it's not FF/00

A BIN file cannot contain holes. Use HEX or ELF instead.

> static const uint8_t __attribute__((section (".myDataStorage"))) memoryReserve[32768];

Probably shouldn't be marked CONST if it can change. Not sure the linker will like a const array which isn't initialized. It will likely want to store it in FLASH.

If you feel a post has answered your question, please click "Accept as Solution".

Even you reserve "sectors" in MCU flash memory - how do you know that the debugger would not do a "full chip erase" before it programs a BIN or ELF file again?

If debugger would erase "all" before it writes a new FW - any definition in linker script would NOT avoid that your data is erased (debugger has no clue about your linker script and does not care).

Because of this: I use I2C and external I2C flash, e.g. EEPROM, as M42M02. This works very well and reliable for me: just 2 wires (GPIOs) lost (for I2Cx or as GPIO, and very simple code to handle it). No issues with flashing my MCU code memory again (and not losing space; I2C as 2Mbit flash provides a lot of space for other stuff, e.g. man pages).

My user config sits NEVER in MCU flash memory (because of the issue that any debugger could erase), instead, here some options:

  • have an I2C flash memory for SYSCFG
  • use the BACKUP RAM as SYSCFG (but without battery connected - it gets lost - but it can survive a RESET)
  • use some RTC registers (sometimes called BACKUP registers) - which are not reset if you perform a RESET
    (they can survive a RESET when you need an updated SYSCFG after RESET, even a very short power cycle I have realized, can survive)
  • when using SD Card (eMMC) - store it there

A persistent SYSCFG should be stored somewhere else, not on MCU flash memory (which can be erased by debugger flashing MCU flash).

BTW: some MCU have options for OTP memory: you can burn some fuses for a non-volatile SYSCFG, but just once!

Other remark:
On saw on some MUC, I guess STM32H7, that you can set locks on internal MCU flash memory (via STM32CubeProgrammer). Maybe you can use this option:

  • remove the locks on flash pages and write/update your SYSCFG
  • set the locks again
  • assuming it will prevent to overwrite next time when you flash new FW to your board (but I am not sure, if guaranteed it will not be unlocked and erased by debugger)

A linker script definition, as to reserve space in MCU flash - I am sure - is not enough (to protect against overwrites with next FW flush).

This one worked, was typo.

FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 16K
FLASH_HOLE (rx) : ORIGIN = 0x08004000, LENGTH = 32K
FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 256K-48K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K