Hi,
Is there a way to explicitly place variable initializer values in a defined flash region using scatter files?
For example, using the scatter file below,
LOAD_ROM 0x0000 0x8000 ; Name of load region (LOAD_ROM), ; Start address for load region (0x0000), ; Maximum size of load region (0x8000) { EXEC_ROM 0x0000 0x8000 ; Name of first exec region (EXEC_ROM), ; Start address for exec region (0x0000), ; Maximum size of first exec region (0x8000) { * (+RO) ; Place all code and RO data into ; this exec region } SRAM 0x10000 0x6000 ; Name of second exec region (SRAM), ; Start address of second exec region (0x10000), ; Maximum size of second exec region (0x6000) { * (+RW, +ZI) ; Place all RW and ZI data into ; this exec region } }
If I declare
int aGlobalVar = 0xDEADBEEF;
aGlobalVar will get placed in SRAM, and the initializer value 0xDEADBEEF will get placed at the end of EXEC_ROM (this seems to be the case according to my experiment).
Is there a way for me to force explicit placement of 0xDEADBEEF in a flash region?
Thanks, LJ
The linker builds it into a static initialization table that unpacks the load region into volatile memories. The code doing the static copy is in __main and once complete jumps to your main() function.
To have a variable in ROM, that stays there, consider using "static const"
Want it at some specific address? Consider making a different load region where you shrink the current one slightly, and have the second one at the end, and then direct specific content into sections therein.
ie
LOAD_ROM 0x0000 0x7F00 { .. } CONST_ROM 0x7F00 0x0100 { .. }
We are not trying to store a const value in FLASH.
We are wondering where in FLASH are all the values used to initialize RAM variables are stored, and if it is possible to explicitly place those values in a known FLASH region.
The reason we are asking is we are seeing unexpected values getting placed in the last FLASH region we declared in the scatter file, and the values match those used to initialize some global variables.
Attaching our scatter file:
LR_IROM1 0x0001D000 0x00023000 { ; load region size_region ER_IROM1 0x0001D000 0x00004000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } ER_BEACON_POWERSTATE_DATA 0x00021000 FIXED 0x400 { ; Power state data used by the beacon powerstate.o (+RO +RW) } ER_BEACON_TRANSMITLEVEL_DATA 0x00021400 FIXED 0x400 { ; Transmit power level of the beacon transmitpower.o (+RO +RW) } ER_BEACON_CONFIGURATION_DATA 0x00021C00 FIXED 0x400 { ; Beacon configuration beaconconfiguration.o (+RO +RW) } RW_IRAM1 0x20002200 0x00001E00 { ; RW data .ANY (+RW +ZI) } }
We are seeing unexpected values getting placed in ER_BEACON_CONFIGURATION_DATA region that clearly do not belong to beaconconfiguration.o. These values do not have an entry in the .map file, and they match values we use to initialize some global variables.
The Load Region describes where to store things, the link packs things there, and the scatter loader (__main) unpack them.
Everything you describe in LR_IROM will be packed in there end-to-end, along with a linker generated table describing where things are, and where they go.
www.keil.com/.../armlink_pge1362065953229.htm
http://www.keil.com/support/docs/3629.htm
I don't feel like our questions are answered. We have the exact same issue as described in here: www.keil.com/.../
The questioner there is using the load region entirely wrong.
Look it's not my job to train you to do your job, or perform your job.
If you don't understand the concepts of the scatter file, and the role of the linker, and startup code, it's not really my problem. Trying to point you in the right direction to find a solution to your issue, but not paid enough to do it for you, and get you past the mind-block where you insist it must do things a certain way without understanding how the mechanics actually work and the degrees of freedom you have to change things, or alter the outcome.
Feel free to Please read the manual, and understand it, and work with your Keil account manager to resolve your support issues.
>>The reason we are asking is we are seeing unexpected values getting placed in the last FLASH region we declared in the scatter file, and the values match those used to initialize some global variables.
See the reason you have this problem is that you believe these things are there "unexpectedly", when actually the linker's doing its job, and the values for your global variables, which are non-zero, have to manifest from somewhere.
Linker packs initialization data beyond your code, loader unpacks into volatile memory, because that like disappears when the power is removed, and needs to come from some place that remembers it a tad more permanently.
Please read the manual in progress. But yeah we understand initial values have to live in FLASH, we were just confused about if we can control where those values are placed.
Maybe our mistake was not realizing each execution block contains a ROM and RAM block (ie as far as linker is concerned, ER_BEACON_CONFIGURATION_DATA and RW_IRAM1 are the same execution block), and any initial values used to initialize RAM variables specified in the RAM block are placed in the corresponding ROM block?
To explicitly place a variable into FLASH (or other valid addresses) you can use a compiler-specific-feature; attribute keyword.
To place your aGlobalVar at the absolute address 0x00021C00, you can do this:
int aGlobalVar __attribute__((at(0x00021C00))) = 0xDEADBEEF;
The ARM linker will place the value 0xDEADBEEF at the address 0x00021C00. The value of aGlobalVar is 0xDEADBEEF. The address of aGlobalVar is 0x00021C00.
As directed by Westonsupermare Pier: Creating new ER region ER_BEACON_CONFIGURATION_DATA in the scatter file and
int aGlobalVar __attribute__((section("ER_BEACON_CONFIGURATION_DATA"))) = 0xDEADBEEF;
will place the 0xDEADBEEF in the address defined for ER_BEACON_CONFIGURATION_DATA in the scatter file. And, the compiler will generate scatter load codes to copy the data in ER_BEACON_CONFIGURATION_DATA to RAM to be called in __main().
One main difference between the two methods is where the aGlobalVar is located in memory. In the first method, every time you access aGlobalVar it will go to 0x00021C00 (FLASH?). In the second method, every time you access aGlobalVar it will go to RAM address assigned by the linker (you dont know it's address before the linker has done it work).
Obviously, the second method is faster if you run code from flash.
Note1: to compile under ARMCC6, GNU GCC, IAR or other compilers, you have to change the syntax for the __attribute__ keyword.
Note2:
ER_BEACON_CONFIGURATION_DATA 0x00021C00 FIXED 0x400 { ; Beacon configuration beaconconfiguration.o (+RO +RW) }
The linker will place code and data (RO and RW) generated by the compiled beaconconfiguration.c into this flash section.