LINUX.ORG.RU

GPIO events

 ,


1

4

Добрый день, коллеги!

Скажу честно, с GPIO столкнулся впервые.

Смотрел 2 способа работы: через /sys и через libgpiod. Через файлы мне понравилось куда как больше.

Чего удалось достичь: инициализировать линии, мыргать светодиодом и даже получать информацию о том в каком состоянии линия.

Остались непонятки: как выяснить какие линии являются IN и какие OUT? Выяснить не методом ручного контроля, а автоматически.

Еще, по ТЗ, требуется постоянный опрос с частотой до 10 раз в секунду, что здорово нагружает процессор.

Начал рыть и нашел некие намеки, что можно как-то сделать через event, т.е. не заниматься постоянным опросом, а использовать нечто, реагируещее на изменение состояния линии.

Нашел пример на python, там, как я понял, при возникновении изменения состояния линии, вызывается функция, которая выполняется в новом потоке.

Подскажите как «присесть» на event при работе через /sys?


Через файлы мне понравилось куда как больше.

но таки депрекейтед,

т.е. не заниматься постоянным опросом, а использовать нечто, реагируещее на изменение состояния линии.

вот в libgpiod как раз можно удобно хэндлить события

Остались непонятки: как выяснить какие линии являются IN и какие OUT?

?? ты же это не выясняешь, а сам устанавливаешь, ну или опять же через libgpiod можно узнать что ввобще есть и в каком состоянии, даже тестовые готовые утилитки в комплекте есть

zurg
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от zurg

но таки депрекейтед,

Деприкейтед, но он такой теплый. Ламповый!

вот в libgpiod как раз можно удобно хэндлить события

Нашел на гите исходный код и… Ни фига не вышло.

Через sysfs понятнее и наверняка можно к нему на event присесть.

HighMan
() автор топика
Ответ на: комментарий от HighMan

Деприкейтед, но он такой теплый. Ламповый!

Только если пишешь башпортянку. На нормальном языке программировании, да даже на сишке, работать через библиотеку не трудно.

ox55ff ★★★★★
()

Остались непонятки: как выяснить какие линии являются IN и какие OUT?

Это вы можете задавать сами. Что-то вроде echo "out" > /sys/class/gpio/gpioN/direction. Подробнее читайте здесь.

czan
()
Ответ на: комментарий от czan

Это вы можете задавать сами. Что-то вроде echo «out» > /sys/class/gpio/gpioN/direction. Подробнее читайте здесь.

Это понятно, но у меня на устройстве 8 линий из которых 4 работают лишь на IN. Вернее они отображают зеркальную информацию о состоянии оставшихся 4х линий

HighMan
() автор топика
Ответ на: комментарий от HighMan

Нашел на гите исходный код и… Ни фига не вышло.

Что, и gpiomon не работает ?

Должно быть что-то вроде

# gpiomon 0 2
event: FALLING EDGE offset: 2 timestamp: [    7395.496667909]
event:  RISING EDGE offset: 2 timestamp: [    7400.176336426]
alx777 ★★
()
Ответ на: комментарий от HighMan

Ничего не понял. На каком устройстве? Почему 4 работают лишь на IN?

czan
()

Как может опрос 10 раз в секунду нагружать процессор? Ты эниак программируешь чтоли?

vbr ★★★★
()
Ответ на: комментарий от alx777

Что, и gpiomon не работает ?

Не работает!

# ls /dev/gpio*
/dev/gpiochip0

# gpiodetect 
gpiochip0 [gpio-kempld] (8 lines)

#gpioget gpiochip0 0
1

#gpiomon gpiochip0 0
gpiomon: error waiting for events: No such device

....
#gpiomon gpiochip0 8
gpiomon: error waiting for events: Invalid argument

И этот «No such device» c 0 по 7 линию.

HighMan
() автор топика
Ответ на: комментарий от alx777

А что сообщает

