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

Viewed 8883

In the codevision compiler for Atmel processors, there is a possibility 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, as per standard C, variables can be initialized upon declaration

int a=42;

However, I did not find any possibility to do them both. int a @0x100 = 42 or int a = 42 @0x100; don't work, they cause compiler errors.

You might ask why it is so important to do it, because one could simply have

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 those values later, because in that case it would actually write the values into the eeprom at each start of the program.

4 Answers

I know what you're talking about and have had the same problem myself. The issue is that using the @ symbol with an address inline with the variable itself is a bolt-on addition to most toolchains. While it's supported for a lot of embedded toolchains so you can explicitly call out where SFRs or other registers are located, it's not a normal behavior for standard C.

While I'm not familiar with the particular compiler you're using, I do know that most compilers provide a more complex way of specifying the memory map. The ATmega series from Atmel for example provides the capability of specifying custom memory section in the project settings. On a GNU toolchain for example, these sections are used as part of the variable declarations by using the section attribute with the variable:

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

For the ATmega series you locate any memory in EEPROM by including on the same line as your variable declaration (either before or after, so long as it comes before the '=' in an assignment) the text:

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

If you'd like to guarantee that the specific memory address in EEPROM is set to a value as part of your binary image, so it only gets programmed once when the image is first written, you can declare a custom memory section in your project settings (it's under the "Memory Settings" of the "Toolchain" settings if you're developing in Atmel Studio).

For example, I've done exactly what you describe with a block of data by declaring section ".tune_data" in the EEPROM portion of the memory settings (following provided documentation as to address offsets, etc) then declaring a variable like the following:

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

Clearly it's going to be slightly different since you're not using a GNU compiler and may not be using Atmel Studio. If you look into it however, pretty much every toolchain for embedded programming provides some way to declare a custom memory section that can then be attached to a variable in the code via a pragma (or attribute for GNU toolchains). The specification should be available through a command-line argument and/or modification of a standard linkerscript with a command-line options to specify a non-default linkerscript. I know the second method is the standard and only way to do it on an IAR provided toolchain.

Related