2024-11-17 05:23 AM - last edited on 2024-11-18 04:12 AM by Andrew Neil
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!
2025-01-21 07:24 AM
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 !
2025-01-21 07:35 AM
@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:
2025-01-21 03:39 PM
@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:
Im not sure what you mean but i will read the link .
Thankyou.
2025-01-21 04:43 PM - edited 2025-01-21 04:44 PM
@HellasT wrote:i dont think it is bad to explicitly set it.
The risk with manually setting it is that you might make a typo ...
@HellasT wrote:Im not sure what you mean but i will read the link .
you have posted your linker script extracts using the </> source code tool. That means the text gets coloured as if it were C source code - but it isn't.
The link explains how to retain the layout (indentation, etc) but without the inappropriate colouring.
2025-01-23 07:43 AM
The risk with manually setting it is that you might make a typo ...
Yes, typo's are always an issue.
you have posted your linker script extracts using the </> source code tool. That means the text gets coloured as if it were C source code - but it isn't.
The link explains how to retain the layout (indentation, etc) but without the inappropriate colouring.
Ho, i see now. Sorry for that !!!