2024-02-14 03:09 PM - edited 2024-02-14 03:13 PM
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
Solved! Go to Solution.
2024-02-14 03:40 PM
FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 256K-48K
Perhaps don't describe or put anything in the hole? Refer to it via a pointer.
2024-02-14 03:40 PM
FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 256K-48K
Perhaps don't describe or put anything in the hole? Refer to it via a pointer.
2024-02-14 04:50 PM
> 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.
2024-02-14 09:44 PM
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:
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:
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).
2024-02-15 02:16 PM
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