Skip to main content
Graduate
November 17, 2024
Question

how to use flash memory "the bare metal way".

  • November 17, 2024
  • 11 replies
  • 6064 views

Hello, everybody! I'm relatively new to STM32 microcontrollers and have a moderate knowledge of C programming and a fair understanding of electronics.

Over the past few months, I've been learning to properly set up STM32F4 series MCUs, specifically the F401RET6U (Nucleo board) and the F411CEU6 (Black Pill board), using bare-metal approach. I've spent considerable time watching tutorial videos and reading online guides to help me get started.

I'm now at a point where I can set up the clock and read from and write to GPIOs.

From what I understand, setting up peripherals involves configuring the correct values in the appropriate registers in the right order.

I would like to learn how to use embedded flash memory to store information that needs to be retained after a power loss. So far, I've struggled to find a guide or tutorial that I can fully understand. Could someone please assist me with this or point me in the right direction?

Thank you very much, and have a blessed week, everyone!

    This topic has been closed for replies.

    11 replies

    HellasTAuthor
    Graduate
    January 21, 2025

    Okay, i think ive got it right this time...

    I modified the STM32F411CEUX_FLASH.ld contents as follows:

    MEMORY
    {
     RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
     FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 48K
     MY_FLASH_SECTION	(rw) : ORIGIN = 0x0800C000, LENGTH = 16K /* My custom section at Sector 3*/
     FLASH_REM			(rw) : ORIGIN = 0x08010000, LENGTH = 448K 
    }

     FLASH_REM stands for flash remaining. and wrote the correct lengths. After that i modified the sections and included my section:

    /* Sections */
    SECTIONS
    {
     /* The startup code into "FLASH" Rom type memory */
     .isr_vector :
     {
     . = ALIGN(4);
     KEEP(*(.isr_vector)) /* Startup code */
     . = ALIGN(4);
     } >FLASH
    
     /* The program code and other data into "FLASH" Rom type memory */
     .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_REM
    
     /* Constant data into "FLASH" Rom type memory */
     .rodata :
     {
     . = ALIGN(4);
     *(.rodata) /* .rodata sections (constants, strings, etc.) */
     *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
     . = ALIGN(4);
     } >FLASH_REM
    
     .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     *(.ARM.extab* .gnu.linkonce.armextab.*)
     . = ALIGN(4);
     } >FLASH_REM
    
     .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     __exidx_start = .;
     *(.ARM.exidx*)
     __exidx_end = .;
     . = ALIGN(4);
     } >FLASH_REM
    
     .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__preinit_array_start = .);
     KEEP (*(.preinit_array*))
     PROVIDE_HIDDEN (__preinit_array_end = .);
     . = ALIGN(4);
     } >FLASH_REM
    
     .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__init_array_start = .);
     KEEP (*(SORT(.init_array.*)))
     KEEP (*(.init_array*))
     PROVIDE_HIDDEN (__init_array_end = .);
     . = ALIGN(4);
     } >FLASH_REM
    
     .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
     {
     . = ALIGN(4);
     PROVIDE_HIDDEN (__fini_array_start = .);
     KEEP (*(SORT(.fini_array.*)))
     KEEP (*(.fini_array*))
     PROVIDE_HIDDEN (__fini_array_end = .);
     . = ALIGN(4);
     } >FLASH_REM
     
     .MyFlashSection :
     {
     	. = ALIGN(4);
     	KEEP(*(.MyFlashSection))
     } > MY_FLASH_SECTION
    
     /* Used by the startup to initialize data */
     _sidata = LOADADDR(.data);
    
     /* Initialized data sections into "RAM" Ram type memory */
     .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 */
    
     } >RAM AT> FLASH
    
     /* Uninitialized data section into "RAM" Ram type memory */
     . = ALIGN(4);
     .bss :
     {
     /* This is used by the startup in order to initialize the .bss section */
     _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" Ram type memory left */
     ._user_heap_stack :
     {
     . = ALIGN(8);
     PROVIDE ( end = . );
     PROVIDE ( _end = . );
     . = . + _Min_Heap_Size;
     . = . + _Min_Stack_Size;
     . = ALIGN(8);
     } >RAM
    
     /* Remove information from the compiler libraries */
     /DISCARD/ :
     {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }
    
     .ARM.attributes 0 : { *(.ARM.attributes) }
    }

     

    Essentially i  left .isr_vector untouched and moved the rest to >FLASH_REM. I touched nothing i figured that has to do with ram.

    in my main.c file i wrote this :

    /* USER CODE BEGIN PV */
    
    uint32_t MyFlashData[4096] __attribute__((section("MyFlashSection"))) = { [0 ... (4095)] = 0xFFFFFFFF }; // 16KB, Word length is 4 bytes (32 bits).

    According to the .map file, my understanding is that i got it right. here is the part in question :

    .MyFlashSection
     0x0800c000 0x0
     0x0800c000 . = ALIGN (0x4)
     *(.MyFlashSection)

     Your comments are appreciated. Thank you !

    Super User
    January 21, 2025

    @HellasT wrote:

    FLASH_REM stands for flash remaining. and wrote the correct lengths. !


    I don't think you should need to manually set the origin of FLASH_REM like that - it should immediately follow the preceding MY_FLASH_SECTION ?

     

    BTW:

    To do "pre-formatted" text without C language syntax highlighting, see:

    https://community.st.com/t5/community-guidelines/how-to-write-your-question-to-maximize-your-chances-to-find-a/tac-p/725146/highlight/true#M54

    HellasTAuthor
    Graduate
    January 21, 2025

    @Andrew Neil wrote:


    I don't think you should need to manually set the origin of FLASH_REM like that - it should immediately follow the preceding MY_FLASH_SECTION ?

    I do not know if it will work without setting the origin. I guess i could try it and see. In any case i dont think it is bad to explicitly set it.


    BTW:

    To do "pre-formatted" text without C language syntax highlighting, see:

    https://community.st.com/t5/community-guidelines/how-to-write-your-question-to-maximize-your-chances-to-find-a/tac-p/725146/highlight/true#M54


    Im not sure what you mean but i will read the link .

    Thankyou.