How to set a non-0 initialization variable under Keil MDK

Source: Internet
Author: User

Source: Keil MDK How to set a non-0 initialization variable

Some industrial products, when the system reset (non-power-on reset), may require to hold the data in the pre-reset RAM, used to quickly restore the scene, or not due to the instantaneous reset of the field equipment restart. and Keil MDK by default, any form of reset resets the uninitialized variable data in the Ram area to zero. How to set a non-initialized data variable is not initialized by 0, which is discussed in this article.

Before giving the method, let's take a look at the code and data storage rules, properties, and why the default non-initialized variables are initialized to zero after reset.

What are initialization data variables and what are non-initialized data variables? (Because my text description is not necessarily accurate, so I like to give some examples to help understand the text.) )

Define a variable: int ntimercount=20; the variable ntimercount is the initialization variable, that is, the initial value;

If the variable is defined: int ntimercount; the variable ntimercount is a non-assignable variable, Keil MDK by default puts it into the input section with the property Zi.

So what is "ZI" and what is the "input section"? It's a little boring to know about the composition of arm image files, but I think it's very necessary to master it.

The composition of the arm image file:

    • An image file consists of one or more domains (region, also translated as "zone")
    • Each field contains one or more output segments (section, also translated as "knots")
    • Each output segment contains one or more input segments
    • Each input segment contains the code and data in the destination file

The input segment contains four types of content: code, initialized data, uninitialized storage area, and storage area where content is initialized to zero. Each input segment has corresponding properties: Read-only (RO), read-write (RW), and initialized to 0 (ZI).

An output segment contains input segments with the same RO, rw, and Zi properties as the columns. The output segment properties are the same as the input segment properties that are contained in them.

A field contains one to three output segments, with different properties for each output segment: Ro property, rw property, and Zi property

Here we can know that, in general, the code will be placed in the Ro property Input section, the initialized variable will be assigned to the RW property input area, and the "ZI" attribute input section can be understood to be initialized to 0 variables of the collection.

What is the initial value of the initialized variable that will be placed on the hardware? (for example, define an int ntimercount=20; So where is the initial value 20?) I think this is an interesting question, such as Keil, after the compilation is complete, gives information about the size of the compiled file, as follows:

Total RO Size (code + RO data) 54520 (53.24kB) Total RW size (RW Data + ZI data) 6088 (5.95kB) Total ROM Size (code + RO Data + RW data) 54696 (53.41kB)

Many people do not know how this is calculated, and do not know exactly how much code is put into Rom/flash. In fact, those variables that have already been initialized are placed in the input section of the RW attribute, and the initial values of those variables are put into rom/flash. Sometimes these initial values are larger, and Keil will compress these initial values into Rom/flash to save storage space. So who are these initial values when they are restored to ram? Zi the variables in the input section are in RAM and who is initialized with 0? To understand these things, look at the default settings, from the system reset, to the execution of the C code you write the main function, Keil to help you do something.

After the hardware reset, the first step is to perform a reset handler, the entry of the program in the startup code (the default), an excerpt of a CORTEX-M3 reset processing entry code:

   1:reset_handler   PROC        ; Proc equals function, which represents the beginning of a functional, as opposed to ENDP ?  
   2:  
   3:                 EXPORT  reset_handler             [WEAK]  
   4:                 IMPORT  Systeminit  
   5:                 IMPORT  __main  
   6:                 LDR     R0, =systeminit  
   7:                 BLX     R0  
   8:                 LDR     R0, =__main  
   9:                 BX      R0  
  Ten:                 ENDP  

After initializing the stack pointer and executing the user-defined underlying initialization code (the Systeminit function), the next code calls the __main function, where the __main function calls the C library functions of some columns to complete the copying, decompression, and 0 initialization of the Zi data for the code and data. The decompression and copying of the data, including copying the initial values of the initialized variables stored in the Rom/flash to the appropriate RAM. For a variable, it may have three properties, the variable modified with the const modifier is most likely to be placed in the Ro property area, the initialized variable is placed in the RW attribute area, then the remaining variables are placed in the Zi attribute area. By default, 0 initialization of the Zi data initializes all the Zi data extents to zero, which is done by the compiler "on its own" before the program executes the C code's main function after each reset. So we have to set some variables in the C code after the reset is not initialized by 0, it must not be allowed by the compiler "arbitrary", we have to use some rules, constraints on the compiler.

Distributed loading files are critical to connectors, where you can use uninit to decorate an execution section in a distributed load file to avoid a 0 initialization of __main Zi data for that section. This is the key to resolving non-0 initialization variables. So we can define a uninit decorated data section, and then put the variables that you want to initialize to 0 in this area. So, there is the first method:

1. Modify the distributed load file, add an execution section named Myram, the start address of the execution section is 0x1000a000, the length is 0x2000 bytes (8KB), decorated by uninit:

   1:lr_irom1 0x00000000 0x00080000  {    ; load region size_region
   2:   er_irom1 0x00000000 0x00080000  {  ; Load address = execution Address
   3:    *. O (RESET, +first) 
   4:    * (inroot$$Sections)  
   5:    . Any (+ro)
   6:   }
   7:   rw_iram1 0x10000000 0x0000a000  {  ; RW data
   8:    . Any (+RW +zi)
   9:   }
  Ten:   uninit 0x00002000  {
  One:    . Any (no_init)
  :   }
  13:}

So, if you have an array in your program and you don't want it to reset after 0 initialization, you can define variables like this:

    
    Char  PLC_EU_BACKUP[PLC_EU_BACKUP_BUF/8] __attribute__ ((at (0x1000a000)));

The variable property modifier, __attribute__ (at (adder)), is used to force the variable to be located at the address of the adder. Since the 8KB area of the address 0x1000a000 starts with the Zi variable not being initialized by 0, the array plc_eu_backup in this area will not be initialized by 0.

The disadvantage of this approach is obvious: to allocate the address of the variable itself, if the non-0 initialization data is more, it will be unimaginable large project (later maintenance, add, modify code, etc.). So find a way for the compiler to automatically allocate variables for this area.

2. Distribute the load to the same method 1, if you still define an array, you can use the following method:

    Char  PLC_EU_BACKUP[PLC_EU_BACKUP_BUF/8] __attribute__ ((section ("No_init"), Zero_init));  

The variable property modifier __attribute__ ((section ("Name"), Zero_init) is used to force the variable to be defined in the Name Attribute Data section, zero_init means that the uninitialized variable is placed in the Zi data section. Because "No_init" is a explicitly named Custom section, it has the UnInit property.

3. How do I initialize a non-initialized variable within a module to 0?

If the module name is test.c, modify the distributed load file as follows:

   1:lr_irom1 0x00000000 0x00080000  {region    size_region
   2:   er_irom1 0x00000000 0x00080000  {  ; Load address = execution Address
   3:    *.o (RESET, +first)
   4:    * (inroot$ $Sections)
   5:    . Any (+ro)
   6:   }
   7:   rw_iram1 0x10000000 0x0000a000  {  ; RW data
   8:    . Any (+RW +zi)
   9:   }
  Ten:   rw_iram2 0x1000a000 uninit 0x00002000  {
  One:    test.o (+zi)
  :   }
  13:}

Use the following methods when defining:

       int Utimercount __attribute__ ((zero_init));

Here, the variable property modifier __attribute__ ((zero_init)) is used to place the uninitialized variable into the Zi data section of the variable, in fact Keil by default, the uninitialized variable is placed in the Zi data area.

4. Initialize the entire program's non-initialized variables to 0. It's not necessary to say that.

How to set a non-0 initialization variable (GO) under Keil MDK

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.