如何计算 devmem2/mmap 的 MMIO GPIO 地址
How to calculate MMIO GPIO addresses for devmem2/mmap
我正在尝试访问一些用于 LED 控制和电池监控的 MMIO GPIO 地址。但我不确定如何计算正确的地址。
文档说明如下:
COMMUINTY_BASE = Bus 0 Device 0x0d Function 0 Reg. 0x10
GPIO North Community PORT ID = 0xC5
GPIO North West Community PORT ID = 0xC4
GPIO_PADBAR = COMMUNITY_BASE + PORT ID << 16 + 0x500
GPO Reg = GPIO_PADBAR + GPIO_Offset Bit [0] (LEDs)
GPI Reg = GPIO_PADBAR + GPIO_Offset Bit [1] (Battery)
Example: Reg LED_USER1_RD_N_P1V8A = 0xD0C506A0
我的问题是北部社区端口 ID 和西北社区端口 ID 之间有什么区别?我什么时候需要使用哪个?在遵循记录的公式时,我也没有想出示例地址。
我编写了以下 C 程序来玩转计算:
int main(void) {
u_int32_t COMMUINTY_BASE = 0x10;
u_int32_t GPIO_NORTH_PORT = 0xC5;
u_int32_t GPIO_WEST_PORT = 0xC4;
u_int32_t GPIO_PADBAR = (COMMUINTY_BASE + GPIO_NORTH_PORT) << 16 + 0x500;
u_int32_t GPIO_REG = GPIO_PADBAR + 0x01;
printf("0x%04x\n", GPIO_REG);
}
但是输出是0xd50001
而不是0xD0C506A0
。
如果我尝试使用 devmem2
读取示例地址,它 returns 寄存器的所有位都设置为 1。
sudo devmem2 0xD0C506A0
结果读取:0xFFFFFFFF
如有任何帮助,我们将不胜感激。
我不明白他们是怎么得到 0xD0C506A0
的,只是我不明白为什么它在以 0xD0000000
开头的地址中。
您计算其他所有内容的方式有误。 <<
运算符的优先级高于 +
,因此应将等式用括号括起来 COMMUNITY_BASE + (PORT ID << 16) + 0x500
。为相关端口计算 PORT_ID << 16
得到 COMMUNITY_BASE + 0xC50000 + 0x500
= COMMUNITY_BASE + 0xC50500
。为此,您添加 0x1A0
的红色用户 1 LED 偏移以获得 COMMUNITY_BASE + 0xC506A0
.
我主要在这个级别做 ARM 架构,所以我不明白设备 0x0D 信息是如何变成 COMMUNITY_BASE
成为 0xD0000000
,但你知道了。
如果您查看文档,您还会看到地址是只写的 ("output"),这解释了为什么您无法从示例地址中读取。如果您不熟悉使用只写 GPIO 寄存器,它们并不少见。通常的方法是要么不读取它们,要么维护一个你认为它们应该是什么的内存副本,然后抽象对象,这样你就可以从寄存器的私有值中 "read" 和 "write" 到实际的 GPIO 引脚并更新您的私有值。
我正在尝试访问一些用于 LED 控制和电池监控的 MMIO GPIO 地址。但我不确定如何计算正确的地址。
文档说明如下:
COMMUINTY_BASE = Bus 0 Device 0x0d Function 0 Reg. 0x10
GPIO North Community PORT ID = 0xC5
GPIO North West Community PORT ID = 0xC4
GPIO_PADBAR = COMMUNITY_BASE + PORT ID << 16 + 0x500
GPO Reg = GPIO_PADBAR + GPIO_Offset Bit [0] (LEDs)
GPI Reg = GPIO_PADBAR + GPIO_Offset Bit [1] (Battery)
Example: Reg LED_USER1_RD_N_P1V8A = 0xD0C506A0
我的问题是北部社区端口 ID 和西北社区端口 ID 之间有什么区别?我什么时候需要使用哪个?在遵循记录的公式时,我也没有想出示例地址。
我编写了以下 C 程序来玩转计算:
int main(void) {
u_int32_t COMMUINTY_BASE = 0x10;
u_int32_t GPIO_NORTH_PORT = 0xC5;
u_int32_t GPIO_WEST_PORT = 0xC4;
u_int32_t GPIO_PADBAR = (COMMUINTY_BASE + GPIO_NORTH_PORT) << 16 + 0x500;
u_int32_t GPIO_REG = GPIO_PADBAR + 0x01;
printf("0x%04x\n", GPIO_REG);
}
但是输出是0xd50001
而不是0xD0C506A0
。
如果我尝试使用 devmem2
读取示例地址,它 returns 寄存器的所有位都设置为 1。
sudo devmem2 0xD0C506A0
结果读取:0xFFFFFFFF
如有任何帮助,我们将不胜感激。
我不明白他们是怎么得到 0xD0C506A0
的,只是我不明白为什么它在以 0xD0000000
开头的地址中。
您计算其他所有内容的方式有误。 <<
运算符的优先级高于 +
,因此应将等式用括号括起来 COMMUNITY_BASE + (PORT ID << 16) + 0x500
。为相关端口计算 PORT_ID << 16
得到 COMMUNITY_BASE + 0xC50000 + 0x500
= COMMUNITY_BASE + 0xC50500
。为此,您添加 0x1A0
的红色用户 1 LED 偏移以获得 COMMUNITY_BASE + 0xC506A0
.
我主要在这个级别做 ARM 架构,所以我不明白设备 0x0D 信息是如何变成 COMMUNITY_BASE
成为 0xD0000000
,但你知道了。
如果您查看文档,您还会看到地址是只写的 ("output"),这解释了为什么您无法从示例地址中读取。如果您不熟悉使用只写 GPIO 寄存器,它们并不少见。通常的方法是要么不读取它们,要么维护一个你认为它们应该是什么的内存副本,然后抽象对象,这样你就可以从寄存器的私有值中 "read" 和 "write" 到实际的 GPIO 引脚并更新您的私有值。