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 接口。

参考资源