Hello,
While porting legacy code from an LPC2103 to a LPC1765 Cortex processor within the Keil environment I came accross the need to implement the linker zero_init attribute for a single byte variable as described by the following links:
(1) infocenter.arm.com/.../index.jsp (2) http://www.keil.com/support/docs/3480.htm
The purpose of this variable was to be read on a system reset to determine whether the reset event was intentional or not and execute additional code if the reset event was intentional (ie: go into the ISP bootloader). As debugging shows, system reset causes RW variables to be zeroed when performing the BX from statup .asm code into application main().
However, when I implemented the change within a 'C' file as follows:
UINT8 Startup_Flags __attribute__( ( section( "NoInit"), zero_init) );
and linker scatter file as follows:
RW_IRAM1 0x10000000 UNINIT 0x00000100 { ;no init section *(NoInit) }
I was getting inconsistent results with the variable every time the reset event occurred, even though it was placed in the declared UNINIT memory region according to the memory map:
Startup_Flags 0x10000000 Data 1 main.o(NoInit) SystemFrequency 0x10000100 Data 4 system_lpc17xx.o(.data)
As the region was declared to be a size of 256, I decided to add a dummy declaration along with the original to troubleshoot the issue further, as follows:
// Zero initialization section UINT8 Startup_Flags __attribute__( ( section( "NoInit"), zero_init) ); UINT8 NoInitUnused[255] __attribute__( ( section( "NoInit"), zero_init) );
This initially showed promise until it too failed periodically (the variable Startup_Flags was located at 0x10000000 according to the memory map).
Startup_Flags 0x10000000 Data 1 main.o(NoInit) NoInitUnused 0x100000ff Data 255 main.o(NoInit)
I then tried swapping the declarations in order to move the location of the variable to the LAST entry in the region (ie: 0x100000FF) as follows:
// Zero initialization section UINT8 NoInitUnused[255] __attribute__( ( section( "NoInit"), zero_init) ); UINT8 Startup_Flags __attribute__( ( section( "NoInit"), zero_init) );
NoInitUnused 0x10000000 Data 255 main.o(NoInit) Startup_Flags 0x100000ff Data 1 main.o(NoInit)
Now the results I am getting are consistently correct (so far) and I can invoke the ISP bootloader whenever the variable has the proper bit flag set.
The caveat seems to be that this zero_init command CAN be used and function properly, but under certain undocumented? conditions (ie: MUST have 8 declared bytes within the region and declaration order seems to be important). Has anyone else run into this issue? If so, how was it corrected? Or am I just misreading the documentation contained within the posted links? Thank you.
Is there any limit to the size of NoInit area? I tried an array of 20 bytes,
U8 Db[20] __attribute__( ( section( "NoInit"),zero_init) );
which I initialized such that Db[0] = 0, Db[1] = 1,...Db[19] = 19;
The scatter file looks like:
LR_IROM1 0x00000000 { ; load region ER_IROM1 0x00000000 0x00020000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } GLOBAL_DATA 0x40000000 UNINIT 0x00000014 { ;no init section *(NoInit) } RW_IRAM2 0x40000014 0x0000FFEC { ; RW data .ANY (+RW +ZI) } }
and the map file shows: Db 0x40000000 Data 20 os_init.o(NoInit) which to me seems like the entire array is in NoInit sector. However, when I execute the program, after the soft reset, only the first 16 bytes are preserved, the rest of them Db[16] thru Db[19] are initialized to zero. Is it some kind of default setting which limits the NoInit sector? If it is how can I increase its size?
I am using Keil uVision3 V3.51 linker and the target processor is ARM LPC_2106.