Linux 内核 GPIO 用户空间接口

文章目录

  • Linux 内核 GPIO 接口
    • 旧版本方式:sysfs 接口
    • 新版本方式:chardev 接口
  • gpiod 库及其命令行
    • gpiod 库的命令行
    • gpiod 库函数的应用

GPIO(General Purpose Input/Output,通用输入/输出接口),是微控制器或微处理器上的引脚,可以被编程为输入或输出,用于与外部设备进行通信。在 Linux 系统中,通过内核提供的用户空间接口,开发者能够轻松地读取、设置 GPIO 的状态,实现对外部设备的控制和监测。

本文将基于 Orangepi ZERO 2开发板,探讨 Linux 内核(kernel 4.8 版本起)基于字符设备的新接口,用于访问和管理用户空间中的 GPIO 线路。
在这里插入图片描述

Linux 内核 GPIO 接口

在 Linux 系统内部,Linux 内核通过生产者/消费者模型实现对 GPIO 的访问。 有生产 GPIO 线路的驱动程序(GPIO控制器驱动程序)和消耗 GPIO 线路的驱动程序(键盘、触摸屏、传感器等)。

[!IMPORTANT]

生产 GPIO 线路的驱动程序相关链接:GPIO Driver Interface — The Linux Kernel documentation

消耗 GPIO 线路的驱动程序相关链接:GPIO Descriptor Consumer Interface — The Linux Kernel documentation

为了管理 GPIO 注册和分配,Linux 内核中有一个名为 gpiolib 的框架。 该框架为在内核空间和用户空间应用程序中运行的设备驱动程序提供了一个 API。

在这里插入图片描述

旧版本方式:sysfs 接口

在 Linux kernel 4.7 版本之前,管理用户空间中 GPIO 线路的接口一直通过在 /sys/class/gpio 导出的文件在 sysfs 中。 因此,如果想要将某个 GPIO 设置成输出,且让这个 GPIO 输入高电平,整体步骤如下:

  1. 确定GPIO线路的编号;
  2. 将 GPIO 编号写入到 /sys/class/gpio/export
  3. 将 GPIO 线路配置为输出,对应设置的文件为 /sys/class/gpio/gpioX/direction
  4. 将 1 写入到 /sys/class/gpio/gpioX/value,使 GPIO 输出高电平。

以 Orangepi ZERO 2 为例子,要从用户空间设置 GPIO 69 输出高电平,要执行以下命令(root 用户下执行):

echo 69 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio69/direction
echo 1 > /sys/class/gpio/gpio69/value

执行前后效果如下图所示(gpio readall 命令用于查看物理引脚的状态):

在这里插入图片描述

从命令的运行界面来看,效果很好,执行也简单,但还是有一些缺陷:

  1. GPIO 的分配不与任何进程绑定,如果使用 GPIO 的进程结束执行或崩溃,GPIO 可能会继续保持当前状态;
  2. 如果多个进程访问同一 GPIO 线路,并发可能是一个问题;
  3. 写入多个引脚需要对大量文件(export / direction / value等)进行 openreadwriteclose 等操作;
  4. 捕获事件(GPIO 线路的中断)的轮询过程不可靠;
  5. 没有接口来配置 GPIO 线路(开源、开漏等);
  6. 分配给 GPIO 线路的编号不确定。

新版本方式:chardev 接口

从 Linux kernel 4.8 版本开始,GPIO sysfs 接口被弃用,现在有一个基于字符设备的新 API,可以从用户空间访问 GPIO 线路。

每个 GPIO 控制器(gpiochip)在 /dev 中都会有一个字符设备,可以使用文件操作(open、read、write、ioctl、poll、close)来管理 GPIO 行并与之交互,输入 ls /dev/gpiochip*,可以看到 GPIO 的所有字符设备:

在这里插入图片描述

