0 前言
本文描述如果通过文件IO sysfs方式控制EasyARM GPIO端口。通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO方向,而value可控制GPIO输出或获得GPIO输入。
用户空间访问gpio,即通过sysfs接口访问gpio,下面是/sys/class/gpio目录下的三种文件:
--export/unexport文件
--gpioN指代具体的gpio引脚
--gpio_chipN指代gpio控制器
(1) export/unexport文件接口:
/sys/class/gpio/export,该接口只能写不能读
用户程序通过写入gpio的编号来向内核申请将某个gpio的控制权导出到用户空间
比如 echo 19 > export
上述操作会为19号gpio创建一个节点gpio19,此时/sys/class/gpio目录下边生成一个gpio19的目录
/sys/class/gpio/unexport和导出的效果相反。
比如 echo 19 > unexport
上述操作将会移除gpio19这个节点。
(2) /sys/class/gpio/gpioN
指代某个具体的gpio端口,里边有如下属性文件
direction 表示gpio端口的方向,读取结果是in或out。该文件也可以写,写入out 时该gpio设为输出同时电平默认为低。写入low或high则不仅可以设置为输出 还可以设置输出的电平。 当然如果内核不支持或者内核代码不愿意,将不会存在这个属性,比如内核调用了gpio_export(N,0)就表示内核不愿意修改gpio端口方向属性
value 表示gpio引脚的电平,0(低电平)1(高电平),如果gpio被配置为输出,这个值是可写的,记住任何非零的值都将输出高电平, 如果某个引脚能并且已经被配置为中断,则可以调用poll(2)函数监听该中断,中断触发后poll(2)函数就会返回。
edge 表示中断的触发方式,edge文件有如下四个值:"none", "rising", "falling","both"。
none 表示引脚为输入,不是中断引脚
rising 表示引脚为中断输入,上升沿触发
falling 表示引脚为中断输入,下降沿触发
both 表示引脚为中断输入,边沿触发
这个文件节点只有在引脚被配置为输入引脚的时候才存在。 当值是none时可以通过如下方法将变为中断引脚
echo "both" > edge;对于是both,falling还是rising依赖具体硬件的中断的触发方式。此方法即用户态gpio转换为中断引脚的方式
active_low 不怎么明白,也木有用过
(3)/sys/class/gpio/gpiochipN
gpiochipN 表示的就是一个gpio_chip,用来管理和控制一组gpio端口的控制器,该目录下存在一下属性文件:
base 和N相同,表示控制器管理的最小的端口编号。
lable 诊断使用的标志(并不总是唯一的)
ngpio 表示控制器管理的gpio端口数量(端口范围是:N ~ N+ngpio-1)
引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数
1 暴露GPIO操作接口
- static int gpio_export(int pin)
- {
- char buffer[BUFFER_MAX];
- int len;
- int fd;
-
- fd = open("/sys/class/gpio/export", O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "Failed to open export for writing!\n");
- return(-1);
- }
-
- len = snprintf(buffer, BUFFER_MAX, "%d", pin);
- if (write(fd, buffer, len) < 0) {
- fprintf(stderr, "Fail to export gpio!");
- return -1;
- }
-
- close(fd);
- return 0;
- }
2 隐藏GPIO操作接口
- static int gpio_unexport(int pin)
- {
- char buffer[BUFFER_MAX];
- int len;
- int fd;
-
- fd = open("/sys/class/gpio/unexport", O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "Failed to open unexport for writing!\n");
- return -1;
- }
-
- len = snprintf(buffer, BUFFER_MAX, "%d", pin);
- if (write(fd, buffer, len) < 0) {
- fprintf(stderr, "Fail to unexport gpio!");
- return -1;
- }
-
- close(fd);
- return 0;
- }
3 配置GPIO方向
- static int gpio_direction(int pin, int dir)
- {
- static const char dir_str[] = "in\0out";
- char path[DIRECTION_MAX];
- int fd;
-
- snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "failed to open gpio direction for writing!\n");
- return -1;
- }
-
- if (write(fd, &dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3) < 0) {
- fprintf(stderr, "failed to set direction!\n");
- return -1;
- }
-
- close(fd);
- return 0;
- }
【简单说明】
【1】dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3 如果输入为常数宏IN, 取dir_str[0]=“in”;若输入常数宏为OUT,取dir_str[0]=“out”。此处巧妙的使用了在数组中的“\0”。
4 控制GPIO输出
- static int gpio_write(int pin, int value)
- {
- static const char values_str[] = "01";
- char path[DIRECTION_MAX];
- int fd;
-
- snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);
- fd = open(path, O_WRONLY);
- if (fd < 0) {
- fprintf(stderr, "failed to open gpio value for writing!\n");
- return -1;
- }
-
- if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) {
- fprintf(stderr, "failed to write value!\n");
- return -1;
- }
-
- close(fd);
- return 0;
- }
5 获得GPIO输入
- static int gpio_read(int pin)
- {
- char path[DIRECTION_MAX];
- char value_str[3];
- int fd;
-
- snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "failed to open gpio value for reading!\n");
- return -1;
- }
-
- if (read(fd, value_str, 3) < 0) {
- fprintf(stderr, "failed to read value!\n");
- return -1;
- }
-
- close(fd);
- return (atoi(value_str));
- }
6 GPIO翻转操作
【main函数】
- int main(int argc, char *argv[])
- {
- int i = 0;
- gpio_export(P24);
-
- gpio_direction(P24, OUT);
- for (i = 0; i < 10; i++) {
- printf("LED Blink\n");
- gpio_write(P24, i % 2);
- usleep(500 * 1000);
- }
- gpio_write(P24, 0);
-
- gpio_unexport(P24);
- return 0;
- }
7 其他例子
- int set_io_value_high(int gpio)
- {
- FILE *fp;
- char buffer[10];
- int value;
- char s[50]="";
- char s1[50]="";
- if ((fp = fopen("/sys/class/gpio/export", "w")) == NULL)
- {
- printf("Cannot open export file.\n");
- return -1;
- }
- fprintf(fp, "%d", gpio);
- fclose(fp);
-
- sprintf(s,"/sys/class/gpio/gpio%d/direction",gpio);
- if ((fp = fopen(s, "rb+")) == NULL)
- {
- printf("Cannot open %s.\n",s);
- return -1;
- }
- fprintf(fp, "out");
- fclose(fp);
-
- sprintf(s1,"/sys/class/gpio/gpio%d/value",gpio);
-
- if ((fp = fopen(s1, "rb+")) == NULL)
- {
- printf("Cannot open %s.\n",s1);
- return -1;
- }
- strcpy(buffer,"1");
- fwrite(buffer, sizeof(char), sizeof(buffer) - 1, fp);
- fclose(fp);
- return 1;
- }
- int set_io_value_low(int gpio)
- {
- FILE *fp;
- char buffer[10];
- int value;
- char s[50]="";
- char s1[50]="";
- if ((fp = fopen("/sys/class/gpio/export", "w")) == NULL)
- {
- printf("Cannot open export file.\n");
- return -1;
- }
- fprintf(fp, "%d", gpio);
- fclose(fp);
-
- sprintf(s,"/sys/class/gpio/gpio%d/direction",gpio);
- if ((fp = fopen(s, "rb+")) == NULL)
- {
- printf("Cannot open %s.\n",s);
- return -1;
- }
- fprintf(fp, "out");
- fclose(fp);
-
- sprintf(s1,"/sys/class/gpio/gpio%d/value",gpio);
-
- if ((fp = fopen(s1, "rb+")) == NULL)
- {
- printf("Cannot open %s.\n",s1);
- return -1;
- }
- strcpy(buffer,"0");
- fwrite(buffer, sizeof(char), sizeof(buffer) - 1, fp);
- fclose(fp);
- return 1;
-
- }