Initializing a variable and specifying the storage address at the same time: is this possible?

In the codevision compiler for Atmel processors, it is possible to specify the storage address of a global variable, for example

int a @0x100; // will place the variable at the address 0x100 in RAM 

Of course, according to the C standard, variables can be initialized after declaration.

 int a=42; 

However, I did not find a way to make them both. int a @0x100 = 42 or int a = 42 @0x100; do not work, they cause compiler errors.

You may ask why it is so important to do this, because it was just possible

 int a @0x100; int main() { a = 42; //... } 

However, if I have variables in the EEPROM , I need to initialize them, because this is the only way to automatically generate the eeprom file with the values ​​in it. I can’t assign these values ​​later, because in this case they will actually write values ​​to eeprom every time the program starts.

+6
source share
4 answers

Just browse through CodeVisionAVR help,

"The following procedure should be used if a global variable placed at a specific address using @ operator must be initialized at the time of declaration:

 /* the variable will be stored in EEPROM at address 0x10 */ eeprom int abc @0x10; /* and it will be initialized with the value 123 */ eeprom int abc=123; 
+2
source

Although I do not know how to directly assign an EEPROM variable to a specific address and initialize it, I found this link very useful: EEPROM data at a fixed address .

I used a solution declaring a structure in EEPROM, and all the EEPROM variables in your program would be members of that structure. The order defining the members of the structure will be the order they place in the EEPROM address space by the linker. Since the structure will be the only global EEPROM declaration, it is safe to say that it will be addressed to 0x0000. Therefore, you will know the address of each EEPROM variable.

Example:

  typedef eeprom struct EEvars { eeprom char foo1; // will be located at EEPROM address 0x0000 eeprom char foo2; // will be located at EEPROM address 0x0001 eeprom short foo3; // will be located at EEPROM address 0x0002 eeprom long foo4; // will be located at EEPROM address 0x0004 eeprom char[3] fooArr; // fooArr[0] @ 0x0008; fooArr[1] @ 0x0009; // fooArr[2] @ 0x000A } EEVARS; 

Then you can initialize the variables in the structure declaration. At compilation, this will create a .eep file with initialized values ​​at known EEPROM addresses.

 eeprom EEVARS eepromInit = {0xAA, 0xBB, 0xCCDD, 0xEEEEFFFF, {0xF0, 0xF1, 0xF2}}; 

This works especially well in scenarios where the AVR bootloader section is used to update FLASH, and the new program needs to access stored EEPROM variables. It even allows you to add EEPROM variables through software updates, while you add them to the end of the structure so as not to violate the addresses of already set variables.

+2
source

I know what you're talking about, and I had the same problem. The problem is that using the @ character with an inline address with the variable itself is adding bolts to most toolboxes. Although it supports many built-in toolchains, so you can explicitly indicate where SFR or other registers are located, this is not normal behavior for standard C.

While I am not familiar with the specific compiler you are using, I know that most compilers provide a more sophisticated way to specify a memory card. For example, Atmel's ATmega series provides the ability to specify a user memory section in project settings. For example, in the GNU toolchain, these sections are used as part of variable declarations using the variable section attribute:

  __attribute__((__section__("<section_name>"))) 

For the ATmega series, you can find any memory in the EEPROM by including it in the same line as the variable declaration (before or after, until it is reached before the "=" in the task):

 __attribute__((__section__(".eeprom"))) 

If you want to ensure that a specific memory address in EEPROM is set as a value as part of your binary image, so it only starts once when the image is first written, you can declare a user memory section in your project settings (in the "Memory Settings" section of the parameters "Toolchain" if you are working at Atmel Studio).

For example, I did exactly what you described using the data block by declaring the ".tune_data" section in the EEPROM section of the memory parameters (according to the provided documentation on offsets, etc.), then declaring a variable like the following:

 const __attribute__((__section__(".tune_data))) Tune_Data_s as_tune_data = { <all_my_data> }; 

Clearly, this will be slightly different since you are not using the GNU compiler and maybe not using Atmel Studio. However, if you look at this, almost every toolchain for embedded programming provides some way to declare a section of user memory, which can then be bound to a variable in the code via pragma (or an attribute for GNU chains). The specification should be available using a command line argument and / or modifying a standard linker with command line parameters to specify a non-default linkrans. I know that the second method is the standard and only way to do this on the IAR toolchain.

+2
source

You can use a pointer pointing to an absolute address:

 volatile int *pa = (int *) 0x100; 

Then you can use the dereference * operator to access the value at that address, for example:

 int value = *pa; 

or

 *pa = 0x10; 

Edit: It is not possible to declare a variable to indicate a specific area and at the same time assign a value to that area. If the compiler does not have extensions that allow this.

0
source

Source: https://habr.com/ru/post/921910/


All Articles