Can/Should 我通过单个指针访问多个设备寄存器?
Can/Should I access multiple device registers via a single pointer?
我目前正在为 STM32F446RE(ARM 编译器)编写 C 语言,并且由于我想获得嵌入式编程方面的经验,所以我没有使用任何库。对于我的初始化,我想知道通过将一个指针递增到该寄存器与外设基址的偏移量来访问寄存器是否是一个好主意。
void I2C_Init(void)
{
volatile uint32_t *reg_ptr = (uint32_t *) GPIOB_LOC;
*(reg_ptr + GPIOB_MODE_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating
*(reg_ptr + GPIOB_MODE_OFFSET) |= ((0xAU<<16) | (0xAU<<20)); //set pins 8, 9, 10, 11 to alt func
*(reg_ptr + GPIOB_OTYPE_OFFSET) &= ~(0xFU<<8); //no types
*(reg_ptr + GPIOB_OSPEED_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating
*(reg_ptr + GPIOB_OSPEED_OFFSET) |= ((0x5U<<16) | (0x5U<<20)); //set to normal speed (will get overriden by alt func)
*(reg_ptr + GPIOB_PUPD_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //no pull up or pull down
*(reg_ptr + GPIOB_AFH_OFFSET) &= ~0xFFFFU; //clear before updating
*(reg_ptr + GPIOB_AFH_OFFSET) |= 0x4444U; //set pins 8, 9, 10, 11 to alt func 4 (i2c1 & i2c2 SCL and SDA respectively)
}
在我的头文件中:
#define GPIOB_LOC 0x40020400UL //base
#define GPIOB_MODE_OFFSET (0x00)
#define GPIOB_OTYPE_OFFSET (0x04)
#define GPIOB_OSPEED_OFFSET (0x08)
#define GPIOB_PUPD_OFFSET (0x0C)
#define GPIOB_AFH_OFFSET (0x24)
这种做法不安全吗?是否有更好、更普遍接受的方法来访问多个设备寄存器,而无需为每个特定寄存器创建指针的开销?
谢谢大家!这是我的第一个 post,如果我可以做些什么来改进我的问题或任何更多有用的信息,也请告诉我。
如果偏移量基于字节,则不安全。
将 0x04
之类的内容添加到 uint32_t *reg_ptr
将导致生成的地址引用比 reg_ptr
中的值大四个 uint32_t
值的偏移量 - 而不是四个字节 更大。
例如,将 0x04
添加到 uint32_t *
指针值 0x40020400UL
将导致实际指针值 0x40020410UL
而 NOT 预期的 0x40020404UL
.
我目前正在为 STM32F446RE(ARM 编译器)编写 C 语言,并且由于我想获得嵌入式编程方面的经验,所以我没有使用任何库。对于我的初始化,我想知道通过将一个指针递增到该寄存器与外设基址的偏移量来访问寄存器是否是一个好主意。
void I2C_Init(void)
{
volatile uint32_t *reg_ptr = (uint32_t *) GPIOB_LOC;
*(reg_ptr + GPIOB_MODE_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating
*(reg_ptr + GPIOB_MODE_OFFSET) |= ((0xAU<<16) | (0xAU<<20)); //set pins 8, 9, 10, 11 to alt func
*(reg_ptr + GPIOB_OTYPE_OFFSET) &= ~(0xFU<<8); //no types
*(reg_ptr + GPIOB_OSPEED_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating
*(reg_ptr + GPIOB_OSPEED_OFFSET) |= ((0x5U<<16) | (0x5U<<20)); //set to normal speed (will get overriden by alt func)
*(reg_ptr + GPIOB_PUPD_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //no pull up or pull down
*(reg_ptr + GPIOB_AFH_OFFSET) &= ~0xFFFFU; //clear before updating
*(reg_ptr + GPIOB_AFH_OFFSET) |= 0x4444U; //set pins 8, 9, 10, 11 to alt func 4 (i2c1 & i2c2 SCL and SDA respectively)
}
在我的头文件中:
#define GPIOB_LOC 0x40020400UL //base
#define GPIOB_MODE_OFFSET (0x00)
#define GPIOB_OTYPE_OFFSET (0x04)
#define GPIOB_OSPEED_OFFSET (0x08)
#define GPIOB_PUPD_OFFSET (0x0C)
#define GPIOB_AFH_OFFSET (0x24)
这种做法不安全吗?是否有更好、更普遍接受的方法来访问多个设备寄存器,而无需为每个特定寄存器创建指针的开销?
谢谢大家!这是我的第一个 post,如果我可以做些什么来改进我的问题或任何更多有用的信息,也请告诉我。
如果偏移量基于字节,则不安全。
将 0x04
之类的内容添加到 uint32_t *reg_ptr
将导致生成的地址引用比 reg_ptr
中的值大四个 uint32_t
值的偏移量 - 而不是四个字节 更大。
例如,将 0x04
添加到 uint32_t *
指针值 0x40020400UL
将导致实际指针值 0x40020410UL
而 NOT 预期的 0x40020404UL
.