2012-08-02 60 views
6

器CodeVision编译器为爱特梅尔处理器,有指定一个全局变量的存储地址的可能性,例如初始化变量并同时指定存储地址:是否有可能?

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

当然,按照标准C,变量可以在初始化声明

int a=42; 

但是,我没有找到任何可能性来做到这一点。 int a @0x100 = 42int a = 42 @0x100;不起作用,它们会导致编译器错误。

你可能会问,为什么它是如此重要这样做,因为人们可以简单地有

int a @0x100; 

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

但是,如果我在EEPROM变量,我需要初始化它们,因为这是只有这样才能自动生成带有值的eeprom文件。我不能在以后分配这些值,因为在这种情况下,它实际上会在程序的每个开始处将值写入eeprom。

+0

哪些特定的Atmel处理器家族?这个线程是否有助于http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=102678? – 2012-08-02 10:04:16

+0

ATmega,但eeprom处理是一样的。线程只是更详细地描述了我写在我的最后一段(如果我在声明'eeprom int a中给一个eeprom变量赋值= 42;'这意味着这个值将被添加到生成的eeprom文件中,该文件只会被写入一次。每次程序启动时它都不会写入eeprom,这是一个非常好的功能)。如果我已经在一个单独的命令中赋值,它将被编译为一个写入eeprom的指令。感谢您的链接,我会试着问,如果我没有在这里得到任何有用的东西。 – vsz 2012-08-02 11:33:36

+0

请解释一下你实际上想要做的事情,听起来你已经走错了一条可以完成的事情。爱特梅尔与此无关。你想控制在特定地址的eeprom空间中的值吗?你想控制寄存器/内存中不在eeprom中的值吗?如果后者是你想控制地址,以便你的程序一旦启动可以有一个变量,指向该寄存器/内存位置(这是不是在eeprom)? – 2012-08-05 11:40:54

回答

2

只是看看CodeVisionAVR帮助,

“必须使用以下过程,如果一个全局变量,放置在使用@ 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; 
0

您可以使用指针指向绝对地址:

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

然后你可以使用对其操作*在该地址访问值,像这样:

int value = *pa; 

*pa = 0x10; 

编辑:没有办法将变量声明为指向特定区域,并且同时为该区域赋值。除非编译器具有允许它的扩展名。

+0

这只是另一种执行'int a @ 0x100'的方法((这很危险,因为编译器可能会在该地址分配其他东西)。它将如何在**那个地址初始化值**?此外,正如问题中所述,在eeprom变量的情况下它是最重要的。 – vsz 2012-08-02 05:37:34

+1

@vsz嵌入式系统的编译器对于内存和内存位置非常严格。嵌入式系统具有堆,堆栈和其他数据段的特定区域。只有当系统未配置时,编译器才会使用它不应该使用的内存地址范围。据我所知,我不支持ANSI C支持' – 2012-08-02 05:44:54

+0

'和'int a @ 0x100'。当然,AVR编译器(codevision和AVR-GCC以及其他可能的编译器)都有扩展功能。 – vsz 2012-08-02 05:53:42

2

虽然我知道没有办法直接分配一个EEPROM变量到一个特定的地址并初始化它,但我发现这个链接非常有用:EEPROM data at fixed address

我使用的解决方案是在EEPROM中声明一个结构,并且程序中的所有EEPROM变量都是该结构的成员。您定义结构成员的顺序将是链接器将它们放置在EEPROM地址空间中的顺序。由于该结构将是唯一的全局EEPROM声明,所以可以说它将被寻址到地址0x0000。因此,您将知道每个EEPROM变量的地址。

例子:

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; 

然后,您可以初始化变量结构的声明。编译时,这将在已知的EEPROM地址处创建具有初始化值的.eep文件。

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

在AVR的bootloader区是用来升级的FLASH和新的程序需要访问存储在EEPROM变量,这尤其适用于场景。它甚至允许您在软件更新中添加EEPROM变量,只要您将它们添加到结构的末尾,以免干扰已建立的变量的地址。

2

我知道你在说什么,自己也有同样的问题。问题在于,使用@符号和变量本身的内联地址是大多数工具链的一个附加功能。尽管它支持很多嵌入式工具链,因此您可以明确地调出SFR或其他寄存器所在的位置,但对标准C来说这不是一个正常行为。

虽然我不熟悉所使用的特定编译器,我知道大多数编译器提供了更复杂的指定内存映射的方式。 Atmel的ATmega系列提供了在项目设置中指定自定义内存部分的功能。

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

对于的ATmega系列你通过包括在同一行作为定位在EEPROM的任何存储器:在GNU工具,例如,这些部分通过使用段属性与可变用作变量声明的一部分您的变量声明(之前或之后,只要它之前“=”在分配中来)的文本:如果你想保证在EEPROM中的特定的内存地址设置为

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

一个值作为二进制图像的一部分,因此只有在第一次写入图像时才会编程一次,您可以在自己的位置声明一个自定义内存部分r项目设置(如果您在Atmel Studio中开发,它位于“工具链”设置的“Memory Settings”下)。例如,我已经通过在内存设置的EEPROM部分中声明部分“.tune_data”完成了对数据块的描述(以下提供了有关偏移地址的文档),然后声明一个变量像下面这样:

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

显然,这是怎么回事,因为你不使用GNU编译器略有不同,可能不会采用Atmel Studio中。但是,如果你仔细研究它,几乎每一个嵌入式编程工具链都提供了一些方法来声明一个自定义内存部分,然后可以通过编译指示(或GNU工具链的属性)将其附加到代码中的变量中。规范应该可以通过命令行参数和/或使用命令行选项修改标准linkerscript来指定非默认linkerscript。我知道第二种方法是在IAR提供的工具链上实现它的标准方法。