# strace gpiomon gpiochip0 0
execve("/usr/bin/gpiomon", ["gpiomon", "gpiochip0", "0"], 0x7ffe89c74dd0 /* 38 vars */) = 0
brk(NULL)                               = 0x56168f7f5000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=14573, ...}) = 0
mmap(NULL, 14573, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f01766b4000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib64/libgpiod.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0005\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=39584, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f01766b2000
mmap(NULL, 41600, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f01766a7000
mmap(0x7f01766aa000, 16384, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f01766aa000
mmap(0x7f01766ae000, 8192, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7f01766ae000
mmap(0x7f01766b0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8000) = 0x7f01766b0000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@\200\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1921200, ...}) = 0
mmap(NULL, 1934024, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f01764ce000
mprotect(0x7f01764f4000, 1740800, PROT_NONE) = 0
mmap(0x7f01764f4000, 1425408, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7f01764f4000
mmap(0x7f0176650000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x182000) = 0x7f0176650000
mmap(0x7f017669d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ce000) = 0x7f017669d000
mmap(0x7f01766a3000, 13000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f01766a3000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f01764cb000
arch_prctl(ARCH_SET_FS, 0x7f01764cb740) = 0
mprotect(0x7f017669d000, 12288, PROT_READ) = 0
mprotect(0x7f01766b0000, 4096, PROT_READ) = 0
mprotect(0x56168f4bd000, 4096, PROT_READ) = 0
mprotect(0x7f01766e5000, 4096, PROT_READ) = 0
munmap(0x7f01766b4000, 14573)           = 0
rt_sigprocmask(SIG_BLOCK, [INT TERM], NULL, 8) = 0
signalfd4(-1, [INT TERM], 8, 0)         = 3
openat(AT_FDCWD, "/dev", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
fstat(4, {st_mode=S_IFDIR|0755, st_size=3860, ...}) = 0
brk(NULL)                               = 0x56168f7f5000
brk(0x56168f816000)                     = 0x56168f816000
getdents64(4, 0x56168f7f52d0 /* 193 entries */, 32768) = 5632
getdents64(4, 0x56168f7f52d0 /* 0 entries */, 32768) = 0
close(4)                                = 0
openat(AT_FDCWD, "/dev/gpiochip0", O_RDWR|O_CLOEXEC) = 4
lstat("/dev/gpiochip0", {st_mode=S_IFCHR|0600, st_rdev=makedev(0xfe, 0), ...}) = 0
stat("/dev/gpiochip0", {st_mode=S_IFCHR|0600, st_rdev=makedev(0xfe, 0), ...}) = 0
access("/sys/bus/gpio/devices/gpiochip0/dev", R_OK) = 0
openat(AT_FDCWD, "/sys/bus/gpio/devices/gpiochip0/dev", O_RDONLY) = 5
read(5, "254:0\n", 15)                  = 6
close(5)                                = 0
ioctl(4, GPIO_GET_CHIPINFO_IOCTL, {name="gpiochip0", label="gpio-kempld", lines=8}) = 0
close(4)                                = 0
openat(AT_FDCWD, "/dev/gpiochip0", O_RDWR|O_CLOEXEC) = 4
lstat("/dev/gpiochip0", {st_mode=S_IFCHR|0600, st_rdev=makedev(0xfe, 0), ...}) = 0
stat("/dev/gpiochip0", {st_mode=S_IFCHR|0600, st_rdev=makedev(0xfe, 0), ...}) = 0
access("/sys/bus/gpio/devices/gpiochip0/dev", R_OK) = 0
openat(AT_FDCWD, "/sys/bus/gpio/devices/gpiochip0/dev", O_RDONLY) = 5
read(5, "254:0\n", 15)                  = 6
close(5)                                = 0
ioctl(4, GPIO_GET_CHIPINFO_IOCTL, {name="gpiochip0", label="gpio-kempld", lines=8}) = 0
ioctl(4, GPIO_GET_LINEINFO_IOCTL, {line_offset=0} => {flags=GPIOLINE_FLAG_KERNEL, name="", consumer="sysfs"}) = 0
ioctl(4, GPIO_GET_LINEEVENT_IOCTL, {lineoffset=0, handleflags=GPIOHANDLE_REQUEST_INPUT, eventflags=GPIOEVENT_REQUEST_BOTH_EDGES, consumer_label="gpiomon"}) = -1 EBUSY (Device or resource busy)
close(4)                                = 0
write(2, "gpiomon: ", 9gpiomon: )                = 9
write(2, "error waiting for events", 24error waiting for events) = 24
write(2, ": Device or resource busy\n", 26: Device or resource busy
) = 26
exit_group(1)                           = ?
+++ exited with 1 +++

Есть еще странность: нет файла /sys/class/gpio/gpio*/edge

Как я смотрел по примерам полинга для sysfs в этот файл записывают ‘rising’.

https://raspberrypi.stackexchange.com/questions/44416/polling-gpio-pin-from-c-always-getting-immediate-response

# ls /sys/class/gpio/gpio*/
/sys/class/gpio/gpio1016/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1017/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1018/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1019/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1020/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1021/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1022/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpio1023/:
active_low  device  direction  power  subsystem  uevent  value

/sys/class/gpio/gpiochip1016/:
base  device  label  ngpio  power  subsystem  uevent

Возможно, я что-то недопонимаю

HighMan
() автор топика
Последнее исправление: HighMan (всего исправлений: 3)
Ответ на: комментарий от HighMan

Скорее всего этот порт занят чем-то еще. В моем случае:

Free:

# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 0-31, parent: platform/30200000.gpio, 30200000.gpio:
 gpio-0   (digital-out 1       )
 gpio-1   (digital-in 1        )

Exported:

В этом случае gpiomon вылетает с Device or resource busy

# echo 1 >/sys/class/gpio/export

# cat /sys/kernel/debug/gpio 
gpiochip0: GPIOs 0-31, parent: platform/30200000.gpio, 30200000.gpio:
 gpio-0   (digital-out 1       )
 gpio-1   (digital-in 1        |sysfs               ) in  hi 

# gpiomon 0 1
gpiomon: error waiting for events: Device or resource busy

gpiomon:

работает как от него и ожидается

# echo 1 >/sys/class/gpio/unexport
# gpiomon 0 1
# cat /sys/kernel/debug/gpio 
gpiochip0: GPIOs 0-31, parent: platform/30200000.gpio, 30200000.gpio:
 gpio-0   (digital-out 1       )
 gpio-1   (digital-in 1        |gpiomon             ) in  hi IRQ 
alx777 ★★
()
Ответ на: комментарий от alx777

Скорее всего этот порт занят чем-то еще.

Будем экспериментировать над портом 1016.

# cat /sys/kernel/debug/gpio
gpiochip0: GPIOs 1016-1023, parent: platform/kempld-gpio, gpio-kempld, can sleep:
 gpio-1017 (                    |sysfs               ) in  hi 
 gpio-1018 (                    |sysfs               ) in  hi 
 gpio-1019 (                    |sysfs               ) in  hi 
 gpio-1020 (                    |sysfs               ) in  lo 
 gpio-1021 (                    |sysfs               ) in  lo 
 gpio-1022 (                    |sysfs               ) in  lo 
 gpio-1023 (                    |sysfs               ) in  lo

# cat /sys/class/gpio/gpiochip1016/base 
1016

# gpiomon 0 0
gpiomon: error waiting for events: No such device
# gpiomon 0 1016
gpiomon: error waiting for events: Invalid argument
# gpiomon gpiochip1016 1016
gpiomon: error waiting for events: No such file or directory
# gpiomon gpiochip1016 0
gpiomon: error waiting for events: No such file or directory

Т.е. открыты все возможные порты кроме 1016 и я всеми невероятными способоми пытаюсь запустить на нем gpiomon

HighMan
() автор топика
Ответ на: комментарий от alx777

Судя по тому, что в драйвере упоминание IRQ найти сложно, может оказаться что ивенты этим железом и не поддерживаются никак

О как… Я думал, что эвенты ОБЯЗАНЫ поддерживаться на всех gpio…

https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals

Check your processor documentation. Not all GPIO pins support interrupts.

А я столько времени потерял!

HighMan
() автор топика
Последнее исправление: HighMan (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.