将指针写入GPIO输出引脚的地址

时间:2019-09-16 05:57:00

标签: c embedded gpio

嵌入式系统的绝对菜鸟。目前,我正在尝试在nRF52832中对名为C的设备进行编程。我知道GPIO的基地址是0x50000000,OUT寄存器的偏移量是0x504。如何创建指向GPIO OUT地址的指针并打印地址?

我可以做

volatile unsigned int* GPIO_BASE = (unsigned int*) 0x50000000;
volatile unsigned int* GPIO_OUT = GPIO_BASE + 0x504; ?

4 个答案:

答案 0 :(得分:3)

请记住,指针算术总是以指针基本类型为单位进行的。

这意味着表达式GPIO_BASE + 0x504将添加0x504 * sizeof *GPIO_BASE的字节偏移量,即0x504 * sizeof(int)(在大多数系统上,其偏移量为5136字节,而不是1284字节)。

如果要添加0x504字节的偏移量,则需要将其除以指针基类型的大小:

volatile unsigned int* GPIO_OUT = GPIO_BASE + (0x504 / sizeof *GPIO_BASE);

除此问题外,您的代码是正确的,并且是访问硬件寄存器的一种非常常见的方式。

答案 1 :(得分:2)

  

我愿意

volatile unsigned int* GPIO_BASE = (unsigned int*) 0x50000000;
volatile unsigned int* GPIO_OUT = GPIO_BASE + 0x504;

不,你不知道。这将意味着在运行时计算地址,因为volatile限定符意味着程序必须在运行时随时更新变量。

这应该改为:

// assuming 32 bit registers and 0x504 being the offset in bytes
#define GPIO_BASE 0x50000000u
#define GPIO_OUT  (*(volatile uint32_t*)(GPIO_BASE + 0x504u))
#define GPIO_X    (*(volatile uint32_t*)(GPIO_BASE + 0x508u)) // some other related register 

...
GPIO_OUT = something;

在此示例中,寄存器地址是在编译时计算的,这是唯一的正确方法。

通过取消引用宏中的地址,我们现在可以像使用普通变量一样使用GPIO_OUT

然而,GPIO外设似乎不太可能具有数百个内存映射寄存器,因此值0x504很奇怪。


还请注意,在嵌入式系统中使用默认的C类型,例如intchar是幼稚的。这些类型具有各种可移植性问题,并且还具有与它们相关的各种形式的定义不明确的行为。专业系统仅使用stdint.h中的类型,而不会使用其他任何类型。

答案 2 :(得分:0)

volatile unsigned int* GPIO_BASE = (unsigned int*) 0x50000000;
volatile unsigned int* GPIO_OUT = GPIO_BASE + 0x504; 

如果offset寄存器的OUT0x504之间有BASE个字节,则需要将GPIO_BASE转换为char *

volatile unsigned int* GPIO_OUT = ((char *)GPIO_BASE) + 0x504; 

否则一切正常。

答案 3 :(得分:0)

由于指针算术,指针GPIO_OUT的值将为GPIO_BASE +(0x504 * sizeof(int))。如果sizeof(int)是4个字节,则将获得指向0x50000000 +(0x504 * 4)= 0x50001410的指针,而OUT寄存器的实际地址为0x50000504。您可以将指针类型转换为无符号字符*,或者更好地使用宏。

#define GPIO_BASE 0x50000000

#define GPIO_OUT GPIO_BASE + 0x504

volatile unsigned int * gpio_out = GPIO_OUT;