This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Linker zero_init Command

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.

Parents
  • 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.

Reply
  • 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.

Children
No data