1.sysfs的方式
以nvidia NX的核心板为例:
-
1.1.内核源码GPIO相关
#define TEGRA194_MAIN_GPIO_PORT_A 0 #define TEGRA194_MAIN_GPIO_PORT_B 1 #define TEGRA194_MAIN_GPIO_PORT_C 2 #define TEGRA194_MAIN_GPIO_PORT_D 3 #define TEGRA194_MAIN_GPIO_PORT_E 4 #define TEGRA194_MAIN_GPIO_PORT_F 5 #define TEGRA194_MAIN_GPIO_PORT_G 6 #define TEGRA194_MAIN_GPIO_PORT_H 7 #define TEGRA194_MAIN_GPIO_PORT_I 8 #define TEGRA194_MAIN_GPIO_PORT_J 9 #define TEGRA194_MAIN_GPIO_PORT_K 10 #define TEGRA194_MAIN_GPIO_PORT_L 11 #define TEGRA194_MAIN_GPIO_PORT_M 12 #define TEGRA194_MAIN_GPIO_PORT_N 13 #define TEGRA194_MAIN_GPIO_PORT_O 14 #define TEGRA194_MAIN_GPIO_PORT_P 15 #define TEGRA194_MAIN_GPIO_PORT_Q 16 #define TEGRA194_MAIN_GPIO_PORT_R 17 #define TEGRA194_MAIN_GPIO_PORT_S 18 #define TEGRA194_MAIN_GPIO_PORT_T 19 #define TEGRA194_MAIN_GPIO_PORT_U 20 #define TEGRA194_MAIN_GPIO_PORT_V 21 #define TEGRA194_MAIN_GPIO_PORT_W 22 #define TEGRA194_MAIN_GPIO_PORT_X 23 #define TEGRA194_MAIN_GPIO_PORT_Y 24 #define TEGRA194_MAIN_GPIO_PORT_Z 25 #define TEGRA194_MAIN_GPIO_PORT_FF 26 #define TEGRA194_MAIN_GPIO_PORT_GG 27 //设备树中使用下面宏定义的,GPIO_BASE编号为288(通过cat /sys/class/gpio/gpiochipX/base得到) #define TEGRA194_MAIN_GPIO(port, offset) \ ((TEGRA194_MAIN_GPIO_PORT_##port * 8) + offset) //设备树中使用下面宏定义的,GPIO_BASE编号为248(通过cat /sys/class/gpio/gpiochipX/base得到) #define TEGRA194_AON_GPIO(port, offset) \ ((TEGRA194_AON_GPIO_PORT_##port * 8) + offset)
-
1.2.使用
sysfs interface
接口控制gpio:#确定gpiochipx的base值,X为gpio所在的gpiochip后的编号 cat /sys/class/gpio/gpiochipX/base #GPIO11使用的编号为 288+(16*8+6) = 422 ,将422号GPIO导出到/sys/gpio echo 422 > /sys/class/gpio/export #设置为输出 echo out > /sys/class/gpio/gpio422/direction #输出高电平 echo 1 > /sys/class/gpio/gpio422/value #输出低电平 echo 0 > /sys/class/gpio/gpio422/value #设置为输入 echo in > /sys/class/gpio/gpio422/direction #获取输入值 cat /sys/class/gpio/gpio22/value #取消导出 echo 422 > /sys/class/gpio/unexport
2.用libgpiod库读写IO
内核版本>4.8。
-
2.1.通过libgpiod提供的
gpioset
、gpioget
、gpiomon
可以快速的读写GPIO和检测输入事件-
1)安装gpiod命令行工具
sudo apt install gpiod
-
2)使用gpiod命令行工具
#查看系统支持多少个gpiochip sudo gpiodetect #查看指定的chip有多少lines sudo gpioinfo 0 #设置指定的gpiochip的某个line输出低电平,(134 = 16*8+6)和上面使用sysfs使操作的是同一个gpio) sudo gpioset -m wait 0 134=0 #设置指定的gpiochip的某个line输出高电平 sudo gpioset -m wait 0 134=1 #设置指定的gpiochip的某个line为输入,并获取其电平状态 sudo gpioget 0 134
-
-
2.2.通过调用libgpiod库函数,对gpio进行用户空间的编程
-
1).下载编译libgpiod库
#下载地址,需要选择合适的版本 https://mirrors.edge.kernel.org/pub/software/libs/libgpiod/ #配置安装 cd libgpiod ./configure make make install #安装命令行工具(或使用 sudo apt install gpiod ) cd tools make sudo make install #配置动态库 sudo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib sudo ldconfig
-
2).编写测试程序调用libgpiod库
#include <stdio.h> #include <unistd.h> #include <string.h> #include <gpiod.h> int main(int argc, char *argv[]) { struct gpiod_chip *output_chip; struct gpiod_line *output_line; struct gpiod_chip *input_chip; struct gpiod_line *input_line; struct gpiod_line_event event; char *chip_out = "gpiochip0"; unsigned int offset_out = 134; char *chip_in = "gpiochip0"; unsigned int offset_in = 148; int line_value = 0; /* Configure a GPIO as output */ output_chip = gpiod_chip_open_by_name(chip_out); if(!output_chip) { perror("gpiod_chip_open_by_name failed\n"); return EXIT_FAILURE; } output_line = gpiod_chip_get_line(output_chip, offset_out); if(!output_line) { perror("gpiod_chip_get_line failed\n"); return EXIT_FAILURE; } if(gpiod_line_request_output(output_line, "out1", GPIOD_LINE_ACTIVE_STATE_LOW) < 0){ perror("gpiod_line_request_output failed\n"); return EXIT_FAILURE; } gpiod_line_set_value(output_line, line_value); /* Configure a GPIO as input */ input_chip = gpiod_chip_open_by_name(chip_in); if(!input_chip) { perror("gpiod_chip_open_by_name failed\n"); return EXIT_FAILURE; } input_line = gpiod_chip_get_line(input_chip, offset_in); if(!input_line) { perror("gpiod_chip_get_line failed\n"); return EXIT_FAILURE; } if (gpiod_line_request_rising_edge_events(input_line, "in1") < 0){ perror("gpiod_line_request_rising_edge_events failed\n"); return EXIT_FAILURE; } while (1) { gpiod_line_event_wait(input_line, NULL); if (gpiod_line_event_read(input_line, &event) != 0) continue; /* this should always be a rising event in our example */ if (event.event_type != GPIOD_LINE_EVENT_RISING_EDGE) continue; if(gpiod_line_get_value(input_line)==1) { line_value = !line_value; gpiod_line_set_value(output_line, line_value); printf("out1_value: %d\n", line_value); } usleep(5000); } gpiod_chip_close(output_chip); gpiod_chip_close(input_chip); return EXIT_SUCCESS; }
-
3).编译测试程序
gcc -o gpiotest gpiotest.c -lgpiod -L/usr/local/lib -I/usr/local/include --static
-
4).执行测试程序
sudo ./gpiotest
-