在Linux中,可以在用戶空間使用sysfs和mmap(/dev/mem)方式操作GPIO,本次實(shí)驗(yàn)的平臺(tái)為IMX8MM(飛凌OKMX8MM-C開發(fā)板),主要介紹sysfs操作GPIO步驟,并附完整代碼。
使用sysfs操作GPIO
sysfs是一個(gè)基于內(nèi)存的文件系統(tǒng),可以向用戶模式應(yīng)用程序提供詳細(xì)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)信息。使用sysfs操作GPIO時(shí),需要先導(dǎo)出IO口,然后設(shè)置IO方向及中斷模式。具體介紹見https://www.kernel.org/doc/Documentation/gpio/sysfs.txt。
1、確定GPIO編號(hào)
使用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對應(yīng)的編號(hào)范圍為128~159,所以GPIO5_IO00對應(yīng)的編號(hào)為128(128 + 0),依次類推,GPIO5_IO01的編號(hào)為129。
2、GPIO配置
進(jìn)入/sys/class/gpio,可以看到以下內(nèi)容:
root@okmx8mm:~# cd /sys/class/gpio
root@okmx8mm:/sys/class/gpio# ls
export gpiochip0 gpiochip32 gpiochip96
gpio118 gpiochip128 gpiochip64 unexport
- 其中
export用于導(dǎo)出GPIO到用戶空間,例如導(dǎo)出編號(hào)為128(GPIO5_IO00):
echo 128 > export
當(dāng)前目錄下會(huì)生成gpio128目錄,當(dāng)系統(tǒng)重啟時(shí),導(dǎo)出的IO口會(huì)消失,所以每次使用時(shí),最好先導(dǎo)出IO口。
-
unexport用于取消導(dǎo)出的GPIO,例如:
echo 128 > unexport
這兒我需要使用GPIO5_IO00和GPIO5_IO01,所以需要運(yùn)行以下指令:
echo 128 > export
echo 129 > export
進(jìn)入其中一個(gè)目錄可以看到:
root@okmx8mm:/sys/class/gpio/gpio128# ls
active_low device direction edge power subsystem uevent value
其中direction用于設(shè)置IO方向(in、out),edge用于設(shè)置中斷模式(none、rising、falling、both),value用于讀取IO電平,具體內(nèi)容見https://www.kernel.org/doc/Documentation/gpio/sysfs.txt。
這兒我把GPIO5_IO00設(shè)置為中斷輸入模式,GPIO5_IO01設(shè)置為輸出模式:
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
測試時(shí)可以使用echo 1 > value設(shè)置GPIO5_IO01輸出高電平;echo 0 > value設(shè)置GPIO5_IO01輸出低電平。
最后配置結(jié)果如下:
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中斷,并翻轉(zhuǎn)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);
// 前面手動(dòng)導(dǎo)出過,這兒就不做處理了
// 中斷輸入
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);
}
版權(quán)聲明:本文為「txfly」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:http://www.itdecent.cn/p/0f702330bdc8