将C结构分配给片外存储器?

时间:2016-02-21 04:18:15

标签: c

我想知道如何将C结构分配给片外存储器。我想说的是,我不希望编译器在这些结构的内部存储器的堆栈或数据区域上分配空间。我想知道编译器如何意识到这些结构的实际数据将存储在外部,因此不应在内部存储器中为它们腾出空间。我该怎么做呢?

这是我的第一次破解,我认为我所做的是正确的并且会产生预期的结果,但我只是想确定。

msgFIFO *cmdFIFOPtr;    
msgFIFO *respFIFOPtr;   

volatile struct eleDataStrut *eleDataStrtPtr; 
volatile struct eleStatStrut *eleStatStrtPtr; 
volatile struct SysStatStrut *SysStatStrutPtr; 
volatile struct CommsCmdStrut *CommsCmdStrutPtr;

volatile struct navDataStrut *navDataStrtPtr;
volatile struct navStatStrut *navStatStrtPtr;
volatile struct OrienDataStrut *orienDataStrtPtr;
volatile struct navGPSDataStrut *navGPSDataStrutPtr;

volatile unsigned char *ele_vcs_array;
volatile unsigned char *nav_vcs_array;

void init_icsb_pointers( void ) {

    //volatile char *SharedRam1_ = (volatile char *) 0x10000000;

    cmdFIFOPtr     = (struct msgFIFO *) 0x10000000;
    respFIFOPtr    = (struct msgFIFO *) ( (int) cmdFIFOPtr + sizeof(struct msgFIFO) );

    eleDataStrtPtr  = (volatile struct eleDataStrut *) ( (int) respFIFOPtr + sizeof(struct msgFIFO) );
    eleStatStrtPtr  = (volatile struct eleStatStrut *) ( (int) eleDataStrtPtr + sizeof(struct eleDataStrut) );
    SysStatStrutPtr = (volatile struct SysStatStrut *) ( (int) eleStatStrtPtr + sizeof(struct eleStatStrut) );

    navDataStrtPtr = (volatile struct navDataStrut *) ( (int) SysStatStrutPtr + sizeof(struct SysStatStrut) );
    navStatStrtPtr = (volatile struct navStatStrut *) ( (int) navDataStrtPtr + sizeof(struct navDataStrut) );
    orienDataStrtPtr = (volatile struct OrienDataStrut *) ( (int) navStatStrtPtr + sizeof(struct navStatStrut) );
    navGPSDataStrutPtr = (volatile struct navGPSDataStrut *) ( (int) orienDataStrtPtr + sizeof(struct OrienDataStrut));
    CommsCmdStrutPtr   = (volatile struct CommsCmdStrut *) ( (int) navGPSDataStrutPtr + sizeof(struct navGPSDataStrut));

    ele_vcs_array = (volatile unsigned char *) eleStatStrtPtr;
    nav_vcs_array = (volatile unsigned char *) navDataStrtPtr;
}

3 个答案:

答案 0 :(得分:1)

有许多方法可以在特定位置分配变量:

  • Via Linker
  • 通过指针

查看链接器的命令文件。对于某些链接器,您需要为变量声明一个段,然后使用特殊语法将该变量放入块中。

语法的示例可以是:MyClass my_variable @ "segment_name";

您还可以设置指向内存中地址的指针:

struct USB_Registers;
USB_Registers * p_usb_1 = (USB_Registers *) 0x12345678;
p_usb_1->transmit_register = 'A';

另一种可能的方法是使用指针为每个成员分配指针:

#define USB_1_BASE_ADDRESS (0x12345678)
uint32_t * p_usb1_transmit_register = (uint32_t)(USB_1_BASE_ADDRESS + TRANSMIT_REG_OFFSET);
*p_usb1_transmit_register = 'B';

答案 1 :(得分:1)

可能遇到的问题(取决于您使用的处理器类型)是对齐方式。

例如,假设eleDataStrut以32位值开头,总大小为13个字节。如果eleDataStrtPtr位于地址0x10000040,则您的代码会将eleStatStrtPtr放在地址0x1000004D。如果处理器需要在4字节边界上对齐32位值,那么这是一个大问题。

解决方案是创建一个包含所有其他结构的大型结构,以便编译器处理任何对齐问题。像这样:

struct Everything
{
    msgFIFO a;
    msgFIFO b;

    struct eleDataStrut  c;
    struct eleStatStrut  d;
    struct SysStatStrut  e;
    struct CommsCmdStrut f;

    // and all the rest of them
};

msgFIFO *cmdFIFOPtr;
msgFIFO *respFIFOPtr;

volatile struct eleDataStrut *eleDataStrtPtr;
volatile struct eleStatStrut *eleStatStrtPtr;
volatile struct SysStatStrut *SysStatStrutPtr;
volatile struct CommsCmdStrut *CommsCmdStrutPtr;

void init_icsb_pointers( void )
{
    struct Everything *everything = (void *)0x10000000;

    cmdFIFOPtr  = &everything.a;
    respFIFOPtr = &everything.b;

    eleDataStrtPtr   = (volatile struct eleDataStrut *)  &everything.c;
    eleStatStrtPtr   = (volatile struct eleStatStrut *)  &everything.d;
    SysStatStrutPtr  = (volatile struct SysStatStrut *)  &everything.e;
    CommsCmdStrutPtr = (volatile struct CommsCmdStrut *) &everything.f;

    // and all the rest
}

答案 2 :(得分:1)

如果你正在使用特殊内存,你必须使用一些交叉编译器和放大器。接头

声明指针并手动初始化它们是一条通往地狱的高速公路。

一旦你将映射了六个区域,你基本上就会冒出几十行代码,很快就会很难维护。

这相当于链接器/定位器可以通过几个指令轻松实现的效率 这也允许编译器将这些指针视为常量,从而生成最有效的代码。

不幸的是,这些指令是编译器/链接器特定的。

我建议只使用手工制作的指针,只需要最多映射2-3个小区域,访问时间并不重要。