c - 将位域结构映射到 volatile 寄存器

标签 c embedded bit-fields

我正在编写一个应用程序,它与 VHDL 中定义的许多寄存器进行交互。这些寄存器为 32 位宽,并分配到组中。我获得了组的基地址和组中每个成员的 32 位偏移量。这是一个组、组内的寄存器和寄存器结构的示例。

Group 1 | base addr | offset | data_port

data_port | alt_u32 data0 : 12; | alt_u32 data1 : 1; | ....

目前 I/O 使用以下位域结构处理,

typedef struct
{
   uint32_t   data0 : 12;
   uint32_t   data1 : 1;
   ...
}volatile data_port;

并使用指向地址的指针修改字段,

data_port *const p_data = (data_port *)0xc006380;

虽然这可能适用于此平台,但对于当前的编译器,我担心可移植性。我想知道在被迫使用这些非常规数据类型时是否有更好的方法来处理硬件接口(interface)?

我能想到的一个替代方案是在硬件和寄存器结构之间创建另一层,一个 volatile unsigned int 指针,并在应用层使用位域结构。问题是,数据仍然必须从位字段复制,这可能在另一个平台上以不同方式对齐到 int,这可能是另一个主题。

编辑:
我认为我真正在寻找的是一种消除位域使用的方法。将具有位域成员的结构映射到硬件似乎确实是一种糟糕的方法。因此,为了消除这种情况,我将使用以下内容之一作为指向 volatile 内存地址的指针,

#define PeripheralBase ((uint32_t volatile *)BASE)

uint32_t volatile *const peripheral_base  = (uint32_t *) BASE;

希望,一旦我达到这一点,一切都会在 32 位中很好地对齐。我想到的一种方法是创建相同的 data_port 结构,但删除位封装,然后为每个寄存器专门创建一个函数,将位转换为无符号整数,然后可以将其传递给寄存器使用 volatile 指针。

有点像,

static inline uint32_t struct_to_uint(data_port *data)
{
   return data->data0
        + ((uint32_t)data->data1 << 12)
        + ((uint32_t)data->data2 << 13)
        + .....;
}

我不确定语法是否正确,但我的想法是将值移入而不必担心编译器或平台。这使自?这种方法是否存在可移植性问题?

最佳答案

虽然位域非常依赖于实现,但您可以做的是使用宏来识别您的寄存器:

typedef struct
{
   uint32_t data0 : 12;
   uint32_t data1 : 1;
   ...
} data_port;

#define DATA_PORT (*(volatile data_port *) 0xc006380) 

然后以这种方式访问​​位:

 DATA_PORT.data0 = 1;  // set data0 bit of DATA_PORT to 1 

关于c - 将位域结构映射到 volatile 寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19282263/

相关文章:

c - 堆栈的内存地址

小端大端的混淆

embedded - 微 Controller 环境中的原子操作是什么?

c - 给出段错误的位字段

c - Turbo C 在执行 C 冒泡排序程序时挂起

c - C 中的 Vigenere 代码因多字符键而崩溃

windows - 滥用 USB 大容量存储类进行无驱动 I/O

embedded - 为什么您需要可编程实时单元 (PRU) 而您可以拥有 RTOS?

c - 为什么 sizeof 未命名位域成员结构打印 1?

c++ - C++ 中带位字段的结构体大小不相加