Electronic – Last address of program in STM32 HAL

flashhalmemorystm32stm32cubeide

Is there a way to find the last address or last page of the program which is stored in an STM32(F1) using a HAL (or LL?) function?

Background: I'm using EEPROM emulation in Flash and this works great. I changed the library from a hardcoded page to be used for EEPROM emulation to a variable one, to be able to implement wear leveling.

However, to know which pages can be used, I need to know where the program 'stops', i.e. the last address or page used by the program being executed, not to overwrite the program itself.

Also I'm a bit confused about the pages used and the size of each page. I'm using this library:

https://github.com/nimaltd/EEPROM/blob/master/eeprom.c (credits to Nima Askari).

Which defines for STM32F103C8T6 (low density F1) 1 KB page sizes and a max page of 31.
Why 31? I would expect 63 as it has 64 KB. Although I noticed when using page 15, it overwrote my program which is around 30 KB in size. (this part is solved, see my answer below).

Of course I can use the size of the program (see below), but this varies while I program, and besides it's too tedious to change/calculate the page number every time, I might forget it too.

arm-none-eabi-size   FuzzTester3.elf 
   text    data     bss     dec     hex filename
  26632     236    3104   29972    7514 FuzzTester3.elf

Best Answer

Your compiler might define a name for the last address used by code and/or const data sections. I know in the one I use, it has definitions for the end of code, something like __text_end__ and const data __rodata_end__. I can extern these in my C code - something like extern uint32_t __rodata_end__; and then use these 'variables' in my code. Once the compiler & linker finish doing their jobs, these values are then automatically substituted into my code where needed.

I've tried out a simple project in STM32CubeIDE, and with all the default settings it looks like it provides a symbol called __fini_array_end at the last used location in Flash. So you'd probably declare it as extern uint32_t __fini_array_end; in your code and then use &__fini_array_end to work out the start of the next page to use as simulated EEPROM.

Depending on how your project's linker is configures, you might find a different arrangement of sections in flash. The default project which STM32CubeIDE created for me put __fini_array_end at the end. So you'll have to look at your map file to see what symbol is at the end for your project and use that instead. Somewhere down near the end of your .map file you'll see the addresses of the symbols change from the 0x080xxxxx range (Flash) to 0x2000xxxx (RAM). You might find some others like __init_array_end, __preinit_array_end, etc.

If you're looking through the .map file and see the .data, .bss and other sections in the 0x2000xxxx range then you've gone too far and need to scroll back up a little to get back to the end of the 0x080xxxxx range.