c 语言结构体成员和位域在内存中的存储方式#
在小端存储的机器上,C编译器对结构体的成员按它们的声明顺序从低到高的地址进行存储,先定义的成员存储在内存的低地址,使用位域的时候也是类似,先定义的成员先占用低比特位。
c 语言怎么描述硬件寄存器?#
通常硬件寄存器会映射到一段特定的内存地址,我们可以通过指针来访问和修改寄存器的内容。每个寄存器的功能不一定相同,需要根据硬件手册来具体定义。下面以某个芯片平台的 pwm 控制寄存器为例,说明如何使用 c 语言描述硬件寄存器。
这个平台有 4 个 pwm 外设,控制寄存器的基址分别是 0xD401A000,0xD401A400,0xD401A800 ,0xD401AC00,然后每个 pwm 有三个 32 位 的寄存器,分别是 PWM_CRx,PWM_DCR,PWM_PCR。在这三个寄存器里面,不同的 bit 范围之间又控制着不同的功能。在 c 语言里面,可通过联合体、结构体和位域来定义这些寄存器的功能。
三个 pwm 控制寄存器的基地址:
1
2
3
4
5
| #include <stdint.h>
#define PWM0_BASE (0xD401A000)
#define PWM1_BASE (0xD401A400)
#define PWM2_BASE (0xD401A800)
#define PWM3_BASE (0xD401AC00)
|
每个 pwm 有三个寄存器, PWM_CRx,PWM_DCR,PWM_PCR,与偏移地址对应,4字节递增:
1
2
3
4
5
6
| typedef volatile struct
{
uint32_t PWM_CRx; /*Offset: 0x00*/
uint32_t PWM_DCR ; /*Offset: 0x04*/
uint32_t PWM_PCR ; /*Offset: 0x08*/
}PWM_HW_T;
|
将 pwm 寄存器地址转换为 PWM_HW_T * 类型的指针,方便通过指针对数据进行读写:
1
2
3
4
| #define HW_PWM0 ((PWM_HW_T *)(PWM0_BASE))
#define HW_PWM1 ((PWM_HW_T *)(PWM1_BASE))
#define HW_PWM2 ((PWM_HW_T *)(PWM2_BASE))
#define HW_PWM3 ((PWM_HW_T *)(PWM3_BASE))
|
每个寄存器的功能定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| // PWM_CRx 寄存器定义
typedef union
{
uint32_t v;
struct
{
uint32_t PRESCALE : 6; //[5:0]
uint32_t SD : 1; //[6]
uint32_t Reserved :25; //[31:7]
}d;
}REG_PWM_CRx_T;
// PWM_DCR 寄存器定义
typedef union
{
uint32_t v;
struct
{
uint32_t DCYCLE : 10; //[9:0]
uint32_t FD :1; //[10]
uint32_t Reserved :21; //[31:11]
}d;
}REG_PWM_DCR_T;
// PWM_PCR 寄存器定义
typedef union
{
uint32_t v;
struct
{
uint32_t PV : 10; //[9:0]
uint32_t Reserved :22; //[31:10]
}d;
}REG_PWM_PCR_T;
|
操作 pwm 寄存器示例,读和写寄存器都可以通过指针操作实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| void PWM0_Init(void)
{
PWM_HW_T *PWM = HW_PWM0;
REG_PWM_CRx_T PWM_CRx = {0};
REG_PWM_DCR_T PWM_DCR = {0};
REG_PWM_PCR_T PWM_PCR = {0};
PWM_CRx.d.PRESCALE = 0x3F;
PWM_CRx.d.SD = 0;
PWM_CRx.d.Reserved = 0;
// 写 pwm0 的 PWM_CRx 寄存器
PWM->PWM_CRx = PWM_CRx.v;
// 读 pwm0 的 PWM_DCR 寄存器
PWM_DCR.v = PWM->PWM_DCR;
PWM_PCR.d.PV = 0x3FF;
PWM_PCR.d.Reserved = 0;
PWM->PWM_PCR = PWM_PCR.v;
}
|