Search code examples
linkerembeddedstm32iarstm32f4

IAR EWARM 6.5 Storing a const variable in a certain address BUG?


I want to save an area of flash memory in stm32 to store my own config information.

To make this i want to save the second sector of the flash memory on STM32F2/STM32F4 (16kb stored at 0x08004000-0x08007FFF)

Checking internet and stackoverflow you have 4 ways to do this

1)

#pragma location=0x08004000 __no_init const char ReservedArea[16*1024];

2)

__no_init const char ReservedArea[16*1024] @0x08004000;

3) creating a section + #pragma location=

project icf:

place at address mem: 0x08004000 { readonly section ConfigSection };

c file:

#pragma location="ConfigSection" __no_init const char ReservedArea[16*1024];

4)

Defining a section in project .icf file IAR define memory region for custom data

Bug or problem found

Method 1 to 3 works ok. Linker include a space area for my variable. You can check the .bin file generated with a hex editor or just debug and see that variable is @ 0x08004000.

The problem found with these methods are that iar linker leave unused more than 12kbytes of flash memory between 0x08000800 - 0x08003FFF. The best way to verify this is to remove the var, compile, write in a note the size of the bin file and then add the variable. If you do this you will notice that new bin file size is greater than 16kb when it must be exact 16kb.

If you move the address from 0x08004000 to 0x0800C000 without any other change the file size will increase in another 32kbytes and all the previous area is set to 0x00 and unused in the bin file. This is a big problem for our project because i use the rest of the unused area out of the bin file to allow firmware update.

Checking the map file you will see that the area previous to the reserved zone is unused too.

I tried several ways to fix this with no luck, for example defining 2 variables with address, playing for hours, checking linker options, optimizations, playing with other #pragma options, etc.

About the 4th method, it stores the variable in the system but it dont get the address that i wanted. Probably the problem was that both areas shared the address space.

icf file

   define region LANGUAGE_region   = mem:[from 0x08004000 to 0x08007FFF];
   define region ROM_region      = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
   define region RAM_region      = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

   "LANGUAGE_PLACE":place at start of LANGUAGE_region  { section .LANGUAGE_PLACE.noinit };

c code

extern const char ReservedArea[16*1024] @".LANGUAGE_PLACE.noinit";

const char ReservedArea[16*1024];

Is it my problem? is it a bug? Any tip is welcomed.

Thanks in advance.


Solution

  • Ok finally i understood how it works. The linker searchs the longest unused space to include the code there.

    Personally I think that this is not the best way, i would prefer that the linker would use the first unused area if the function or the const variable has enough space to fit in.

    To limit this I just added the next code (Example for stm32F4)

    const char unusedarea[128*3*1024] @0x08020000 ;
    #pragma required=unusedarea
    

    This use the space between 0x08020000 and 0x0807FFFF and force the linker to use the other areas. And effectively it worked.

    This allow me to reserve space but leaving the needed space free and unused. I can even remove the last 384 kb from the bin file, and upload only the first 128kbytes.

    Edited. Setting those vars to __no_init bin file is still small and reserves áreas are not overwritted when using jtag