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.
-
Did you try defining ROM_region to not overlap with LANGUAGE_region?desowin– desowin2016年05月11日 17:53:52 +00:00Commented May 11, 2016 at 17:53
-
I was able to understand it, check the solution :).Hamboy75– Hamboy752016年05月12日 09:21:42 +00:00Commented May 12, 2016 at 9:21
3 Answers 3
This does not sound like a bug to me but rather an issue that you'll need to deal with. The .bin file is a raw memory file where each byte of the file maps to a byte in memory. How do you expect the .bin file to represent a byte located at offset 0x4000 or 0xC0000 without also representing all the bytes that come before that? The .bin file must include all the unused bytes between two memory sections in order to maintain the relative offset of the subsequent section.
Is your concern that the unused bytes are 0x00, and therefore they cannot be programmed without first being erased? If so then you can probably configure the linker (or whatever program you're using to create the .bin file) to use 0xFF instead of 0x00 for all unused bytes. Check the linker (or command line) options.
Or is your concern that the .bin file contains a lot of unused memory which will take longer to download and reprogram? Or is the .bin file now too large to fit in the memory region you've reserved for firmware updates? In either case, the solution is to divide the firmware update into two separate portions. For example, the first portion contains just the code starting at 0x08000000 and ending wherever the code ends. The second portion contains the data starting at 0x08004000. The size of the two portioned .bin files will be much less than the combined .bin file because they don't need to include all the unused memory in between. Your firmware update routines will need to be smart enough to recognize each portion and program them to the proper memory address.
If you don't want to deal with separate .bin files then you could consider downloading a .hex file as opposed to a .bin file. A .hex file is not a one-to-one mapping of memory bytes and contains coded information that allows unused memory regions to be skipped. However, your embedded firmware update routines will have to be smart enough to decode the hex file before programming the flash.
8 Comments
I am trying to place some constants into a know FLASH address, but using those methods dealt above I don't get the result. I tried with pragma location and I get no result a all, and also with the @ but IAR complain about this. The variable I want to store is the version of the FW so it has a 12 bytes value and I declare it like this as a global value (outside the functions I want to mean, so it is accessible from all the functions of the .c):
#pragma location=0x00001FF0
__no_init const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};
I have also checked IAR documentation such as: Technical Note 27498
I am using IAR 6.5 if it helps (because I noticed some methods require 6.70 newer!
EDITED:
Well, now it works doing the following:
In the .icf file:
/* Now I have a read only section in the ROM address 0x00001FF4 */
"ROM":
place at address mem:0x00001FF4 { readonly section .version };
In the .c source file:
#pragma location=".version"
__root const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};
Best regards,
Iván
1 Comment
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