我有一组32位寄存器用于嵌入式应用程序(ARM裸机)中的外设,具有以下字节地址。
CTL 0x0;
STAT 0x4
TXR 0x8< - 不连续地址
RXR 0x20
DAT1 0x30< - 不连续地址
DAT2 0x40< - 不连续地址
等等
我想将所有这些寄存器分组为C结构(它是一个压缩结构)
struct my_peri {
uint32_t CTL;
uint32_t STAT;
uint32_t TXR;
uint32_t RXR;
uint32_t DAT1;
uint32_t DAT2;
};
struct my_peri* pPeri0 = (uint32_t*) (BASE_ADDRESS_OF_MY_PERI_0);
现在,如果我访问
pPeri->RXR; // This will point to (BASE_ADDRESS + 0x10)
// But the actual address i want to refer is (BASE_ADDRESS + 0x20)
为了获得正确的地址,我在
之间手动添加了一些元素struct my_peri {
uint32_t CTL;
uint32_t STAT;
uint32_t TXR;
uint32_t RESERVED[4]; // 0x10 to 0x1c
uint32_t RXR;
uint32_t RESERVED_1[3]; // 0x24-0x2c
uint32_t DAT1;
uint32_t RESERVED_2[3]; // 0x34-0x3c
uint32_t DAT2;
};
但是对RESERVED,RESERVED_1和RESERVED_2的任何访问都会根据外设规格给出错误。
Is there a way to add address spacing between the struct elements?
Without adding RESERVED elements
If not, is there a way to group these registers into a single data structure?.
With each register pointing to the right address.
我正在使用ARM-GCC工具链。
答案 0 :(得分:2)
是的,您可以使用“位字段”在结构中创建未命名的字段:
struct my_peri {
uint32_t CTL;
uint32_t STAT;
uint32_t TXR;
uint32_t : 32;
uint32_t RXR;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t DAT1;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t DAT2;
};
不幸的是没有数组语法;如果您愿意,可以通过将类型更改为uint64_t来折叠:32
到:64
对。
另一种方法是,如果您的字段与本示例中的字段完全相同,则将整个事物视为整数数组,并使用enum { CTL = 0, STAT = 1, TXR = 2, RXR = 4, ... }
将其编入索引。
答案 1 :(得分:0)
要回答你的两个问题, 你将不可避免地得到某种假填充元素,因为C没有强制为结构强制特定布局。
然而,在你最终拥有稀疏布局的情况下,实现这一点的更好方法可能是使用一个充满指针的结构。这不再以任何方式限制您的布局,并且在大多数情况下,如果您将指针定义为const,则gcc将完全优化取消引用,甚至应该优化整个数组。我承认这不是你要求的,但我认为它仍然是解决问题的好方法。您也不再依赖C扩展,并希望编译器尊重您的打包和布局要求。
答案 2 :(得分:0)
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
struct my_peri {
uint32_t CTL;
uint32_t STAT;
uint32_t TXR;
uint32_t RXR __attribute__((aligned (32)));
uint32_t DAT1 __attribute__((aligned (16)));
uint32_t DAT2 __attribute__((aligned (16)));
};
int main(void)
{
printf("RXR @%x\n", (unsigned) offsetof(struct my_peri, RXR));
printf("DAT1 @%x\n", (unsigned) offsetof(struct my_peri, DAT1));
printf("DAT2 @%x\n", (unsigned) offsetof(struct my_peri, DAT2));
return 0;
}
输出:
RXR @20
DAT1 @30
DAT2 @40
请注意,aligned
值必须是2的幂。但这可以解决这个问题。