尽管这个新的字符设备接口可以防止使用 echocat 等标准命令行操作 GPIO,但与 sysfs 接口相比,它有一些优点:

  1. GPIO 的分配与正在使用它的进程相关联,从而改进了对用户空间进程使用哪些 GPIO 线路的控制;
  2. 以一次读取或写入多条 GPIO 线路;
  3. 可以按名称找到 GPIO 控制器和 GPIO 线路;
  4. 可以配置引脚的状态(开源、开漏等);
  5. 捕获事件(来自 GPIO 线路的中断)的轮询过程是可靠的。

gpiod 库及其命令行

使用 chardev 接口,可以安装 libgpiod 项目来使用,这是个与 Linux GPIO 字符设备交互的 C 库和工具。

还是以 Orangepi ZERO 2 开发板为例,该板运行的操作系统为 Ubuntu22.04,kernel 版本为 5.16。安装 libgpiod 库和工具的命令如下(如不是在 root 用户下操作,需要命令前加上 sudo 扩充命令的权限):

apt update
apt install libgpiod-dev
apt install gpiod

gpiod 库的命令行

安装好库和工具后,可以使用一些命令来确认是否安装成功。例如,检查可用的 GPIO 芯片:

gpiodetect

Orangepi ZERO 2 开发板的 GPIO 芯片如下图所示,有两个 gpiochip,GPIO 线路分别是 288 和 32。

在这里插入图片描述

[300b000.pinctrl][7022000.pinctrl] 是GPIO芯片的名称或标签,通常与芯片的硬件地址或设备树节点名称相关联。这些名称由内核设备驱动程序指定,用于标识和区分不同的GPIO芯片。

查看 GPIO 芯片的信息命令(以 gpiochip0 为例):

gpioinfo /dev/gpiochip0

这个命令显示的信息很多,line 是GPIO 线的编号(从 0 到 287),后面是 GPIO 线的名称,未命名的线显示为 unnamedunused表示该 GPIO 线目前未被使用,input 表示该 GPIO 线配置为输入模式,output 表示该 GPIO 线配置为输出模式,active-high 表示该 GPIO 线的活动电平为高电平。

在这里插入图片描述

在上图可以看出,有几个 GPIO 引脚被使用,被使用的 GPIO 会被命名为其他的名字,后面还会出 [used] 的字样。

用此前 wiringPi 库的命令 gpio readall 查看当前物理引脚的状态。其中物理引脚 12 号对应的 GPIO 线路号为 75,当前值为 0。

在这里插入图片描述

[!NOTE]

wiringPi 库是开发 Orangepi ZERO 2 开发板应用层程序的中间件,安装教程在我之前的博客《OrangePi ZERO 2 外设应用程序开发之接口与 wiringOP 库》提及。

gpioset 命令可以设置 GPIO 线路,假设现在要改变 75 号 GPIO 的输出状态(输出为 1),具体命令如下:

gpioset 0 75=1

命令中的 0 表示 gpiochip075 为 GPIO 线路号,1 为写入值。

执行后,GPIO 75 的输出值立刻变为 1,相较于 sysfs 接口的调用,方便了非常多。

在这里插入图片描述

gpioget 命令将读取 GPIO 线路的值。例如,读取 GPIO 65 的值,命令如下:

gpioget 0 65

执行结果如下图,表示 GPIO 65 号引脚当前值为 0。

在这里插入图片描述

所有这些命令的源代码都可以在 libgpiod 仓库中找到。

gpiod 库函数的应用

gpiod 库提供了很多 API,可以直接对 GPIO 线路进行操作:

struct gpiod_chip *gpiod_chip_open(const char *path);
struct gpiod_line *gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset);
int gpiod_line_request_input(struct gpiod_line *line, const char *consumer);
int gpiod_line_get_value(struct gpiod_line *line);

