GPIOD使用

GPIOD简介

自Linux 4.8起,GPIO sysfs接口已被弃用。用户空间应改用libgpiod来与GPIO字符设备进行交互。

libgpiod是Linux GPIO字符设备(/dev/gpiochipX)的C库和工具集,提供了现代化的GPIO操作接口。

主要特点

  • 简单易用:libgpiod提供了简洁的API,使得控制和操作GPIO设备变得简单易懂。开发者只需了解基本的GPIO概念和函数接口即可使用。
  • 独立性:libgpiod是一个独立的用户空间库,不依赖于任何特定的硬件平台或芯片。它适用于多种支持GPIO控制的嵌入式平台,如Radxa ROCK系列、树莓派、BeagleBone等。
  • 支持多种编程语言:libgpiod原生支持C语言,同时也提供了Python绑定(python3-libgpiod)和其他语言的封装,使得在不同的编程语言下都可以方便地使用。
  • 高效的事件监听:libgpiod提供了用于异步事件监听的功能,例如等待GPIO状态变化等。这使得开发者可以实现高效的事件驱动应用程序。
  • GPIO 规格支持:libgpiod提供了对不同GPIO规格和编号方式的支持,包括基于GPIO编号和基于物理引脚编号两种方式。

安装libgpiod

安装命令行工具

sudo apt update
sudo apt install gpiod -y

安装开发库(用于C编程)

sudo apt install libgpiod-dev -y

安装Python绑定

sudo apt install python3-libgpiod -y

验证安装

# 查看版本(Quectel Pi H1使用2.2.1版本)
apt list --installed | grep gpiod

# 查看可用的GPIO芯片
gpiodetect

注意:Quectel Pi H1使用libgpiod 2.2.1,语法与1.x版本不兼容。

命令行工具

libgpiod提供了命令行工具,用于查看和控制GPIO设备。

