注:所有文章基于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/direction
cat  /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-->HIGH
static 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-->OUT
static 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-->both

static 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
  1. 控制GPIO1为输出高
devmem 0xf101000 4 0x200
devmem 0xf101004 4 0x2

3)控制GPIO1 为输出低

devmem 0xf101000 4 0x200
devmem 0xf101004 4 0x0

4)控制GPIO1 为输出上拉和输出下拉

//上拉
devmem 0xf101000 4 0x203
//下拉
devmem 0xf101004 4 0x201

5)控制GPIO1 为输入,同时读取其值

devmem 0xf101000 4 0x0
devmem 0xf101004 //读取对应的值,第一位为1 就是高,为0就是低
		                                                           bg  thanks!! ay
Logo

更多推荐