LINUX GPIO 基操之应用层
应用层sysfs操作GPIO相关文件节点介绍如何编写应用程序操作GPIO如何通过寄存器操作GPIO注:所有文章基于linux-3.13 以上,本系列主要介绍 GPIO的一些基本知识,驱动操作GPIO的接口,应用层通过sysfs操作GPIO的接口,GPIO一些debug信息查看,以及对高通相关GPIO的寄存器操作。分享给刚刚接触外设bsp的小伙伴们。当然后面有时间还会分享GPIO子系统框架和pinctrl子系统框架,先知道黑盒怎么使用,然后咱再打开仔细瞅瞅。有错误不正当点,勿喷,还请指出,一起修改,谢谢!!
本篇为应用层控制接口篇,主要分享,应用层对gpio的操作和如何通过寄存器操作gpio(主要介绍高通的寄存器方式)。
应用层sysfs操作GPIO
相关文件节点介绍
1)导出节点
//下面的动作前提是要先导出对应的gpio,动态生成了对应的节点才能下一步操作echo 1 > /sys/class/gpio/export
2) 设置输入方向,读取对应的值
echo in > /sys/class/gpio/gpio1/directioncat /sys/class/gpio/gpio1/value
3)设置输出方向,设置对应的值
echo out > /sys/class/gpio/gpio1/direction//拉高echo 1 > /sys/class/gpio/gpio1/value//拉低echo 1 > /sys/class/gpio/gpio1/value
4) 设置中断触发方式
//设置的中断触发方式 none rising falling both,echo none > /sys/class/gpio/gpio1/edge// 要结合poll机制来获取对应gpio口的中断
5)销毁对应GPIO节点
echo 1 > /sys/class/gpio/unexport
如何编写应用程序操作GPIO
我们完全可以通过调用system的方式实现上面提到的前三种操作,但是无法实现中断的监控,而且system方式太消耗资源。linux里面万物皆文件,下面重点介绍如何通过open,write,poll等方式对gpio进行操作。
1)需要包含的头文件
#include stdlib.h #include stdio.h #include string.h#include unistd.h#include fcntl.h #include poll.h
2)导出一个节点
tatic int gpio_export(int pin) {char buffer[64]; int len; int fd; fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) {MSG("Failed to open export for writing!\n"); return(-1); } len = snprintf(buffer, sizeof(buffer), "%d", pin); if (write(fd, buffer, len) < 0) {MSG("Failed to export gpio!"); return -1; } close(fd); return 0; }
3)销毁一个节点
static int gpio_unexport(int pin) {char buffer[64]; int len; int fd; fd = open("/sys/class/gpio/unexport", O_WRONLY); if (fd < 0) {MSG("Failed to open unexport for writing!\n"); return -1; } len = snprintf(buffer, sizeof(buffer), "%d", pin); if (write(fd, buffer, len) < 0) {MSG("Failed to unexport gpio!"); return -1; } close(fd); return 0; }
4)读写一个节点
static int gpio_read(int pin) {char path[64]; char value_str[3]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_RDONLY); if (fd < 0) {MSG("Failed to open gpio value for reading!\n"); return -1; } if (read(fd, value_str, 3) < 0) {MSG("Failed to read value!\n"); return -1; } close(fd); return (atoi(value_str));} //value: 0-->LOW, 1-->HIGHstatic int gpio_write(int pin, int value) {static const char values_str[] = "01"; char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_WRONLY); if (fd < 0) {MSG("Failed to open gpio value for writing!\n"); return -1; } if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0) {MSG("Failed to write value!\n"); return -1; } close(fd); return 0; }
5) 设置方向
//dir: 0-->IN, 1-->OUTstatic int gpio_direction(int pin, int dir) {static const char dir_str[] = "in\0out"; char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); if (fd < 0) {MSG("Failed to open gpio direction for writing!\n"); return -1; } if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) < 0) {MSG("Failed to set direction!\n"); return -1; } close(fd); return 0; }
6)中断方式设置
// none表示引脚为输入,不是中断引脚// rising表示引脚为中断输入,上升沿触发// falling表示引脚为中断输入,下降沿触发// both表示引脚为中断输入,边沿触发// 0-->none, 1-->rising, 2-->falling, 3-->bothstatic int gpio_edge(int pin, int edge){const char dir_str[] = "none\0rising\0falling\0both"; char ptr;char path[64]; int fd; switch(edge){case 0:ptr = 0;break;case 1:ptr = 5;break;case 2:ptr = 12;break;case 3:ptr = 20;break;default:ptr = 0;} snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin); fd = open(path, O_WRONLY); if (fd < 0) {MSG("Failed to open gpio edge for writing!\n"); return -1; } if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0) {MSG("Failed to set edge!\n"); return -1; } close(fd); return 0; }
7)监控一个gpio中断
如何通过寄存器操作GPIO
首先来看gt对应的寄存器解释
然后就是使用devmem命令来对寄存器进行操作。注意要使用devmem必须打开内核宏CONFIG_DEVMEM。
注:下面都是以sm6350为例
1)打开CONFIG_DEVMEM
CONFIG_DEVMEM=y
控制GPIO1为输出高
devmem 0xf101000 4 0x200devmem 0xf101004 4 0x2
3)控制GPIO1 为输出低
devmem 0xf101000 4 0x200devmem 0xf101004 4 0x0
4)控制GPIO1 为输出上拉和输出下拉
//上拉devmem 0xf101000 4 0x203//下拉devmem 0xf101004 4 0x201
5)控制GPIO1 为输入,同时读取其值
devmem 0xf101000 4 0x0devmem 0xf101004 //读取对应的值,第一位为1 就是高,为0就是低
bg thanks!! ay