Skip to main content
Graduate II
September 2, 2025
Solved

Place constant at end of used flash - not specific address

  • September 2, 2025
  • 23 replies
  • 1047 views

Heyho,

how can I put a constant at the end of the STM32's used flash? (using: STM32CubeIDE)

Not at a specific address (that's not a problem), but I'd like to have a constant always at the end of the used internal flash, independent of any other source code changes.

I just find that there's some ASCII characters = "ASCII" (twice) and lots of 0x00 at the end of my H7 and F7 bin files - that from my sources or placed by CubeIDE?

 

Thanks!

    This topic has been closed for replies.
    Best answer by mfgkw

    In the linker script (*.ld) you can define a new section (e.g. "EOF") and place it behind FLASH place it as last entry in FLASH.

    When you declare your const variable with __attribute__((section("EOF"))) you should be done.

    23 replies

    LCEAuthor
    Graduate II
    September 2, 2025

    Paranoia! :D

    LCEAuthor
    Graduate II
    September 2, 2025

    Shoot, now the STM32CubeProg complains about the *.elf file :

    Warning: File corrupted. Two or more segments defines the same memory zone

    And it doesn't load the complete flash content into the programmer.

    :(

    And this is very bad for first time flashing in production.

    Graduate II
    September 2, 2025

    Showing your ld file could help helping ...

     

    I tried a small project with this change in the ld file:

    ...

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

    ENDOFFLASH :
    {
    . = ALIGN(8);
    } >FLASH

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

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

     

    In the c file I added a variable like this:

    const int __attribute__((section("ENDOFFLASH"))) lastVariable = 123;
    Visitor II
    September 2, 2025

    ENDOFFLASH :
    {

    . = ALIGN(8);

    *(ENDOFFLASH)

    } >FLASH

     

    Input section and output, don't mix this. Also used attribute for variable or keep for section should me used

    LCEAuthor
    Graduate II
    September 3, 2025

    Now I moved the EOF section within the linker file right after the data init section where ">FLASH" is last used.

    Then STM32CubeProg does not complain about the *.elf file, but the data window only shows the first flash section...

    No problems with the bin file.

    Here's part of my linker file - lots of sections... but it works! Except for the new EOF part with elf.

    ...
    
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* Specify the memory areas */
    MEMORY
    {
    	ITCMRAM	(xrw)		: ORIGIN = 0x00000000, LENGTH = 64K		/* instruction RAM */
    
    	FLBTVEC		(rx)	: ORIGIN = 0x08000000, LENGTH = 1K		/* bootloader vector table */
    	FLBTFWINFO	(rx)	: ORIGIN = 0x08000400, LENGTH = 1K		/* bootloader firmware info */
    	FLBOOT 		(rx)	: ORIGIN = 0x08000800, LENGTH = 250K	/* bootloader */
    
    	FLUSER 	 	(rx)	: ORIGIN = 0x0803F000, LENGTH = 4K		/* TBD / shared One-Time-Programmable ROM */
    
    	FLASHVEC 	(rx)	: ORIGIN = 0x08040000, LENGTH = 1K		/* application vector table */
    	FLFWINFO 	(rx)	: ORIGIN = 0x08040400, LENGTH = 1K		/* application firmware info */
    	FLASH 	 	(rx)	: ORIGIN = 0x08040800, LENGTH = 766K	/* application */
    
    /* DTCM: 128 kB
     *	0x2000 0000 - 0x2001FFFF
     *	used as "general" RAM
     *	no DMA1/2 access, only MDMA memory to memory
     */
    /*	DTCM_HPST(xrw)		: ORIGIN = 0x20000000, LENGTH = 15K		*/	/* DTCM heap & stack */
    /*	DTCM_NOINIT(xrw)	: ORIGIN = 0x20003C00, LENGTH = 1K		*/	/* DTCM no init */
    /*	DTCM_RAM(xrw)		: ORIGIN = 0x20004000, LENGTH = 112K	*/	/* DTCM */
    	DTCM_RAM(xrw)		: ORIGIN = 0x20000000, LENGTH = 112K		/* DTCM */
    	DTCM_NOINIT(xrw)	: ORIGIN = 0x2001C000, LENGTH = 1K			/* DTCM no init */
    	DTCM_HPST(xrw)		: ORIGIN = 0x2001C400, LENGTH = 15K			/* DTCM heap & stack */
    
    /*
    without OCTOSPI / HyperRAM, all A2IP buffers in internal SRAM - NUCLEO debug only:
    	SRAXI_D1(xrw)		: ORIGIN = 0x24000000, LENGTH = 96K
    	SRAXI_D1_LWIP(xrw)	: ORIGIN = 0x24018000, LENGTH = 128K
    	SRAXI_D1_A2IP(xrw)	: ORIGIN = 0x24038000, LENGTH = 96K
    */
    /*
    with OCTOSPI / HyperRAM, all A2IP buffers in external HyperRAM:
    */
    
    /* internal */
    	SRAXI_D1(xrw)		: ORIGIN = 0x24000000, LENGTH = 320K
    
    	SRAM1_D2(xrw)		: ORIGIN = 0x30000000, LENGTH = 16K
    	SRAM2_D2(xrw)		: ORIGIN = 0x30004000, LENGTH = 16K
    
    	SRAM4_D3(xrw)		: ORIGIN = 0x38000000, LENGTH = 16K			/* only D3 access */
    
    /* external via OCTOSPI / HyperRAM */
    	OSPI_A2IP_D1(xrw)	: ORIGIN = 0x90000000, LENGTH = 0x0E00000	/* OCTOSPI 1 for A2IP */
    	OSPI_FILE_D1(xrw)	: ORIGIN = 0x90E00000, LENGTH = 0x0200000	/* OCTOSPI 1 for file upload buffer */
    
    /* external quad SPI flash via OCTOSPI */
    	OSPI_FLASH(xrw)		: ORIGIN = 0x70000000, LENGTH = 0x0800000	/* OCTOSPI 2 for QSPI flash */
    }
    
    
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* Define output sections */
    SECTIONS
    {
    	/* The startup code goes first into FLASHVEC */
    	.isr_vector :
    	{
    		. = ALIGN(4);
    		KEEP(*(.isr_vector))	/* Startup code */
    		. = ALIGN(4);
    	} >FLASHVEC
    
    	/* 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 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
    
    	.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
    	.ARM :
    	{
    		__exidx_start = .;
    		*(.ARM.exidx*)
    		__exidx_end = .;
    	} >FLASH
    
    	.preinit_array :
    	{
    		PROVIDE_HIDDEN (__preinit_array_start = .);
    		KEEP (*(.preinit_array*))
    		PROVIDE_HIDDEN (__preinit_array_end = .);
    	} >FLASH
    
    	.init_array :
    	{
    		PROVIDE_HIDDEN (__init_array_start = .);
    		KEEP (*(SORT(.init_array.*)))
    		KEEP (*(.init_array*))
    		PROVIDE_HIDDEN (__init_array_end = .);
    	} >FLASH
    
    	.fini_array :
    	{
    		PROVIDE_HIDDEN (__fini_array_start = .);
    		KEEP (*(SORT(.fini_array.*)))
    		KEEP (*(.fini_array*))
    		PROVIDE_HIDDEN (__fini_array_end = .);
    	} >FLASH
    
    
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* FLASH sections for BOOTLOADER
     *	firmware version info
     */
    
    	.FlashBootFwSection :
    	{
    		KEEP(*(.FlashBootFwSection)) ;
    	} >FLBTFWINFO
    
    
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* FLASH sections for APPLICATION
     *	user eeprom
     *	firmware version info
     */
    
    	.FlashAppUserSection :
    	{
    		KEEP(*(.FlashAppUserSection)) ;
    	} >FLUSER
    
    	.FlashAppFwSection :
    	{
    		KEEP(*(.FlashAppFwSection)) ;
    	} >FLFWINFO
    
    
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* internal SRAM */
    
    	/* 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 */
    		*(.RamFunc) /* .RamFunc sections */
    		*(.RamFunc*) /* .RamFunc* sections */
    
    		. = ALIGN(4);
    		_edata = .; /* define a global symbol at data end */
    	} >SRAXI_D1 AT >FLASH
    /* SRAXI_D1 or DTCM_RAM */
    
    /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* EOF string file info */
    	.FlashAppEOF :
    	{
    		. = ALIGN(8);
    		*(.FlashAppEOF)
    		*(.FlashAppEOF*)
    		. = ALIGN(8);
    	} >FLASH
    /* -------------------------------------------------------- */
    
    	/* Uninitialized data section */
    
    ...
    Visitor II
    September 3, 2025

    Maybe it is removed by linker as not used?

     

     One linker for APP and bootloader? Very bad idea !!!!!!!!!!!!

     

     

    LCEAuthor
    Graduate II
    September 3, 2025

    One linker for APP and bootloader? 

    No.

    But boot/app need to know about the other's flash sections.

    Works like a charm.

    Visitor II
    September 3, 2025

    @LCE wrote:

    One linker for APP and bootloader? 

    No.

    But boot/app need to know about the other's flash sections.

    Works like a charm.

     

    No need at all. thats not true.  

    In there

    /* application firmware info */

    will be good place to store  application flash end info.  

     

    Seemd you are to much complicate this.

    LCEAuthor
    Graduate II
    September 3, 2025

    There is a reason to place it at the end of flash: to make sure that the bootloading process finished completely.

    We have to cope with problems like a *** user who suddenly pulls out the connector, or presses the reset button, or there's a power off, ...

    Visitor II
    September 3, 2025

    OK, veryfication that aplication is complite, OK.  But still i suggest to store this addres in  firmware info section to find it quicker,

     

    Check my suggestion about removing your section by linker. 

    Use KEEP for this section.

    LCEAuthor
    Graduate II
    September 3, 2025

    > But still i suggest to store this addres in  firmware info section to find it quicker,

    No, that does not make sense, because I want to keep that part at the start of flash / file, and EOF info should be .... well, at the end.

    Visitor II
    September 3, 2025

    You misanderstood,

    And the and you  puts for ex "DEADBEEF"  mark to detect  that all APP was programmed.

    in firmware info section you addotionnaly stores adres  whare this mark will is located. 

    Simple easy,

    But back to problem?  Did you set KEEP for this ENDOFFLASH section?

    LCEAuthor
    Graduate II
    September 3, 2025

    Okay, and yes I put KEEP back in, lost that when playing with it.

    But how doe you make sure that "DEADBEEF"  or whatever mark is stored at the and of used flash ?