写一篇随意一点的博客吧,因为我的时间总是不够用。虽然简单,我怀疑本篇文章能帮到不少人。帮人就是我的乐趣。我希望解决了温饱问题的同志们,积极参与社会治理活动中来。只有每个人出一份力,我们的社会才会变得美好。只有社会美好,我们以及我们的子孙才能美好。
世界是他们的,但也是我们的,但终究还是我们的!!每天看30分钟的负能量,我任然充满正能量。
最近我使用的Linux环境完全弃用了sysfs的gpio系统。那么我就只能使用gpiod子系统。gpiod提供了许多工具,例如gpioget、gpioset、gpioinfo等。这些指令的使用在网上都有教程。如果我们使用c语言编程控制GPIO会使用到libgpiod库。
我碰到一个问题,就是读取输出模式下的GPIO口的值,我没有找到合适的工具。因为gpioget
会把要操作的GPIO口先设置为输入模式,这明显不满足我的要求。在网上找了一下,找到了gpioget
的as-is
选项。该选项说是保留GPIO原有的模式。然后就根据帮助信息尝试,果然不可以,这个命令还是改变了GPIO口的输出方向,非吾之所想。但是也介绍一下,命令如下。
# gpioset 5 12=1
#
# gpioget -B as-is 5 12
1
# gpioset 5 12=0
#
# gpioget -B as-is 5 12
0
#
帮助信息如下:
# gpioset --help
Usage: gpioset [OPTIONS] <chip name/number> <offset1>=<value1> <offset2>=<value2> ...
Set GPIO line values of a GPIO chip and maintain the state until the process exits
Options:
-h, --help: display this message and exit
-v, --version: display the version and exit
-l, --active-low: set the line active state to low
-B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):
set the line bias
-D, --drive=[push-pull|open-drain|open-source] (defaults to 'push-pull'):
set the line drive mode
-m, --mode=[exit|wait|time|signal] (defaults to 'exit'):
tell the program what to do after setting values
-s, --sec=SEC: specify the number of seconds to wait (only valid for --mode=time)
-u, --usec=USEC: specify the number of microseconds to wait (only valid for --mode=time)
-b, --background: after setting values: detach from the controlling terminal
Biases:
as-is: leave bias unchanged
disable: disable bias
pull-up: enable pull-up
pull-down: enable pull-down
Drives:
push-pull: drive the line both high and low
open-drain: drive the line low or go high impedance
open-source: drive the line high or go high impedance
Modes:
exit: set values and exit immediately
wait: set values and wait for user to press ENTER
time: set values and sleep for a specified amount of time
signal: set values and wait for SIGINT or SIGTERM
如果你的开发环境没有as-is
选项,那么你可自己写一个。下面是我写的一个读取输出状态的GPIO口值的示例程序。
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <gpiod.h>
#define GPIO_CHIP_PREFIX "gpiochip"
static void usage(char **argv)
{
fprintf(stderr, "Usage:\n");
fprintf(stderr, "%s group_number line_number\n", argv[0]);
}
static int extract_gpio_group_line_number(char **argv, int *r_group_num, int *r_line_num)
{
if (!r_group_num || !r_line_num) {
return -1;
}
const char *g_str, *l_str;
if (0 == strncasecmp(argv[1], GPIO_CHIP_PREFIX, strlen(GPIO_CHIP_PREFIX))) {
g_str = argv[1] + strlen(GPIO_CHIP_PREFIX);
} else {
g_str = argv[1];
}
if (0 == strncasecmp(argv[2], GPIO_CHIP_PREFIX, strlen(GPIO_CHIP_PREFIX))) {
l_str = argv[2] + strlen(GPIO_CHIP_PREFIX);
} else {
l_str = argv[2];
}
char *endptr = NULL;
int group_num = strtol(g_str, &endptr, 10);
if (endptr == g_str || *endptr != '\0' || group_num < 0) {
fprintf(stderr, "The GPIO Group number error, %s\n", g_str);
return -2;
}
int line_num = strtol(l_str, &endptr, 10);
if (endptr == l_str || *endptr != '\0' || line_num < 0 || line_num >= 32) {
fprintf(stderr, "The GPIO Line number error, %s\n", l_str);
return -3;
}
*r_group_num = group_num;
*r_line_num = line_num;
return 0;
}
int main(int argc, char **argv)
{
if (argc != 3) {
usage(argv);
return -1;
}
int group_num, line_num;
int ret = extract_gpio_group_line_number(argv, &group_num, &line_num);
if (ret != 0) {
usage(argv);
return ret;
}
char chipname[32];
snprintf(chipname, sizeof(chipname), "gpiochip%d", group_num);
struct gpiod_chip *chip = gpiod_chip_open_by_name(chipname);
if (!chip) {
fprintf(stderr, "Open chip:%s failed, reasion:%s\n", chipname, strerror(errno));
return -1;
}
struct gpiod_line *line = gpiod_chip_get_line(chip, line_num);
if (!line) {
fprintf(stderr, "Get line:%d failed, reasion:%s\n", line_num, strerror(errno));
goto close_chip;
}
/* ref : https://libgpiod-dlang.dpldocs.info/source/gpiod.d.html#L1025 */
struct gpiod_line_request_config conf;
memset(&conf, 0, sizeof(conf));
/* just a label for gpio */
conf.consumer = "snoop";
/* request gpio and do not change the current mode */
conf.request_type = GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
/* up down pull flags */
conf.flags = 0;
ret = gpiod_line_request(line, &conf, 0 /* default value */);
if (ret < 0) {
fprintf(stderr, "Request line(%s %d) as-is is failed, reasion:%s\n", chipname, line_num, strerror(errno));
goto release_line;
}
int value;
/* Read input */
value = gpiod_line_get_value(line);
if (value < 0) {
fprintf(stderr, "Read line input failed, reasion:%s\n", strerror(errno));
goto release_line;
}
printf("%d\n", value);
release_line:
gpiod_line_release(line);
close_chip:
gpiod_chip_close(chip);
return 0;
}
测试过程如下:
~# gpioget 5 12
0
~# gpioinfo | grep PF12
line 12: "PF12" unused input active-high
~#
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# ./gpiosnoop 5 12
0
~# gpioinfo | grep PF12
line 12: "PF12" unused input active-high
~#
~# gpioset 5 12=1
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# gpioinfo | grep PF12
line 12: "PF12" unused output active-high
~# gpioinfo | grep PF12
line 12: "PF12" unused output active-high
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# ./gpiosnoop 5 12
1
~# gpioinfo | grep PF12
line 12: "PF12" unused output active-high
~#
~# ./gpiosnoop gpiochip5 12
1
~# ./gpiosnoop gpiochip5 12x
The GPIO Line number error, 12x
Usage:
./gpiosnoop group_number line_number
~#
如果你喜欢我的理想,请加入我们,行动起来。