简体   繁体   English

初始化变量并同时指定存储地址:是否可能?

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

In the codevision compiler for Atmel processors, there is a possibility to specify the storage address of a global variable, for example 例如,在Atmel处理器的codevision编译器中,可以指定全局变量的存储地址

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 当然,根据标准C,变量可以在声明时初始化

int a=42;

However, I did not find any possibility to do them both. 但是,我没有发现任何可能同时做到这两点。 int a @0x100 = 42 or int a = 42 @0x100; int a @0x100 = 42int 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. 但是,如果我在EEPROM中有变量,我需要初始化它们,因为这是自动生成带有值的eeprom文件的唯一方法。 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. 我以后不能分配这些值,因为在这种情况下,它实际上会在程序的每个开始时将值写入eeprom。

While I know of no way to directly assign an EEPROM variable to a specific address and initialize it, I found this link very helpful: EEPROM data at fixed address . 虽然我知道无法直接将EEPROM变量分配给特定地址并对其进行初始化,但我发现此链接非常有用: 固定地址的EEPROM数据

The solution I used was that of declaring a struct in EEPROM and having all EEPROM variables in your program be a member of that struct. 我使用的解决方案是在EEPROM中声明一个结构,并且程序中的所有EEPROM变量都是该结构的成员。 The order you define the members of the struct will be the order they are placed in the EEPROM address space by the linker. 您定义结构成员的顺序将是链接器将它们放置在EEPROM地址空间中的顺序。 Since the struct will be the only global EEPROM declaration it is safe to say it will be addressed to address 0x0000. 由于结构将是唯一的全局EEPROM声明,因此可以安全地说它将被寻址到地址0x0000。 Therefore, you will know the address of each EEPROM variable. 因此,您将知道每个EEPROM变量的地址。

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;

You can then initialize the variables in the declaration of the structure. 然后,您可以在结构声明中初始化变量。 When you compile, this will create the .eep file with the initialized values at the known EEPROM addresses. 编译时,这将创建.eep文件,其初始值为已知的EEPROM地址。

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

This works especially well in scenarios where the bootloader section of the AVR is used to upgrade the FLASH and the new program needs to access the stored EEPROM variables. 这在AVR的引导加载程序部分用于升级FLASH并且新程序需要访问存储的EEPROM变量的情况下尤其有效。 It even allows you to add EEPROM variables across software updates as long as you add them to the end of the struct so as not to disturb the addresses of those variables already established. 它甚至允许您在软件更新中添加EEPROM变量,只要将它们添加到结构的末尾即可,以免干扰已建立的变量的地址。

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. 虽然它支持许多嵌入式工具链,因此您可以明确地调出SFR或其他寄存器所在的位置,但这不是标准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. 例如,Atmel的ATmega系列提供了在项目设置中指定自定义内存部分的功能。 On a GNU toolchain for example, these sections are used as part of the variable declarations by using the section attribute with the variable: 例如,在GNU工具链上,通过将section属性与变量一起使用,这些部分将用作变量声明的一部分:

 __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: 对于ATmega系列,您可以通过与变量声明位于同一行(在赋值之前或之后,只要它在赋值中的'='之前)包含在EEPROM中的任何内存:

__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). 如果您想保证EEPROM中的特定存储器地址被设置为二进制映像的一部分,那么它只能在首次写入映像时编程一次,您可以在项目设置中声明自定义存储器部分(如果您正在使用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: 例如,我通过在内存设置的EEPROM部分中声明“.tune_data”部分(按照提供的文档解决偏移等)然后声明如下变量来完成您用数据块描述的内容:

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. 显然,由于您没有使用GNU编译器而且可能没有使用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). 但是,如果你研究它,几乎每个嵌入式编程的工具链都提供了一些方法来声明一个自定义内存部分,然后可以通过编译指示(或GNU工具链的属性)将其附加到代码中的变量。 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. 规范应该可以通过命令行参数和/或使用命令行选项修改标准linkerscript来指定非默认的linkerscript。 I know the second method is the standard and only way to do it on an IAR provided toolchain. 我知道第二种方法是在IAR提供的工具链上进行标准和唯一的方法。

Just a look at CodeVisionAVR help, 只需看看CodeVisionAVR帮助,

"The following procedure must be used if a global variable, placed at a specific address using the @ operator , must be initialized during declaration: “如果在声明期间必须初始化使用@ operator放置在特定地址的全局变量,则必须使用以下过程:

/* 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; 

You can use pointer that point to an absolute address: 您可以使用指向绝对地址的指针:

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

Then you can use the dereferencing operator * to access the value at that address like so: 然后你可以使用解除引用运算符*来访问该地址的值,如下所示:

int value = *pa;

or 要么

*pa = 0x10;

Edit: There is no way of declaring a variable to point to a specific area and at the same time assign a value to that area. 编辑:无法声明变量指向特定区域,同时为该区域指定值。 Not unless the compiler has extensions that allow it. 除非编译器具有允许它的扩展名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM