3

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
Michel Keijzers
  • 13,867
  • 18
  • 69
  • 139
  • 1
    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. – brhans May 09 '20 at 00:20
  • @brhans that sounds useful, however I cannot find them (I'm using STM32CubeIDE – Michel Keijzers May 09 '20 at 01:11
  • Tell your compiler to produce a .map file when it compiles. You should be able to use that to find some symbols you can use. Typically they would be given the names of your various memory sections, so you have a sections called '.text' where all your code is - search the map file for symbols containing .text or _text_ or something similar with an 'end' in it. I'm sure you'll find something similar. – brhans May 09 '20 at 01:44
  • 1
    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 – brhans May 09 '20 at 03:04
  • @brhans I don't know why I would need the address of `__fini_array_end`. However, I indeed get a value for `__fini_array_end`, however, it's value (24472) is somehow a few KB less than my text size (26865). Also `__ini_array_start` (269) does not make it better. But it's a good step in the right direction, thanks. I hope you have an idea how to clarify the few KB difference. – Michel Keijzers May 09 '20 at 13:56
  • 1
    It would depend on how your sections are arranged in flash. The default project which STM32CubeIDE created for me put that 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 0x0800xxxx range (Flash) to 0x2000xxxx (RAM). You might find some others like `__init_array_end`, `__preinit_array_end`, etc. – brhans May 09 '20 at 14:37
  • @brhans I just checked, after fini_array comes also data and bss, and user_heap_stack... since the last might change (although I don't use dynamic memory in my current project), ti will be very hard to find programmatically the address... guess I will use the manual way instead. – Michel Keijzers May 09 '20 at 14:44
  • 1
    .data, .bss, etc should be in RAM in the 0x2000xxx range. You're looking for the last symbol in Flash in the 0x0800xxxx range. – brhans May 09 '20 at 14:50
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/107791/discussion-between-michel-keijzers-and-brhans). – Michel Keijzers May 09 '20 at 14:51

2 Answers2

4

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.

brhans
  • 14,373
  • 3
  • 34
  • 49
2

Note this only answers the max page 31 issue. My main issue (finding the last address or last page is not solved.

By coincidence searching in hal_stm32f1xx_hal_flash_ex.h, I found the following code (removed irrelevant parts):

/* Low Density */
#if (defined(STM32F101x6) || defined(STM32F102x6) || defined(STM32F103x6))
...

/* Medium Density */
#if (defined(STM32F100xB) || defined(STM32F101xB) || defined(STM32F102xB) || defined(STM32F103xB))
...

/* High Density */
#if (defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F103xE))
...

/* XL Density */
#if defined(FLASH_BANK2_END)

/* Connectivity Line */
#if (defined(STM32F105xC) || defined(STM32F107xC))
...

The model I use (STM32F103C8T6) is NOT within this list, and when I search in the preprocessor definitions, I see STM32F10CxB is defined. Which is strange because this model has 128 KB and mine has 64 KB. I selected mine as Low Density which seems not to be the case, and this was defined as 31 pages (i.e. 32 KB).

So except for the slightly misleading HAL generation, I can use 64 KB (I verified this).

Michel Keijzers
  • 13,867
  • 18
  • 69
  • 139