Linux gpiod(GPIO Character Device Interface)的支持是在Linux内核4.8版本中正式引入的,当前M300的SDK已经适配了Linux5.10以及Linux6.6版本,所以之后的两个版本都是支持gpiod。
这一更新标志着GPIO的用户空间操作接口从旧的sysfs方式,向更便捷,更安全的字符设备方式转变;实测gpiod方式操作gpio的效率介于devmem用户态映射和sysfs之间,如果指望使用gpiod实现某些高速功能,可能是不太现实的,但是gpiod所提供的工具命令,在我们调试gpio过程中,能够直观展示gpio的使用状况和很便捷的操作方式,避免了sysfs的繁杂操作。
为了适应排版,本文对原始文章进行了版面重排。
查看设备目录/dev/下是否有gpiochip字符设备:

系统是否支持gpiod
系统下使用gpiod需要有相关库和执行命令的支持,可以在系统下执行gpio并使用tab补全,查看是否支持,如下:

并执行gpioinfo命令,查看libgpiod是否支持。

如果通过以上测试,并不能正常使用gpiod。就需要进行对应的内核以及文件系统的配置。

在SDK根目录下运行make buildroot-menuconfig,在Target packages → Libraries → Hardware handling中:

勾选libgpiod和install tools,选择完成后,编译烧录开发板。
gpiod的使用方式
gpiod的使用方式,主要包含两种。一种是使用gpiod相关tools,在系统下进行调试验证等工作;还有就是基于libgpiod编程,使用libgpiod提供的相关C接口,可用于在用户程序中进行低速的gpio操作,也可以基于它开发I2C、SPI、MDIO等低速接口。
如果使用python开发,也可以安装python3-libgpiod,同样可以实现基于python的命令和程序开发。
gpiod tools的使用
gpiod tools一共支持以下几种:
gpiodetect gpiofind gpioget gpioinfo gpiomon gpioset由于接触的使用场景有限,仅做个人经验分享。
gpiodetect简介
此工具的功能是列出所有的gpio芯片,无论是SOC内部的gpio还是通过其它方式拓展的gpio;例如在M300上执行此命令,可以看到一共支持5组gpio。

而在ubuntu桌面主机上,安装gpiod的支持并插入cp2112这类USB转gpio、i2c等芯片,执行可以看到:
root@cduguobin-VMware-Virtual-Platform:/# gpiodetectgpiochip0 [cp2112_gpio] (8 lines)
它对外挂的gpio芯片也能完美支持。
gpioinfo简介
查看指定芯片的所有引脚,可以直接执行,也可以带参数执行。
直接执行会将所有的gpio芯片信息dump出来,参数为gpiodetect中探测到的gpio芯片索引如下:

将该芯片下所有的gpio信息全部展示出来,包含输入输出状态,有无驱动注册,也能在此体现出来。
gpioset简介
用于设置gpio的值,根据帮助说明,此工具有很多功能的支持,但是更多受限于gpio芯片的设计以及驱动的支持。我们常用的功能还是一些基础的拉高拉低等操作。
例如需要设置一个gpio输出高:

也可以设置同一组gpio芯片的多个gpio:

还有一些高级操作,具体使用还需看帮助手册:
gpioset --mode=time --sec=1 1 0=1 #设置为高电平,并持续1秒gpioset 1 0=1 #立即设置为低
gpioget简介
见名知意,即为获取gpio线的状态:

gpiomon简介
这个功能没用过,介绍说的是可以监控gpio的事件,如边沿事件等,在测试场景用的较少。需要用的时候在研究。
C语言编程接口
gpiolib提供的相关接口都在gpiod.h头文件中定义,使用时需要#include <gpiod.h>包含这个头文件。并在编译时-lgpiod库文件。以下是AI写的一个简单例程,gpiod.h中包含的功能很多,这里只能抛砖引玉,使用的时候再仔细研究。
#include<gpiod.h>#include<stdio.h>#include<unistd.h>intmain(void){const char *chipname = "gpiochip0";struct gpiod_chip *chip;struct gpiod_line *line;int ret, val;// 打开GPIO芯片chip = gpiod_chip_open_by_name(chipname);if (!chip) {perror("Open chip failed");return 1;}// 获取GPIO线(引脚17)line = gpiod_chip_get_line(chip, 17);if (!line) {perror("Get line failed");gpiod_chip_close(chip);return 1;}// 配置为输入模式ret = gpiod_line_request_input(line, "example");if (ret < 0) {perror("Request line as input failed");gpiod_line_release(line);gpiod_chip_close(chip);return 1;}// 读取引脚值val = gpiod_line_get_value(line);printf("GPIO 17 value: %d\n", val);// 配置为输出模式ret = gpiod_line_request_output(line, "example", 0);if (ret < 0) {perror("Request line as output failed");gpiod_line_release(line);gpiod_chip_close(chip);return 1;}// 设置引脚值gpiod_line_set_value(line, 1);sleep(1);gpiod_line_set_value(line, 0);// 监控事件struct gpiod_line_request_config config = {.consumer = "example",.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES,};ret = gpiod_line_request(line, &config, 0);if (ret < 0) {perror("Request event failed");} else {struct gpiod_line_event event;ret = gpiod_line_event_wait(line, NULL);if (ret > 0) {ret = gpiod_line_event_read(line, &event);printf("Event type: %d\n", event.event_type);}}// 清理资源gpiod_line_release(line);gpiod_chip_close(chip);return 0;}
总结
和传统的sysfs接口相比,gpiod的方式明显更直观和更高效。解决了sysfs接口的目录层级太多,且都需要以字符串的方式进行操作。而且提供了libgpiod的库,让用户实现一些基础的gpio功能,也不用再去研究数据手册中的gpio寄存器,可以更安全的操作gpio。
尾声
作者原始链接:https://ima.qq.com/note/share/_AwZNLSM8gqfLZoXbl5lNA?channel=4