13-Linux-gpio-system

本文介绍了Linux系统中GPIO资源的基本概念及使用方法,详细说明了内核和用户空间如何操作GPIO,包括端口申请、配置方向、读写值等,并提供了监听GPIO中断的用户态示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于gpio的应用其实会在很多地方,最常用的就是led和key,我们也可以使用类似单片机的写法,去直接读写寄存器来控制,没有文件的体现,但这样总感觉不够Linux,所以我们还是要使用linux已有的一些设备节点来实现。

一 概述

Linux内核中gpio是最简单,最常用的资源(和 interrupt ,dma,timer一样)驱动程序,应用程序都能够通过相应的接口使用gpio,gpio使用0~MAX_INT之间的整数标识,不能使用负数,gpio与硬件体系密切相关的,不过linux有一个框架处理gpio,能够使用统一的接口来操作gpio.在讲gpio核心(gpiolib.c)之前先来看看gpio是怎么使用的

二 内核中gpio的使用

1 测试gpio端口是否合法 int gpio_is_valid(int number);

2 申请某个gpio端口当然在申请之前需要显示的配置该gpio端口的pinmux

int gpio_request(unsigned gpio, const char *label)

3 标记gpio的使用方向包括输入还是输出

/*成功返回零失败返回负的错误值*/ 

int gpio_direction_input(unsigned gpio); 

int gpio_direction_output(unsigned gpio, int value); 

4 获得gpio引脚的值和设置gpio引脚的值(对于输出)

int gpio_get_value(unsigned gpio);

void gpio_set_value(unsigned gpio, int value); 

5 gpio当作中断口使用

int gpio_to_irq(unsigned gpio); 

返回的值即中断编号可以传给request_irq()和free_irq()

内核通过调用该函数将gpio端口转换为中断,在用户空间也有类似方法

6 导出gpio端口到用户空间

int gpio_export(unsigned gpio, bool direction_may_change); 

内核可以对已经被gpio_request()申请的gpio端口的导出进行明确的管理,

参数direction_may_change表示用户程序是否允许修改gpio的方向,假如可以

则参数direction_may_change为真

/* 撤销GPIO的导出 */

void gpio_unexport(); 
三 用户空间gpio的调用

用户空间访问gpio,即通过sysfs接口访问gpio,下面是/sys/class/gpio目录下的三种文件:

  • export/unexport文件
  • gpioN指代具体的gpio引脚
  • gpio_chipN指代gpio控制器

必须知道以上接口没有标准device文件和它们的链接。

1.export/unexport文件接口:

/sys/class/gpio/export,该接口只能写不能读

用户程序通过写入gpio的编号来向内核申请将某个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端口,里边有如下属性文件

root@zihome:/sys/class/gpio# ls
export      gpio16      gpiochip0   gpiochip64
gpio13      gpio17      gpiochip32  unexport
2.1 direction

表示gpio端口的方向,读取结果是in或out。该文件也可以写,写入out 时该gpio设为输出同时电平默认为低。写入low或high则不仅可以

设置为输出 还可以设置输出的电平。 当然如果内核不支持或者内核代码不愿意,将不会存在这个属性,比如内核调用了gpio_export(N,0)就

表示内核不愿意修改gpio端口方向属性

2.2 value

表示gpio引脚的电平,0(低电平)1(高电平),如果gpio被配置为输出,这个值是可写的,记住任何非零的值都将输出高电平,如果某个引脚能并且已经被配置为中断,则可以调用poll(2)函数监听该中断,中断触发后poll(2)函数就会返回。

root@zihome:/sys/devices/virtual/gpio/gpio13# cat value 
1
root@zihome:/sys/devices/virtual/gpio/gpio13# echo 0 > value 
root@zihome:/sys/devices/virtual/gpio/gpio13# cat value 
0
2.3 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)
四 用户态使用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函数会总是返回。

https://www.cnblogs.com/dirt2/p/5890649.html

https://blog.youkuaiyun.com/jklinux/article/details/78645106

### Linux Kernel 4.9 PCA953X GPIO Driver Implementation Details In the context of Linux kernel version 4.9, the PCA953X GPIO driver is designed to manage and control devices that use the PCA953X series of I/O expanders from NXP Semiconductors[^1]. These chips provide additional general-purpose input/output (GPIO) lines through an I²C interface. The driver initializes by registering itself with the platform bus using `platform_driver_register` function call. This allows it to be probed when a matching device appears on the system: ```c static struct platform_driver pca953x_driver = { .probe = pca953x_probe, .remove = pca953x_remove, .driver = { .name = "pca953x", .of_match_table = of_match_ptr(pca953x_of_match), }, }; module_platform_driver(pca953x_driver); ``` During initialization (`pca953x_probe`), several key operations occur including setting up interrupt handling mechanisms if interrupts are supported by hardware configuration. The driver also configures pin directions based on predefined settings or runtime configurations provided via Device Tree overlays or other means. For controlling individual pins as inputs or outputs, userspace applications interact with this driver primarily through standard sysfs interfaces available under `/sys/class/gpio`. Operations such as reading current state, writing new values, configuring directionality can all be performed here without needing direct access to low-level registers within the chip itself. Additionally, support exists for polling mode operation where changes detected at any configured line trigger events reported back into user space asynchronously. Such functionality enhances responsiveness while reducing CPU usage compared to continuous polling loops implemented entirely in application code. Finally, error conditions encountered during normal operation—such as communication failures over I²C—are handled gracefully ensuring stability even under adverse circumstances.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Creator_Ly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值