前面介绍了使用sysfs
操作GPIO,这儿介绍另一种方式:mmap
。mmap可以将物理设备/dev/mem
映射到内存,通过读写内存的方式操作GPIO寄存器,使用起来速度比sysfs
更快。
测试环境: 飞凌OKMX8MM-C开发板
使用寄存器操作GPIO时,需要设置的寄存器有:
- Pad Mux Register,PAD复用寄存器
- Pad Control Register,PAD控制寄存器
- GDIR,GPIO 方向寄存器
- DR,数据寄存器
下面以GPIO5_IO00
为例,先从手册中找到各寄存器的地址,并介绍基本配置。
Pad Mux Register
Pad Mux Register是端口复用寄存器,GPIO5_IO00
复用的端口为SAI3_TXC
,对应的寄存器为IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC
,可以看到地址为0x303301DC
,占用四个字节。文档内容如下图所示:
Mux Mode 其中后三位用于设置复用模式。从表格中可以看到,
MUX_MODE
设置为101
,可以复用为IO模式。
Pad Control Register
对应的寄存器为IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC
,查手册可以看到地址为0x30330444
。
FSEL
部分,设置为FAST
模式,即0x10
。
GDIR和DR
GDIR和DR设置比较简单,所以放在一起说。根据手册可以看到,GPIO5
对应的GDIR寄存器地址为0x30240004
,DR寄存器地址为 0x30240000
。
GDIR介绍 从上面可以看到,如果我们使用GPIO某个引脚,将对应的位置1或者置0即可。这儿我们使用
GPIO5_IO00
用于输出,所以将GPIO5
对应的GDIR寄存器0
位置为1即可。
同样,DR寄存器用于设置IO输出电平,将对应的位置1或置0即可:
DR寄存器 我们使用的是GPIO5_IO00
,所以操作GPIO5
对应的DR寄存器第0
位即可。
综上所述,GPIO5_IO00
对应的寄存器为:
- Pad Mux Register,0x303301DC
- Pad Control Register,0x30330444
- GDIR,0x30240004
- DR,0x30240000
测试
首先打开/dev/mem
文件,然后使用mmap
映射到内存。使用mmap时要注意起始位置、长度和偏移。在这里我从偏移为GPIO5_DR 0x30240000
处开始映射,IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC 0x30330444
处结束,共984132个字节。在这儿getpagesize()
大小为4096,所以把长度设为getpagesize() * 250
,这儿只要不小于实际长度就行。
下面是完整测试代码:
//
// Created by txfly on 2020/8/26.
//
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
// gpio5_00
#define GPIO5_DR 0x30240000
#define GPIO5_GDIR 0x30240004
#define GPIO5_PSR 0x30240008
#define IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC 0x303301DC
#define IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC 0x30330444
static volatile uint32_t *gpio;
int main(int argc, char **argv) {
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) {
printf("Unable to open /dev/mem: %s\n", strerror(errno));
return -1;
}
gpio = (uint32_t *) mmap(0, getpagesize() * 250, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO5_DR);
if ((void *) gpio == MAP_FAILED) {
printf("mmap failed: %s\n", strerror(errno));
exit(1);
}
printf("start config mux...\n");
*(gpio + (IOMUXC_SW_MUX_CTL_PAD_SAI3_TXC - GPIO5_DR) / 4) |= 0x5;
printf("start config pad...\n");
*(gpio + (IOMUXC_SW_PAD_CTL_PAD_SAI3_TXC - GPIO5_DR) / 4) |= 0x10;
printf("start config direction...\n");
*(gpio + (GPIO5_GDIR - GPIO5_DR) / 4) |= 0x1;
printf("start...\n");
while (1) {
*gpio ^= 0x1;
usleep(500000);
}
munmap(gpio, getpagesize() * 250);
close(fd);
}
版权声明:本文为「txfly」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://www.jianshu.com/p/d4681baf0288
网友评论