下面是 libgpiod 提供的几个函数的解释:

  1. gpiod_chip_open

    • 功能: 打开一个 GPIO 芯片。
    • 参数:
      • const char *path - 设备文件的路径,例如 /dev/gpiochip0
    • 返回值:
      • 成功时返回一个指向 gpiod_chip 结构体的指针。
      • 失败时返回 NULL
    • 用途: 这是使用 GPIO 芯片的第一步,通过指定的路径打开一个 GPIO 芯片。
    struct gpiod_chip *chip;
    chip = gpiod_chip_open("/dev/gpiochip0");
    if (!chip) {perror("gpiod_chip_open");exit(1);
    }
    
  2. gpiod_chip_get_line

    • 功能: 获取 GPIO 芯片上的一条 GPIO 线。
    • 参数:
      • struct gpiod_chip *chip - 一个指向打开的 GPIO 芯片的指针。
      • unsigned int offset - 要获取的 GPIO 线的编号(从 0 开始)。
    • 返回值:
      • 成功时返回一个指向 gpiod_line 结构体的指针。
      • 失败时返回 NULL
    • 用途: 获取特定编号的 GPIO 线,以便对其进行操作。
    struct gpiod_line *line;
    line = gpiod_chip_get_line(chip, 4); // 获取第 4 条 GPIO 线
    if (!line) {perror("gpiod_chip_get_line");gpiod_chip_close(chip);exit(1);
    }
    
  3. gpiod_line_request_input

    • 功能: 请求将 GPIO 线配置为输入模式。
    • 参数:
      • struct gpiod_line *line - 一个指向要配置的 GPIO 线的指针。
      • const char *consumer - 请求者的名称(通常是应用程序的名称,用于调试和日志记录)。
    • 返回值:
      • 成功时返回 0。
      • 失败时返回 -1。
    • 用途: 将指定的 GPIO 线配置为输入模式,以便读取其电平值。
    int ret;
    ret = gpiod_line_request_input(line, "my_consumer");
    if (ret) {perror("gpiod_line_request_input");gpiod_line_release(line);gpiod_chip_close(chip);exit(1);
    }
    
  4. gpiod_line_get_value

    • 功能: 获取 GPIO 线的电平值。
    • 参数:
      • struct gpiod_line *line - 一个指向配置为输入模式的 GPIO 线的指针。
    • 返回值:
      • 成功时返回 0 或 1,分别表示低电平和高电平。
      • 失败时返回 -1。
    • 用途: 读取 GPIO 线的当前电平值。
    int value;
    value = gpiod_line_get_value(line);
    if (value < 0) {perror("gpiod_line_get_value");
    } else {printf("GPIO line value: %d\n", value);
    }
    

总结来说,这几个函数的主要作用是打开 GPIO 芯片、获取 GPIO 线路、将 GPIO 线路配置为输入模式并读取其电平值。通过这些步骤,可以实现对 GPIO 线状态的监测和响应。

以下 C 程序使用 libgpiod 读取 GPIO 70 的例子:

// gpio_line.c#include <stdio.h>
#include <string.h>
#include <gpiod.h>
#include <errno.h>int main()
{struct gpiod_chip *chip;struct gpiod_line *line;int req, value;chip = gpiod_chip_open("/dev/gpiochip0");if (!chip) {perror("Failed to open GPIO chip");return -1;}line = gpiod_chip_get_line(chip, 70);if (!line) {gpiod_chip_close(chip);perror("Failed to get line");return -1;}req = gpiod_line_request_input(line, "gpio_state");if (req) {gpiod_chip_close(chip);fprintf(stderr, "Failed to request line as input: %s\n", strerror(errno));return -1;}value = gpiod_line_get_value(line);if (value < 0) {gpiod_chip_close(chip);fprintf(stderr, "Failed to get line value: %s\n", strerror(errno));return -1;}printf("GPIO value is: %d\n", value);gpiod_chip_close(chip);return 0;
}

编译和运行命令如下:

gcc -o gpio_line gpio_line.c -lgpiod
./gpio_line

运行结果如下:

在这里插入图片描述