前提条件:确保已安装gpiod工具包(sudo apt install gpiod -y

gpiodetect

列出系统中所有GPIO控制器:

gpiodetect

输出示例:

gpiochip0 [gpio0] (32 lines)
gpiochip1 [gpio1] (32 lines)
gpiochip2 [gpio2] (32 lines)
gpiochip3 [gpio3] (32 lines)
gpiochip4 [gpio4] (128 lines)

提示:Quectel Pi H1主要使用gpiochip4

gpioinfo

显示GPIO设备信息:

# 查看所有GPIO芯片的信息
gpioinfo

# 查看特定芯片的信息(使用grep过滤)
# 注意:Quectel Pi H1的gpiochip4有176条线路,根据需要调整数字
gpioinfo | grep -A 180 "gpiochip4"

libgpiod 版本差异

  • 1.x 版本:支持gpioinfo /dev/gpiochip4语法
  • 2.x 版本:只支持gpioinfo查看所有,需配合grep过滤特定芯片

输出示例(Quectel Pi H1实际输出):

gpiochip4 - 176 lines:
        line   0:       unnamed                 input
        line   1:       unnamed                 input
        line   2:       unnamed                 output active-low consumer=perst
        ...
        line  36:       unnamed                 output
        line  37:       unnamed                 input
        ...
        line  77:       unnamed                 input
        ...
        line  91:       unnamed                 input active-low consumer=cd
        ...

字段说明:

  • unnamed:引脚未命名(Quectel Pi H1的默认状态)
  • input/output:引脚方向
  • consumer=xxx:引脚被某个功能占用(如consumer=perstconsumer=cd
  • active-low:低电平有效

注意

  • Quectel Pi H1的GPIO引脚默认为unnamed(未命名)
  • consumer=标记的引脚正在被其他功能使用,无法直接作为GPIO使用
  • gpiochip4有176条线路

gpiofind(已移除)

重要提示gpiofind命令在libgpiod 2.x版本中已被移除。

Quectel Pi H1使用libgpiod 2.x,所有GPIO引脚默认为unnamed(未命名),需要直接使用芯片名和引脚编号进行操作。

查看引脚信息:

# 查看特定引脚的详细信息
gpioinfo | grep "line  77"

# 查看某个范围的引脚
gpioinfo | grep -E "line  (77|78|79)"

gpioget

读取GPIO输入:

# 读取gpiochip4的第77号引脚(必须使用-c选项指定芯片)
gpioget -c gpiochip4 77

# 也可以使用芯片编号
gpioget -c 4 77

# 或使用完整路径
gpioget -c /dev/gpiochip4 77

输出示例(libgpiod 2.x):

"77"=inactive
  • inactive表示低电平(0)
  • active表示高电平(1)

如果需要数字格式输出:

# 使用--numeric选项输出0/1
gpioget -c gpiochip4 --numeric 77

gpioset

设置GPIO输出:

重要提示(libgpiod 2.x)

  • 默认情况下,gpioset会持续保持设置的电平,直到程序被终止(Ctrl+C)
  • 程序退出后,GPIO状态由硬件决定,不保证保持
  • 必须使用-c选项指定芯片

基本用法(持续保持状态):

# 设置GPIO77为高电平(持续保持,按Ctrl+C停止)
gpioset -c gpiochip4 77=1

# 设置为低电平
gpioset -c gpiochip4 77=0

# 也可以使用active/inactive
gpioset -c gpiochip4 77=active
gpioset -c gpiochip4 77=inactive

# 或使用on/off
gpioset -c gpiochip4 77=on
gpioset -c gpiochip4 77=off

设置多个引脚:

# 同时设置多个引脚
gpioset -c gpiochip4 16=1 17=0

设置后延迟退出:

# 设置高电平并保持5秒后退出
gpioset -c gpiochip4 -p 5s 77=1

# 保持100毫秒后退出
gpioset -c gpiochip4 -p 100ms 77=1

后台运行(守护进程模式):

# 设置后在后台运行
gpioset -c gpiochip4 -z 77=1

gpiomon

监控GPIO事件:

# 基本用法:监控GPIO77的状态变化(默认监控双边沿)
gpiomon -c gpiochip4 77

# 指定监控的边沿类型
gpiomon -c gpiochip4 -e rising 77     # 只监控上升沿
gpiomon -c gpiochip4 -e falling 77    # 只监控下降沿
gpiomon -c gpiochip4 -e both 77       # 监控双边沿(默认)

# 显示横幅信息
gpiomon -c gpiochip4 --banner 77

# 限制事件数量(监控10个事件后退出)
gpiomon -c gpiochip4 -n 10 77

# 设置空闲超时(5秒内无事件则退出)
gpiomon -c gpiochip4 --idle-timeout 5s 77

# 添加防抖(10ms防抖周期)
gpiomon -c gpiochip4 -p 10ms 77

使用示例:

  1. 运行gpiomon -c gpiochip4 77
  2. 用杜邦线将Pin7 (GPIO77) 连接到GND或3.3V
  3. 观察终端输出的事件信息
  4. 按Ctrl+C停止监控

输出示例(libgpiod 2.x):

event:  RISING EDGE offset: 77 timestamp: [    1234.567890123]
event: FALLING EDGE offset: 77 timestamp: [    1234.678901234]

自定义输出格式:

# 使用格式化输出
gpiomon -c gpiochip4 --format "Line %o: %E edge at %S" 77

# 输出示例:
# Line 77: rising edge at 1234.567890123
# Line 77: falling edge at 1234.678901234

GPIO引脚映射

Quectel Pi H1主要使用/dev/gpiochip4进行GPIO控制。

40Pin常用引脚映射

物理引脚 引脚名称 GPIO编号 GPIO芯片 libgpiod使用 默认功能
Pin3 NFC_I2C_SDA GPIO36 gpiochip4 gpiochip4 36 I2C09_SDA
Pin5 NFC_I2C_SCL GPIO37 gpiochip4 gpiochip4 37 I2C09_SCL
Pin7 CAM2_RST GPIO77 gpiochip4 gpiochip4 77 GPIO
Pin11 GPIO_16 GPIO16 gpiochip4 gpiochip4 16 GPIO/SPI/UART/I2C
Pin13 GPIO_17 GPIO17 gpiochip4 gpiochip4 17 GPIO/SPI/UART/I2C

注意:Pin3和Pin5默认配置为I2C9接口,如需作为GPIO使用,请确保没有其他设备占用。

完整的引脚映射请参考:40Pin扩展

查看引脚状态

使用gpioinfo查看引脚的当前状态:

# 查看gpiochip4的所有引脚(使用grep过滤)
gpioinfo | grep -A 180 "gpiochip4"

# 查看特定引脚(例如GPIO77)
gpioinfo | grep "line  77"

# 查看所有已占用的引脚
gpioinfo | grep "consumer="

常见问题

命令未找到

问题:bash: gpiodetect: command not found

原因:
libgpiod工具包未安装

解决方法:

# 安装gpiod工具包
sudo apt update
sudo apt install gpiod -y

# 验证安装
gpiodetect

注意:libgpiod 2.x版本中没有gpiofind命令,这是正常的。

权限问题

问题:Permission denied

error: unable to request line 77: Permission denied

解决方法:

使用sudo运行命令:

sudo gpioget -c gpiochip4 77
sudo gpioset -c gpiochip4 77=1

引脚占用问题

问题:Device or resource busy

error: unable to request line 36: Device or resource busy

原因:

  • 引脚被其他进程占用(如I2C、SPI等)
  • 引脚已被系统功能使用

解决方法:

  1. 检查引脚状态:
gpioinfo | grep "line  36"
  1. 如果引脚已被占用,输出结果会通过consumer=显示占用者信息:
line  36:       unnamed                 output consumer=i2c-9
  1. 选择未被占用的引脚(输出中显示为unused

引脚编号错误

问题:cannot find line

gpioget: cannot find line '200'

原因:
引脚编号超出范围或引脚不存在

解决方法:

确认Quectel Pi H1的引脚范围:

  • gpiochip4:0-175(共176条线路)
  • 使用gpioinfo查看:gpioinfo | grep -A 180 "gpiochip4"

libgpiod版本问题

问题:不同版本的API和命令行工具差异

libgpiod在不同版本中有显著变化。Quectel Pi H1使用的是libgpiod 2.2.1

检查版本:

apt list --installed | grep gpiod
# 或
gpiodetect --version

主要版本差异:

功能 libgpiod 1.x libgpiod 2.x (Quectel Pi H1)
基本语法 gpioget gpiochip4 77 gpioget -c gpiochip4 77
芯片指定 位置参数 必须使用-c选项
gpioinfo gpioinfo /dev/gpiochip4 gpioinfo | grep -A 180 "gpiochip4"
gpioset默认行为 立即退出 持续保持(需 Ctrl+C)
gpioset持久模式 gpioset -m signal 默认持久(无需参数)
输出格式 0 / 1 "77"=inactive / "77"=active
gpiofind 支持 已移除
gpiochip4线路数 128(示例) 176(Quectel Pi H1)
GPIO命名 可能已命名 Quectel Pi H1全部unnamed
C API 旧API 新API(不兼容)
Python API 旧API 新API(不兼容)

关键变化总结:

  • ✅ 所有命令必须使用-c <chip>选项指定芯片
  • gpioset默认持续保持状态,不再立即退出
  • ✅ 输出格式改为"line"=active/inactive
  • gpiofind命令已移除
  • ❌ 不再支持位置参数方式指定芯片

调试技巧

常用调试命令

# 1. 查看所有GPIO芯片
gpiodetect

# 2. 查看gpiochip4的所有引脚信息
gpioinfo | grep -A 180 "gpiochip4"

# 3. 查看被占用的引脚
gpioinfo | grep "consumer="

# 4. 查看特定引脚状态
gpioinfo | grep "line  77"

# 5. 读取引脚值
gpioget -c gpiochip4 77

# 6. 设置引脚值(持续保持)
gpioset -c gpiochip4 77=1

# 7. 监控引脚事件
gpiomon -c gpiochip4 77

与sysfs的对比

特性 sysfs(已弃用) libgpiod
接口路径 /sys/class/gpio/ /dev/gpiochipX
导出引脚 需要手动export 自动管理
资源管理 手动unexport 自动释放
并发访问 容易冲突 更好的资源管理
性能 较慢(文件操作) 更快(ioctl)
事件监听 支持 更好的支持
维护状态 已弃用 活跃维护

建议:新项目应使用libgpiod而不是已弃用的sysfs接口。

参考资源