在Linux中,可以在用户空间使用sysfs和mmap(/dev/mem)方式操作GPIO,本次实验的平台为IMX8MM(飞凌OKMX8MM-C开发板),主要介绍sysfs
操作GPIO步骤,并附完整代码。
使用sysfs操作GPIO
sysfs
是一个基于内存的文件系统,可以向用户模式应用程序提供详细的内核数据结构信息。使用sysfs
操作GPIO时,需要先导出IO口,然后设置IO方向及中断模式。具体介绍见https://www.kernel.org/doc/Documentation/gpio/sysfs.txt。
1、确定GPIO编号
使用cat /sys/kernel/debug/gpio
查看GPIO信息:
root@okmx8mm:~# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-31, parent: platform/30200000.gpio, 30200000.gpio:
gpiochip1: GPIOs 32-63, parent: platform/30210000.gpio, 30210000.gpio:
gpio-38 ( |? ) out hi
gpio-44 ( |cd ) in hi IRQ
gpio-51 ( |VSD_3V3 ) out lo
gpiochip2: GPIOs 64-95, parent: platform/30220000.gpio, 30220000.gpio:
gpio-80 ( |status ) out hi
gpio-83 ( |usb_otg1_vbus ) out lo
gpio-89 ( |WLAN_EN ) out lo
gpiochip3: GPIOs 96-127, parent: platform/30230000.gpio, 30230000.gpio:
gpio-118 ( |headphone detect ) in lo IRQ
gpio-124 ( |GPIO Key HOME ) in hi IRQ
gpio-127 ( |GPIO Key UP ) in hi IRQ
gpiochip4: GPIOs 128-159, parent: platform/30240000.gpio, 30240000.gpio:
gpio-130 ( |GPIO Key DOWN ) in hi IRQ
gpio-137 ( |spi_imx ) out hi
gpio-141 ( |spi_imx ) out hi
在这儿我要使用GPIO5_IO00
,由上面gpiochip4: GPIOs 128-159, parent: platform/30240000.gpio, 30240000.gpio
可以看到,GPIO5对应的编号范围为128~159,所以GPIO5_IO00
对应的编号为128(128 + 0),依次类推,GPIO5_IO01
的编号为129。
2、GPIO配置
进入/sys/class/gpio
,可以看到以下内容:
root@okmx8mm:~# cd /sys/class/gpio
root@okmx8mm:/sys/class/gpio# ls
export gpiochip0 gpiochip32 gpiochip96
gpio118 gpiochip128 gpiochip64 unexport
- 其中
export
用于导出GPIO到用户空间,例如导出编号为128(GPIO5_IO00):
echo 128 > export
当前目录下会生成gpio128
目录,当系统重启时,导出的IO口会消失,所以每次使用时,最好先导出IO口。
-
unexport
用于取消导出的GPIO,例如:
echo 128 > unexport
这儿我需要使用GPIO5_IO00
和GPIO5_IO01
,所以需要运行以下指令:
echo 128 > export
echo 129 > export
进入其中一个目录可以看到:
root@okmx8mm:/sys/class/gpio/gpio128# ls
active_low device direction edge power subsystem uevent value
其中direction
用于设置IO方向(in、out),edge
用于设置中断模式(none、rising、falling、both),value
用于读取IO电平,具体内容见https://www.kernel.org/doc/Documentation/gpio/sysfs.txt。
这儿我把GPIO5_IO00
设置为中断输入模式,GPIO5_IO01
设置为输出模式:
root@okmx8mm:/sys/class/gpio/gpio128# echo "in" > direction
root@okmx8mm:/sys/class/gpio/gpio128# echo "rising" > edge
root@okmx8mm:/sys/class/gpio/gpio128# cd ../gpio129
root@okmx8mm:/sys/class/gpio/gpio129# echo "out" > direction
测试时可以使用echo 1 > value
设置GPIO5_IO01
输出高电平;echo 0 > value
设置GPIO5_IO01
输出低电平。
最后配置结果如下:
root@okmx8mm:/sys/class/gpio/gpio129# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-31, parent: platform/30200000.gpio, 30200000.gpio:
gpiochip1: GPIOs 32-63, parent: platform/30210000.gpio, 30210000.gpio:
gpio-38 ( |? ) out hi
gpio-44 ( |cd ) in hi IRQ
gpio-51 ( |VSD_3V3 ) out lo
gpiochip2: GPIOs 64-95, parent: platform/30220000.gpio, 30220000.gpio:
gpio-80 ( |status ) out hi
gpio-83 ( |usb_otg1_vbus ) out lo
gpio-89 ( |WLAN_EN ) out lo
gpiochip3: GPIOs 96-127, parent: platform/30230000.gpio, 30230000.gpio:
gpio-118 ( |headphone detect ) in lo IRQ
gpio-124 ( |GPIO Key HOME ) in hi IRQ
gpio-127 ( |GPIO Key UP ) in hi IRQ
gpiochip4: GPIOs 128-159, parent: platform/30240000.gpio, 30240000.gpio:
gpio-128 ( |sysfs ) in lo IRQ
gpio-129 ( |sysfs ) out lo
gpio-130 ( |GPIO Key DOWN ) in hi IRQ
gpio-137 ( |spi_imx ) out hi
gpio-141 ( |spi_imx ) out hi
3、测试
使用epoll读取GPIO5_IO00
中断,并翻转GPIO5_IO01
,完整代码如下:
//
// Created by txfly on 2020/8/25.
//
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/epoll.h>
int main(int argc, char *argv[]) {
// int fd = open("/sys/class/gpio/export", O_WRONLY);
// if (fd == -1){
// write(fd, "128", 3);
// write(fd, "129", 3);
// }
// close(fd);
// 前面手动导出过,这儿就不做处理了
// 中断输入
int trigger = open("/sys/class/gpio/gpio128/value", O_RDWR | O_NONBLOCK);
if (trigger == -1) {
printf("Fail to open GPIO5_IO00\n");
exit(1);
}
// LED
int led = open("/sys/class/gpio/gpio129/value", O_WRONLY);
if (led == -1) {
printf("Fail to open GPIO5_IO01\n");
exit(1);
}
// epoll
int epfd = epoll_create(1);
struct epoll_event ev, events;
ev.events = EPOLLPRI;
ev.data.fd = trigger;
int n = epoll_ctl(epfd, EPOLL_CTL_ADD, trigger, &ev);
if (n == -1) {
printf("Fail to add a file descriptor to the interface. \n");
exit(1);
}
char buf = 0;
while (1) {
n = epoll_wait(epfd, &events, 1, -1);
if (n > 0) {
lseek(trigger, 0, SEEK_SET);
n = read(trigger, &buf, 1);
printf("read, buf=%c\tlen=%d\n", buf, n);
if (buf == '0') {
write(led, "0", 1);
} else {
write(led, "1", 1);
}
} else {
break;
}
}
close(led);
close(trigger);
close(epfd);
}
版权声明:本文为「txfly」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://www.jianshu.com/p/0f702330bdc8