新的 Linux 内核 GPIO 用户空间接口是一个非常简单、优雅和健壮的 API,从现在开始应该用在嵌入式Linux开发上吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/41157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MAX()和ROW_NUMBER()函数的对比

SQL 查询中,使用 MAX() 函数和使用窗口函数 ROW_NUMBER() 都可以实现获取每个分组中某个列的最大值,但它们的实现方式和性能表现有所不同。以下是两者的区别和性能对比: 使用 MAX() 函数 SELECTMAX(d.times) FROMv_y d WHEREd.id = a.idAND d.name = a.nameAND d.age = a.…

交换机需要多大 buffer(续:更一般的原理)

前面用 aimd 系统分析了交换机 buffer 需求量随流数量增加而减少&#xff0c;今天从更一般的角度继续分析这事。 将交换机建模为一个 m/m/1 排队系统&#xff0c;多流场景下它就会变成一个 m/g/1 排队系统&#xff0c;而这事比前面的 aimd 系统分析更容易推导。 m/m/1 系统中…

哪里还可以申请免费一年期的SSL证书?

目前&#xff0c;要申请免费一年期的SSL证书&#xff0c;选项较为有限&#xff0c;因为多数供应商已转向提供短期的免费证书&#xff0c;通常有效期为90天。不过&#xff0c;有一个例外是JoySSL&#xff0c;它仍然提供一年期的免费SSL证书&#xff0c;但是只针对教育版和政务版…

halcon学习

halcon列程详细介绍-V1.3 从文件夹中遍历图片(用到的算子及实例) 1)list_files(::Directory,Options:Files) 功能:列出目录中的所有文件 参数列表: 第1个参数Directory为输入变量,需要列出的目录名字,即输入目录地址; 第2个参数Options为输入变量,默认值为files,建…

html三级菜单

示例 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>Menu Example</title> <link re…

mybatispuls 分页插件的基本原理是什么?

MyBatis-Plus 是一个基于 MyBatis 的增强框架,它提供了许多额外的功能,其中分页插件是一个常用的功能。分页插件的基本原理是拦截 SQL 语句,在执行查询之前对 SQL 进行修改,以实现分页的功能。以下是 MyBatis-Plus 分页插件的基本原理及其工作机制: 1. 基本原理 分页插件…

LED显示屏跟COB显示屏有哪些不同?

COB显示屏跟LED显示屏的主要区别在于产品的显示效果、封装技术、耐用性、防护力、维护以及制造成本方面的不同&#xff0c;这里所说的LED显示屏主要指的是使用SMD封装的LED显示屏&#xff0c;今天跟随COB显示屏厂家中品瑞科技一起来详细看看具体分析&#xff1a; 一、封装技术 …

品牌推广的深层逻辑:自我提升与市场认同的和谐共生

品牌推广的深层逻辑&#xff1a;自我提升与市场认同的和谐共生 著名飞行员查尔斯林德伯格(Charles Lindbergh) 曾写道:“改善生活方式比传播生活方式更重要。如果我们自己的生活方式使别人感到满意&#xff0c;那么它将自动蔓延。如果不是这样&#xff0c;那么任何武力都不可能…

如何在 Odoo 16 中继承和更新现有邮件模板

在本文中,让我们看看如何在 Odoo 16 中继承和编辑现有邮件模板。我们必须这样做才能对现有模板的内容进行任何调整或更新。让我们考虑一个在会计模块中更新邮件模板的示例。 单击“account.move”模型中的“发送并打印”按钮后,将打开上述向导。在这里,我们将进行更改。从…

8人团队历时半年打造开源版GPT-4o,零延迟演示引爆全网!人人可免费使用!

目录 01 Moshi 02 背后技术揭秘 GPT-4o可能要等到今年秋季才会公开。 然而&#xff0c;由法国8人团队开发的原生多模态Moshi&#xff0c;已经达到了接近GPT-4o的水平&#xff0c;现场演示几乎没有延迟&#xff0c;吸引了大量AI专家的关注。 令人惊讶的是&#xff0c;开源版的…

