GPIO子系统

http://blog.rongpmcu.com/gpiozi-xi-tong-he-pinctrlzi-xi-tong/#

GPIO算是一种设备,有设备那我们就要对这个设备进行一个抽象,同时为了各种各样的GPIO设备会去抽象出一个gpio的核心层gpiolib.c,用于管理各种各种各样的gpio,
(话外:感觉内核对于设备的管理最精髓的就是核心层总线和driver,device分开,device,driver只需要向核心层去注册就好,核心层会去管理他们)
内核抽象的设备结构体就是:gpio_chip
gpio driver的工作就是去初始化实现这个结构体,然后注册这个结构体,此时gpio就可以工作了。
从层次来分,内核的gpio接口有两层,一层是提供给bsp用于实现gpio功能的,一层是提供给其他驱动去在内核态使用gpio的
如何使用gpio:
1.内核态:

使用gpio lib中提供的gpio子系统接口
gpio_request(30, "j15"); 申请该gpio
gpio_direction_input(30);置方向输入
gpio_get_value(20);输入模式下获取电平状态
gpio_direction_output(30);方向输出
gpio_set_value(20,0);输出模式下置高
gpio_set_value(20,1);输出模式下置低
gpio_free(20);释放gpio资源

上述就是一个完整的在内核中如果想操作一个gpio的流程
上述操作是基于内核的标准gpio子系统而注册gpiodriver后才可以使用,其他各种不标准的做法不可以使用上述即下述的操作

2.用户态:
http://blog.csdn.net/xgbing/article/details/51009384
http://blog.chinaunix.net/uid-27875-id-3979149.html
(1).将GPIO通过sysfs导出到用户空间
要想在用户空间访问GPIO,首先需要在sysfs中使能GPIO支持。

 Device Drivers  --->
            [*] GPIO Support  ---> 
                    [*]   /sys/class/gpio/... (sysfs interface)

配置后gpiolib_sysfs.c才可以支持编译。
此时系统会有目录/sys/class/gpio这个文件夹出现

cd /sys/class/gpio
ls
export      gpiochip0   gpiochip32  gpiochip64  gpiochip96  unexport
或者使用:for i in gpiochip* ; do echo `cat $i/label`: `cat $i/base` ; done
/soc/gpio@18000100: 0
/soc/gpio@18000120: 32
/soc/gpio@18000140: 64
/soc/gpio@18000160: 96
这个表示目前系统中有4组gpio,index从0开始一直到96+32 = 127
此时若要操作某个gpio,现将其导出
echo 139 >/sys/class/gpio/export
export_store: invalid GPIO 139
sh: write error: Invalid argument //因为139号引脚不存在,所以报错
echo 26 >/sys/class/gpio/export //没有报错
ls
export      gpio26      gpiochip0   gpiochip32  gpiochip64  gpiochip96  unexport//此时已经有gpio26被导出在sysfs空间了
cd gpio26  //进入gpio发现会有这么多它的属性,此时我们可以cat这些属性查询他们的default状态
# ls
active_low  direction   power       uevent
device      edge        subsystem   value
我们对gpio26的direction属性做操作
echo out > /sys/class/gpio/gpio26/direction //置为输出状态
echo 1 > /sys/class/gpio/gpio26/value       //设置为高电平
# cat value                                 //查看设置成功
1
echo 26 > /sys/class/gpio/unexport          //取消导出
s
export      gpiochip0   gpiochip32  gpiochip64  gpiochip96  unexport  //此时已经看不到 gpio26 这个文件了,表示取消成功
上述我们看到要操作一个gpio的时候可以要使用echo 26 >/sys/class/gpio/export才可以导出gpio26这个文件,其实也可以预先让其默认让其导出,
在内核代码中当使用gpio_export()函数去使能:
gpio_request(26, "ACS5K CAN Control");
gpio_direction_output(26, 1); /* Default CAN_RESET high */
gpio_export(26, 0); /* export CAN_RESET as output only */0表示该gpio口的方向不能在用户空间通过sysfs来进行改变,1表示可以改变
static inline int gpio_export(unsigned gpio, bool direction_may_change)
函数原型static inline int gpio_export(unsigned gpio, bool direction_may_change)
gpio_export()的调用一定是要在request之后才可以,调用后,/sys/class/gpio/目录下就默认有gpio26这个目录了,
(2)将driver支持普通字符设备的file_operation操作,创建dev目录下节点,提供ioctl接口

gpio的中断是如何使用的?
gpio的中断是需要gpio的driver去支持的,当driver中注册了gpio的中断后,同时选中gpio的sysfs后就可以在/sys/class/gpio/gpio26目录下看到edge这个节点了
1.内核态:

2.用户态:
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转换为中断引脚的方式

用户态使用gpio监听中断     
首先需要将该gpio配置为中断

echo  "rising" > /sys/class/gpio/gpio12/edge      
以下是伪代码
int gpio_id;
struct pollfd fds[1];

gpio_fd = open("/sys/class/gpio/gpio12/value",O_RDONLY);
if( gpio_fd == -1 )
   err_print("gpio open");
fds[0].fd = gpio_fd;
fds[0].events  = POLLPRI;
ret = read(gpio_fd,buff,10);
if( ret == -1 )
    err_print("read");
while(1){
     ret = poll(fds,1,-1);
     if( ret == -1 )
         err_print("poll");
       if( fds[0].revents & POLLPRI){
           ret = lseek(gpio_fd,0,SEEK_SET);
           if( ret == -1 )
               err_print("lseek");
           ret = read(gpio_fd,buff,10);
           if( ret == -1 )
               err_print("read");
            /*此时表示已经监听到中断触发了,该干事了*/
            ...............
    }
}

记住使用poll()函数,设置事件监听类型为POLLPRI和POLLERR在poll()返回后,使用lseek()移动到文件开头读取新的值或者关闭它再重新打开读取新值。必须这样做否则poll函数会总是返回。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值