libgpiod C++ 2.1.x请求GPIO线路报错:设备或资源忙
问题:libgpiod请求GPIO线路提示“Device or resource busy”
基于libgpiod的C++示例编写了监听多路GPIO的类,代码如下:
#include <stdlib.h> #include <iostream> #include <thread> #include <chrono> #include <vector> #include <cstdlib> #include <gpiod.hpp> #include <iomanip> #include <iostream> #include <filesystem> #include "gpiod.hpp" #define GPIO_PORT_1_LINE 0 #define GPIO_PORT_2_LINE 1 #define GPIO_PORT_3_LINE 5 #define GPIO_PORT_4_LINE 6 #define GPIO_CHIP_NAME "/dev/gpiochip0" IO::IO() { std::cout << "IO constructor" << std::endl; } IO::~IO() { std::cout << "IO destructor" << std::endl; } void IO::loop() { std::cout << "Loop start" << std::endl; const std::vector<int> offsets = { GPIO_PORT_1_LINE, GPIO_PORT_2_LINE, GPIO_PORT_3_LINE, GPIO_PORT_4_LINE }; try { // Open chip std::filesystem::path chip_path(GPIO_CHIP_NAME); std::cout << "STEP 1" << std::endl; // Get the requested lines gpiod::line::offsets line_offsets; for (int offset : offsets) line_offsets.push_back(offset); std::cout << "STEP 2" << std::endl; auto chip = gpiod::chip(chip_path); std::cout << "STEP 3" << std::endl; // Prepare que line request auto request_builder = chip.prepare_request(); std::cout << "STEP 4" << std::endl; // Set the consumer request_builder.set_consumer("io_test"); std::cout << "STEP 5" << std::endl; // Create the line settings gpiod::line_settings line_settings; line_settings.set_direction(gpiod::line::direction::INPUT); line_settings.set_edge_detection(gpiod::line::edge::BOTH); std::cout << "STEP 6" << std::endl; // Add the line settings request_builder.add_line_settings(line_offsets, line_settings); std::cout << "STEP 7" << std::endl; // Request the line auto request = request_builder.do_request(); std::cout << "STEP0 8" << std::endl; gpiod::edge_event_buffer buffer; while (true) { std::cout << "BLOCK WAIT" << std::endl; /* Blocks until at leat one event available */ request.read_edge_events(buffer); std::cout << "LINE READ" << std::endl; for (const auto &event : buffer) { std::cout << "IO EVENT" << std::endl; std::cout << "offset: " << event.line_offset() << " event #" << event.global_seqno() << " line event #" << event.line_seqno() << " timestamp " << event.timestamp_ns().ns() << ::std::endl; auto type = event.type(); auto ns = std::chrono::nanoseconds(event.timestamp_ns().ns()); } } } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } }
运行程序时出现以下错误:
IO Constructor Loop start STEP 1 STEP 2 STEP 3 STEP 4 STEP 5 STEP 6 STEP 7 Error: error requesting GPIO lines: Device or resource busy
已使用gpiomon工具正常访问这些线路并获取数据变化,确认无其他程序占用线路,重启设备后问题仍存在。需排查问题原因、函数调用顺序是否正确、是否遗漏关键调用。
解决方法
1. 排查GPIO线路的内核占用情况
"Device or resource busy"最常见的原因是目标GPIO线路被内核驱动占用(而非用户程序)。即使gpiomon能运行,也可能是它使用了不同的配置绕过了内核占用,或者某一条线路单独被占用导致批量请求失败。
运行以下命令查看线路状态:
gpioinfo /dev/gpiochip0
查看offset 0、1、5、6对应的行,如果显示used,说明该线路被内核模块(如LED、按键驱动)绑定,需要先解除绑定:
- 修改设备树,禁用对应GPIO的内核驱动配置;
- 卸载占用线路的内核模块(如
rmmod <module-name>)。
2. 修复代码中的潜在问题
你的代码调用顺序大体正确,但存在几个细节问题:
- 重复包含头文件:同时包含
<gpiod.hpp>和"gpiod.hpp"可能导致重复定义冲突,建议只保留其中一个; - 边缘检测兼容性:部分GPIO硬件不支持边缘检测,或需要先配置上拉/下拉电阻。可以尝试先移除
set_edge_detection调用,测试是否能成功请求线路,再逐步添加边缘检测逻辑; - 批量请求排查:尝试单独请求某一条线路(比如只保留offset 0),如果能成功,说明是某条线路的问题,逐一排查找到故障线路。
3. 验证libgpiod版本兼容性
你参考的是v2.1.x的示例代码,需确保系统安装的libgpiod版本为v2.x系列(v1.x和v2.x的API差异极大)。运行以下命令确认版本:
gpiodetect --version
如果版本不匹配,需升级或降级libgpiod到对应版本。
4. 权限验证
虽然权限问题通常提示Permission denied,但仍可尝试用sudo运行程序,排除权限导致的隐性问题。
内容的提问来源于stack exchange,提问作者Mendes
相关产品推荐
相关产品推荐