Python酷库之旅-第三方库Pandas(003)

目录 一、用法精讲 4、pandas.read_csv函数 4-1、语法 4-2、参数 4-3、功能 4-4、返回值 4-5、说明 4-6、用法 4-6-1、创建csv文件 4-6-2、代码示例 4-6-3、结果输出 二、推荐阅读 1、Python筑基之旅 2、Python函数之旅 3、Python算法之旅 4、Python魔法之旅 …

T100-XG查询报表的开发

制作XG报表 1、注册程序 azzi900 首先现将程序注册一下,在内部构建基础代码档。 2、注册作业 azzi910 也是直接新增一个,作业跟程序绑定一下。 3、T100签出规格程序 这个时候应该是没签出的,首先将规格迁出。 4、T100画面产生器 规格迁出之后,这个时候还需要生成一个画…

springcloud-gateway 网关组件中文文档

Spring Cloud网关 Greenwich SR5 该项目提供了一个基于Spring生态系统的API网关&#xff0c;其中包括&#xff1a;Spring 5&#xff0c;Spring Boot 2和项目Reactor。Spring Cloud网关的目的是提供一种简单而有效的方法来路由到API&#xff0c;并向它们提供跨领域的关注&#x…

Java中的数据脱敏与隐私保护技术

Java中的数据脱敏与隐私保护技术 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 随着信息化进程的加深&#xff0c;数据安全和隐私保护越来越受到关注。数据脱…

Python文件读入操作

本套课在线学习视频&#xff08;网盘地址&#xff0c;保存到网盘即可免费观看&#xff09;&#xff1a; ​​https://pan.quark.cn/s/e2ba7867f034​​ Python编程中&#xff0c;文件操作是一项基础且重要的技能。本文将详细介绍如何使用Python进行文件的打开、读取、写入和关…

配置基于不同IP地址的虚拟主机

定义配置文件vhost.conf <directory /www> allowoverride none require all granted </directory> <virtualhost 192.168.209.136:80> documentroot /www servername 192.168.209.136 </virtualhost><virtualhost 192.168.209.138:80> document…

Restore Equipment

Restore Equipment 魔兽世界 - 盗号申请 - 恢复装备流程 魔兽和网易真的不行啊 1&#xff09;这个装备本来就是兑换的竟然可以卖NPC 2&#xff09;针对这个情况竟然无法挽回 3&#xff09;设计理念真的不得不吐槽一下 4&#xff09;策划真的不咋样&#xff0c;要是有机会我要自…

【C++】 解决 C++ 语言报错:Stack Overflow

文章目录 引言 栈溢出&#xff08;Stack Overflow&#xff09;是 C 编程中常见且严重的错误之一。栈溢出通常发生在程序递归调用过深或分配过大的局部变量时&#xff0c;导致栈空间耗尽。栈溢出不仅会导致程序崩溃&#xff0c;还可能引发不可预测的行为。本文将深入探讨栈溢出…

Linux系统安装青龙面板结合内网穿透实现使用公网地址远程访问

文章目录 前言一、前期准备本教程环境为&#xff1a;Centos7&#xff0c;可以跑Docker的系统都可以使用。本教程使用Docker部署青龙&#xff0c;如何安装Docker详见&#xff1a; 二、安装青龙面板三、映射本地部署的青龙面板至公网四、使用固定公网地址访问本地部署的青龙面板 …

【带你全面了解 RAG,深入探讨其核心范式、关键技术及未来趋势】

文末有福利&#xff01; 大型语言模型&#xff08;LLMs&#xff09;已经成为我们生活和工作的一部分&#xff0c;它们以惊人的多功能性和智能化改变了我们与信息的互动方式。 然而&#xff0c;尽管它们的能力令人印象深刻&#xff0c;但它们并非无懈可击。这些模型可能会产生…