1

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.

asked May 11, 2016 at 13:22
2
  • Did you try defining ROM_region to not overlap with LANGUAGE_region? Commented May 11, 2016 at 17:53
  • I was able to understand it, check the solution :). Commented May 12, 2016 at 9:21

3 Answers 3

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.

answered May 11, 2016 at 14:53
Sign up to request clarification or add additional context in comments.

8 Comments

My bin file is 106kb actually , the device ram is 256kb. If i set any of those commands, it raises to 145kb at least so i dont have the space to upload the new firmware to the rest. Is doesnt make any sense to raise the size of the binary leaving unused bytes (more than 10kb). In my tests everything (all variables and functions) use memory after the last of the variables with fixed location. Thats stupid :).
My concern is that binary is not optimized, in microcontrollers all must be optimized to the max, because everything is needed, at least in my case i'm always close to the limit. In this case, the linker is leaving unused space memory only if i set variables to a certain position and using as starting address the last of them. Imagine that i need to define this variable at the end of the flash memory..... i would not have space the program..
An example, i need to set a fixed variable to 0x08038000. Linker would leave unused all posistions from 0x08000800 to 0x08037FFF. (You can check easily this). If you think that it is not a bug?
I'm doing some tests: const char Version[] @0x08020000={...}, this this, all the code and consts variables are set after position 0x08020000. Higher address is 0x0803EE77..
If i set that variable to 0x08030000 then it works fine, variable is set to that address, the rest of code is before (0x0800000 to 0x0801F6A0). It seems that or you have anough space before to put ALL before the address or it sets everything after.
|
1

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

answered Jul 20, 2016 at 7:12

1 Comment

I was looking for the same thing for LPC1758 to set the CRP1. I finally figured it out, but I give this answer a thumb up in case anyone encountered the same problem would notice this
0

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

answered May 12, 2016 at 7:53

1 Comment

If you want code and/or data to be located in specific regions/sections of memory then you should edit the linker command/script file to explicitly specify those regions/sections. Read the linker manual to learn how to do this.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.