将具有许多成员的结构转换为内存地址

Casting a struct with many members to a memory address

我正在阅读(自学)一些微控制器代码,想验证我是否理解正确。

#define PERIPH_BASE           ((u32)0x40000000)
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)

/*------------------------ Reset and Clock Control ---------------------------*/
typedef struct
{
  vu32 CR;
  vu32 CFGR;
  vu32 CIR;
  vu32 APB2RSTR;
  vu32 APB1RSTR;
  vu32 AHBENR;
  vu32 APB2ENR;
  vu32 APB1ENR;
  vu32 BDCR;
  vu32 CSR;
} RCC_TypeDef;

#define RCC                 ((RCC_TypeDef *) RCC_BASE)

上面的第 3 行正在分配地址 0x40000000 + 0x20000 + 0x1000 to RCC_BASE

那应该是芯片设计者定义的地址;我可以在这个 datasheet 中找到它,它告诉 CPU 在哪里可以找到用于其余和控制时钟的寄存器集的开头。

显然 u32vu32 是 typdef,vu32volatile 告诉编译器不要对其进行任何优化。我拉了它,它是:

typedef volatile unsigned long  vu32;

所以最后一行将变量 RCC 设置为 RCC_BASE 从而将其第一个成员 CR 分配给 RCC_BASE 的值,因此 CFGR 变为 RCC_BASE + 0x04 ( 4 bytes i.e 32 bits),并且 CIR = RCC_BASE + 0x08 (64 bits)。这是因为 volatile.

这些都是准确的吗?有点准确?彻头彻尾的错误?

代码段看起来非常像 ARM 和 CMSIS,所以我会在这些方面尽力而为。

这些类型的声明在定义内存映射外设寄存器时很常见。定义 RCC 的最后一行不是变量声明。它是一个预处理器宏定义。目的是让你有这样的陈述:

vu32 cr = RCC->CR ;

在您的代码中,它将 RCC 外围设备中的 CR 寄存器的值提供给我以类似方式命名的局部变量。编译器计算 CR 结构成员的正确偏移量,并生成从该地址的内存中获取值所需的指令。显然,编译器不知道地址中有什么。由于它是由预处理器宏扩展的,意味着直接文本替换,最终你有一个硬物理地址强制转换为指向硬件外围寄存器的特定布局,你已经 "cleverly" 排列成 "C"结构体。波动性与此没有太大关系,除了编译器不会假设仅仅因为它没有对结构成员执行写入值就没有改变,即值可以在程序不执行写入的情况下改变。