Работа с GPIO: различия между версиями

Материал из Wiren Board
 
(не показано 17 промежуточных версий 4 участников)
Строка 1: Строка 1:
<languages/>
'''ВНИМАНИЕ:''' статья рассчитана на разработчиков или опытных пользователей и даёт общие рекомендации того, как использовать gpio в обход [[Wiren Board Software | официального ПО WirenBoard]].
<translate>
<!--T:1-->
В Wiren Board часть GPIO выведена на клеммники, часть выведена на разъёмы расширения, часть используется для служебных целей.
GPIO также используются для управления транзисторами для коммутации низковольтной нагрузки.  


<!--T:4-->
Если вам нужно работать напрямую с gpio, то мы рекомендуем делать это через драйвер [https://github.com/wirenboard/wb-homa-gpio wb-mqtt-gpio].
* '''Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V.'''
* '''Подключение сигнала с напряжением > 3.3V к ножке GPIO грозит выходом из строя процессорного модуля.'''
В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более </b>


<!--T:2-->
Описание доступных ножек gpio для конкретной ревизии контроллера можете посмотреть в статье [[GPIO]].
Описание использующихся ножек gpio для конкретной ревизии контроллера можно найти в статье [[GPIO]].


=Именование gpio=<!--T:6-->
=Меры предосторожности=
К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил:
* '''Убедитесь, что вашу задачу нельзя решить стандартными средствами программного обеспечения Wiren Board.'''
* выводы gpio сгруппированы по банкам (''banks''; эквивалентно ''gpiochips'')
* '''Все порты Wiren Board, в том числе и GPIO, работают с напряжением 3.3V.'''  
* каждый банк содержит 32 gpio. Нумерация банков начинается с 0.
* '''Подключение сигнала с напряжением большим 3.3V к ножке GPIO грозит выходом из строя процессорного модуля.'''


==Вычисление номера gpio==<!--T:6-->
В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более.
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio ''A1_IN'' контроллера WB6.7 (номер: 109; gpiochip 3, offset 13):


<!--T:7-->
=Именование gpio=
Вычислим банк gpio и offset, зная номер (109):
К сожалению, четкого стандарта по именованию gpio не существует. Номера, смещения и названия gpiochip стоит брать в таблицах: [[GPIO | Таблицы GPIO разных версий контроллера]].
<pre>
# Поделим 109 на 32. Целая часть - номер банка, остаток - offset:
109.0 / 32.0 = 3, остаток 13
</pre>


То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio:
=Работа из userspace=
<pre>
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio — свободен. Для этого можно посмотреть на вывод команды
# Умножим номер банка на 32 и прибавим offset:
<syntaxhighlight lang="bash">
3 * 32 + 13 = 109
</pre>
 
=Работа из userspace=<!--T:6-->
 
<!--T:7-->
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio не занят ядром. Для этого можно посмотреть на вывод команды
<pre>
cat /sys/kernel/debug/gpio
cat /sys/kernel/debug/gpio
</pre>
</syntaxhighlight>


<!--T:7-->
В выводе команды видим примерно следующее:
В выводе команды видим примерно следующее:
<pre>
<syntaxhighlight lang="bash">
gpiochip0: GPIOs 0-31, parent: platform/209c000.gpio, 209c000.gpio:
gpiochip0: GPIOs 0-31, parent: platform/209c000.gpio, 209c000.gpio:
  gpio-0  (                    |sysfs              ) in  hi IRQ
  gpio-0  (                    |sysfs              ) in  hi IRQ
Строка 52: Строка 30:
  gpio-26  (                    |sysfs              ) out lo     
  gpio-26  (                    |sysfs              ) out lo     
  gpio-27  (                    |sysfs              ) out hi     
  gpio-27  (                    |sysfs              ) out hi     
</pre>
</syntaxhighlight>


<!--T:7-->
Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 — свободны.
Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 доступны для экспорта.


<!--T:7-->
Если нужный gpio — занят, то можно остановить драйвер:
Если эти gpio нужны по каким-то причинам, то можно остановить драйвер:
<syntaxhighlight lang="bash">
<pre>
lsmod | grep w1 # узнаем название драйвера
lsmod | grep w1 # узнаем название драйвера
rmmod w1_gpio # выгружаем драйвер, название которого узнали
rmmod w1_gpio # выгружаем драйвер, название которого узнали
</pre>
</syntaxhighlight>
 
'''ВНИМАНИЕ:''' остановка драйверов может привести к неожиданному поведению контроллера. Теперь нужный gpio свободен до следующей перезагрузки.
 
В контроллерах Wiren Board доступные к использованию gpio обычно заняты сервисом wb-mqtt-gpio. Остановить его можно так:
<syntaxhighlight lang="bash">
systemctl stop wb-mqtt-gpio
</syntaxhighlight>
==Bash==
 
В настоящий момент, для работы с gpio в userspace доступны 2 интерфейса: ''sysfs'' и ''chardev'' (начиная с версии ядра 4.8).
 
Различия между ''chardev'' и ''sysfs'' хорошо описаны в [https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ этой статье]. Sysfs имеет статус deprecated, поэтому, по возможности, <u>стоит работать через chardev</u>.


<!--T:7-->
===Работа через chardev===
'''Остановка драйверов может привести к неожиданному поведению контроллера'''. Желаемый gpio свободен до следующей перезагрузки.


==Интерфейс sysfs в Linux==<!--T:6-->
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod].


<!--T:7-->
Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev''. Установка:
GPIO в Linux поддерживаются через sysfs-интерфейс.
 
<syntaxhighlight lang="bash">
~# apt install gpiod
</syntaxhighlight>
 
Для работы с gpio в пакете ''gpiod'' поставляются следующие утилиты:
* <code>gpiodetect</code> — информация обо всех банках gpio в системе
* <code>gpioinfo</code> — подробная информация обо всех линиях gpio определённого банка
* <code>gpioget <чип> <линия></code> — возвращает значение определённого gpio
* <code>gpioset <чип> <линия1>=<значение1> <линия2>=<значение2></code> — устанавливает состояние на определенные линии gpio
* <code>gpiofind <название></code> — возвращает номер gpio
* <code>gpiomon</code> — отслеживание событий gpio
 
Пример работы:
<syntaxhighlight lang="bash">
~# systemctl stop wb-mqtt-gpio # stop WB GPIO<==>MQTT bridge
~# gpiofind "A1 IN" # find gpiochip and offset for a given label
gpiochip0 231
~# gpioget `gpiofind "A1 IN"` # get the current GPIO value, using data returned by gpiofind
1
~# gpiofind "A1 OUT" # find chip and offset for another GPIO
gpiochip0 109
~# gpioset gpiochip0 109=1 # enable A1 OUT
~# gpioset gpiochip0 109=0 # disable A1 OUT
~# gpioset `gpiofind "A1 OUT"`=0 # now the same using gpiofind
 
</syntaxhighlight>
 
Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod].
 
===Интерфейс sysfs===


<!--T:8-->
Для работы через sysfs c определённым GPIO его надо экспортировать:
Для работы через sysfs c определённым GPIO его надо экспортировать:


<!--T:9-->
Здесь и далее N номер gpio
Здесь и далее N - номер gpio


<!--T:10-->
<syntaxhighlight lang="bash">
<pre>
echo N > /sys/class/gpio/export
echo N > /sys/class/gpio/export
</pre>
</syntaxhighlight>


<!--T:11-->
Экспортированные gpio появляются в каталоге <code>/sys/class/gpio</code>:
Экспортированные gpio появляются в каталоге /sys/class/gpio :
<syntaxhighlight lang="bash">
 
~# ls -1 /sys/class/gpio/
<!--T:12-->
<pre>
root@wirenboard:~# ls -1 /sys/class/gpio/
export
export
gpio32
gpio32
Строка 96: Строка 107:
gpiochip64
gpiochip64
unexport
unexport
</pre>
</syntaxhighlight>


<!--T:13-->
В директории <code>/sys/class/gpioN</code> теперь находятся файлы для работы с GPIO (где N номер GPIO, как и было сказано ранее):
В директории <b>/sys/class/gpioN</b> теперь находятся файлы для работы с GPIO (где N - номер GPIO, как и было сказано ранее):


<!--T:14-->
<syntaxhighlight lang="bash">
<pre>
~# ls -1 /sys/class/gpio/gpioN/
root@wirenboard:~# ls -1 /sys/class/gpio/gpioN/
active_low
active_low
device
device
Строка 112: Строка 121:
uevent
uevent
value
value
</pre>
</syntaxhighlight>


<!--T:15-->
Установка направления GPIO (ввод/вывод) производится с помощью записи в файл <code>direction</code>
Установка направления GPIO (ввод/вывод) производится с помощью записи в файл <b>direction</b>


<!--T:16-->
<syntaxhighlight lang="bash">
<pre>
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод
</pre>
</syntaxhighlight>


<!--T:17-->
Чтение и установка значения GPIO производится с помощью файла <code>value</code>.  
Чтение и установка значения GPIO производится с помощью файла <b>value</b>.  


<!--T:18-->
====Чтение и запись====
Чтение:
Чтение:
 
<syntaxhighlight lang="bash">
<!--T:19-->
<pre>
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
cat /sys/class/gpio/gpioN/value # вернёт 1 или 0
cat /sys/class/gpio/gpioN/value # вернёт 1 или 0
</pre>
</syntaxhighlight>


<!--T:20-->
Запись:
Запись:
 
<syntaxhighlight lang="bash">
<!--T:21-->
<pre>
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод
echo 0 > /sys/class/gpio/gpioN/value # установим логический 0  (низкое напряжение) на GPIO номер N
echo 0 > /sys/class/gpio/gpioN/value # установим логический 0  (низкое напряжение) на GPIO номер N
echo 1 > /sys/class/gpio/gpioN/value # установим логический 1  (высокое напряжение) на GPIO номер N
echo 1 > /sys/class/gpio/gpioN/value # установим логический 1  (высокое напряжение) на GPIO номер N
</pre>
</syntaxhighlight>


<!--T:13-->
Пример:
Пример:
# Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице [[GPIO|WB2.8]]. Для клеммника номер 2 в версии 2.8 это GPIO 32.
# Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице [[GPIO|WB2.8]]. Для клеммника номер 2 в версии 2.8 это GPIO 32.
# Экспортируем GPIO в sysfs
# Экспортируем GPIO в sysfs
#:<pre>root@wirenboard:~# echo 32 > /sys/class/gpio/export</pre>
#:<syntaxhighlight lang="bash">
echo 32 > /sys/class/gpio/export
</syntaxhighlight>
# Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
# Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
#:<pre>root@wirenboard:~# echo out > /sys/class/gpio/gpio32/direction</pre>
#:<syntaxhighlight lang="bash">
echo out > /sys/class/gpio/gpio32/direction
</syntaxhighlight>
# Открываем транзистор, подавая логический высокий уровень на затвор:
# Открываем транзистор, подавая логический высокий уровень на затвор:
#:<pre>root@wirenboard:~# echo 1 > /sys/class/gpio/gpio32/value</pre>
#:<syntaxhighlight lang="bash">
echo 1 > /sys/class/gpio/gpio32/value
</syntaxhighlight>
# Закрываем транзистор, подавая логический ноль на затвор:
# Закрываем транзистор, подавая логический ноль на затвор:
#:<pre>root@wirenboard:~# echo 0 > /sys/class/gpio/gpio32/value</pre>
#:<syntaxhighlight lang="bash">
echo 0 > /sys/class/gpio/gpio32/value
</syntaxhighlight>


===Работа с прерываниями===<!--T:22-->
====Номера GPIO====
Наиболее унивверсальный способ получить номер GPIO для устаревшего интерфейса sysfs - получить его по метке GPIO.
Для этого нужно найти номер gpiochip, смещение внутри gpiochip и базовый адрес gpiochip.


<!--T:23-->
Пример:
Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора.


<!--T:24-->
<syntaxhighlight lang="bash">
Установка прерывания производится путём записи значения в файл "edge". Значения могут быть:
~# gpiofind "A1 OUT"
* "none" - отключить прерывание
gpiochip0 109
* "rising" - включить прерывание по нисходящему фронту
~# cat /sys/class/gpio/gpiochip0/base
* "falling" - включить прерывание по восодящему фронту
0
* "both" - включить прерывание по обеим фронтам.
</syntaxhighlight>


<!--T:25-->
Т.е. для A1 OUT будет старый номер 0 (base) + 109 (offset) = 109.
Пример работы с прерываниями:
<pre>
root@wirenboard:~# echo 3 >  /sys/class/gpio/export # экспортируем GPIO номер 3 (TB10 на WB3.3)
root@wirenboard:~# cat /sys/class/gpio/gpio3/edge  # проверяем состояние прерывания
none
root@wirenboard:~# echo falling > /sys/class/gpio/gpio3/edge # устанавливаем прерывание по нисходящему фронту
root@wirenboard:~# cat /proc/interrupts  | grep gpiolib # прерывание появилось в списке. 26 - внутренний номер прерывания, 0 - количество событий
26:          0  gpio-mxs  3  gpiolib
root@wirenboard:~# cat /proc/interrupts  | grep gpiolib # после нескольких собтий, 76 - количество событий
26:        76  gpio-mxs  3  gpiolib


<!--T:26-->
Номера по метке можно получить также через отладочный интерфейс ядра. Это не требует использования утилит gpiod, но формат вывода может быть изменён в новых версиях ядра. "Старый" (глобальный) номер указан в первом столбце:
</pre>


<!--T:27-->
Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value.
Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs]


<!--T:28-->
<syntaxhighlight lang="bash">
См. также [http://elinux.org/GPIO elinux.org]
~# cat /sys/kernel/debug/gpio  | grep "A1 OUT"
gpio-109 (A1 OUT              |wb-mqtt-gpio        ) out lo
</syntaxhighlight>


==Работа через официальное ПО==<!--T:29-->
GPIO для дискретных входов и выходов модулей расширения и модулей ввода-вывода доступны таким же образом. Не забудьте выбрать модуль в интерфейсе Hardware Modules Configuration.


==Работа из python==<!--T:29-->


Для управления gpio из python был написан модуль wb_common.gpio, представляющий собой обёртку вокруг sysfs. Исходный код доступен [https://github.com/wirenboard/wb-common/blob/master/wb_common/gpio.py на нашем github.]


Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.


==Прямое обращение через память процессора==<!--T:29-->


<!--T:30-->
====Работа с прерываниями====
<b>Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs, как описано в предыдущем разделе</b>.


<!--T:31-->
Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора.
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать,
если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки.
Рекомендуется выносить критичные ко времени задачи в ядро.


<!--T:32-->
Установка прерывания производится путём записи значения в файл "edge". Значения могут быть:
См. [http://olimex.wordpress.com/2012/09/11/imx233-olinuxino-gpios-faster-and-faster/] , [https://github.com/OLIMEX/OLINUXINO/blob/master/SOFTWARE/iMX233/gpio-mmap.h]
* <code>none</code> — отключить прерывание
* <code>rising</code> — включить прерывание по нисходящему фронту
* <code>falling</code> — включить прерывание по восодящему фронту
* <code>both</code> — включить прерывание по обеим фронтам.


=Работа из ядра Linux=<!--T:44-->
Пример работы с прерываниями:
<syntaxhighlight lang="bash">
~# echo 3 >  /sys/class/gpio/export # экспортируем GPIO номер 3 (TB10 на WB3.3)
~# cat /sys/class/gpio/gpio3/edge  # проверяем состояние прерывания
none
~# echo falling > /sys/class/gpio/gpio3/edge # устанавливаем прерывание по нисходящему фронту
~# cat /proc/interrupts  | grep gpiolib # прерывание появилось в списке. 26 - внутренний номер прерывания, 0 - количество событий
26:         0  gpio-mxs  3  gpiolib
~# cat /proc/interrupts  | grep gpiolib # после нескольких собтий, 76 - количество событий
26:        76  gpio-mxs  3  gpiolib
</syntaxhighlight>


===GPIO и Device Tree=== <!--T:33-->
Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value.
Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs]


<!--T:5-->
См. также [http://elinux.org/GPIO elinux.org]
На некоторых GPIO можно программно установить 47к подтяжку к +3.3В. См. [[Special:MyLanguage/Pin_pull-up|Pin_pull-up]].


<!--T:34-->
Указывать GPIO в Device Tree необходимо для настройки работы GPIO в режиме программного SPI, I2C, для использования GPIO в качестве источника прерываний и т.д.
Так, например, на пин 10@UEXT1 (CS) и пины 5@UEXT2 (SCL), 6@UEXT2 (SDA), 10@UEXT2 (CS) выведены линии GPIO процессора. Их можно сконфигурировать для использования, например, в качестве chip-select для SPI или в качестве I2C.


<!--T:35-->
==Python==
GPIO процессора и периферийных устройств разбиты на банки (gpiochip). GPIO процессора разбиты на 3 банка по 32 GPIO: gpio0, gpio1, gpio2. Адресация GPIO в Device Tree происходит по номеру банка и номеру GPIO *внутри* банка.


====Пример 1==== <!--T:36-->
Для управления gpio из python был написан модуль <pre>wb_common.gpio</pre>
Модуль представляет собой обёртку вокруг sysfs. Исходный код доступен [https://github.com/wirenboard/wb-common/blob/master/wb_common/gpio.py на нашем github.]


<!--T:37-->
Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.
Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице [[Special:MyLanguage/Список GPIO|Список GPIO]], сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 :
 
<pre>
6lowpan@0 {
compatible = "microchip,mrf24j40";
spi-max-frequency = <100000>;
reg = <6>;
interrupt-parent = <&gpio1>;
interrupts = <21 0>;
};
</pre>
</translate>

Текущая версия на 13:42, 17 октября 2023

ВНИМАНИЕ: статья рассчитана на разработчиков или опытных пользователей и даёт общие рекомендации того, как использовать gpio в обход официального ПО WirenBoard.

Если вам нужно работать напрямую с gpio, то мы рекомендуем делать это через драйвер wb-mqtt-gpio.

Описание доступных ножек gpio для конкретной ревизии контроллера можете посмотреть в статье GPIO.

Меры предосторожности

  • Убедитесь, что вашу задачу нельзя решить стандартными средствами программного обеспечения Wiren Board.
  • Все порты Wiren Board, в том числе и GPIO, работают с напряжением 3.3V.
  • Подключение сигнала с напряжением большим 3.3V к ножке GPIO грозит выходом из строя процессорного модуля.

В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более.

Именование gpio

К сожалению, четкого стандарта по именованию gpio не существует. Номера, смещения и названия gpiochip стоит брать в таблицах: Таблицы GPIO разных версий контроллера.

Работа из userspace

Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio — свободен. Для этого можно посмотреть на вывод команды

cat /sys/kernel/debug/gpio

В выводе команды видим примерно следующее:

gpiochip0: GPIOs 0-31, parent: platform/209c000.gpio, 209c000.gpio:
 gpio-0   (                    |sysfs               ) in  hi IRQ
 gpio-10  (                    |?                   ) in  lo    
 gpio-11  (                    |w1                  ) in  hi    
 gpio-13  (                    |w1 strong pullup    ) out lo    
 gpio-26  (                    |sysfs               ) out lo    
 gpio-27  (                    |sysfs               ) out hi

Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 — свободны.

Если нужный gpio — занят, то можно остановить драйвер:

lsmod | grep w1 # узнаем название драйвера
rmmod w1_gpio # выгружаем драйвер, название которого узнали

ВНИМАНИЕ: остановка драйверов может привести к неожиданному поведению контроллера. Теперь нужный gpio свободен до следующей перезагрузки.

В контроллерах Wiren Board доступные к использованию gpio обычно заняты сервисом wb-mqtt-gpio. Остановить его можно так:

systemctl stop wb-mqtt-gpio

Bash

В настоящий момент, для работы с gpio в userspace доступны 2 интерфейса: sysfs и chardev (начиная с версии ядра 4.8).

Различия между chardev и sysfs хорошо описаны в этой статье. Sysfs имеет статус deprecated, поэтому, по возможности, стоит работать через chardev.

Работа через chardev

Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку libgpiod и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в репозитории libgpiod.

Утилиты распространяются в составе debian-пакетов gpiod и libgpiod-dev. Установка:

~# apt install gpiod

Для работы с gpio в пакете gpiod поставляются следующие утилиты:

  • gpiodetect — информация обо всех банках gpio в системе
  • gpioinfo — подробная информация обо всех линиях gpio определённого банка
  • gpioget <чип> <линия> — возвращает значение определённого gpio
  • gpioset <чип> <линия1>=<значение1> <линия2>=<значение2> — устанавливает состояние на определенные линии gpio
  • gpiofind <название> — возвращает номер gpio
  • gpiomon — отслеживание событий gpio

Пример работы:

~# systemctl stop wb-mqtt-gpio # stop WB GPIO<==>MQTT bridge
~# gpiofind "A1 IN" # find gpiochip and offset for a given label
gpiochip0 231
~# gpioget `gpiofind "A1 IN"` # get the current GPIO value, using data returned by gpiofind
1
~# gpiofind "A1 OUT" # find chip and offset for another GPIO
gpiochip0 109
~# gpioset gpiochip0 109=1 # enable A1 OUT
~# gpioset gpiochip0 109=0 # disable A1 OUT
~# gpioset `gpiofind "A1 OUT"`=0 # now the same using gpiofind

Примеры использования gpiod можно посмотреть в [1] и [2].

Интерфейс sysfs

Для работы через sysfs c определённым GPIO его надо экспортировать:

Здесь и далее N — номер gpio

echo N > /sys/class/gpio/export

Экспортированные gpio появляются в каталоге /sys/class/gpio:

~# ls -1 /sys/class/gpio/
export
gpio32
gpiochip0
gpiochip120
gpiochip32
gpiochip64
unexport

В директории /sys/class/gpioN теперь находятся файлы для работы с GPIO (где N — номер GPIO, как и было сказано ранее):

~# ls -1 /sys/class/gpio/gpioN/
active_low
device
direction
edge
power
subsystem
uevent
value

Установка направления GPIO (ввод/вывод) производится с помощью записи в файл direction

echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод

Чтение и установка значения GPIO производится с помощью файла value.

Чтение и запись

Чтение:

echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод
cat /sys/class/gpio/gpioN/value # вернёт 1 или 0

Запись:

echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод
echo 0 > /sys/class/gpio/gpioN/value # установим логический 0  (низкое напряжение) на GPIO номер N
echo 1 > /sys/class/gpio/gpioN/value # установим логический 1  (высокое напряжение) на GPIO номер N

Пример:

  1. Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице WB2.8. Для клеммника номер 2 в версии 2.8 это GPIO 32.
  2. Экспортируем GPIO в sysfs
    echo 32 > /sys/class/gpio/export
    
  3. Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
    echo out > /sys/class/gpio/gpio32/direction
    
  4. Открываем транзистор, подавая логический высокий уровень на затвор:
    echo 1 > /sys/class/gpio/gpio32/value
    
  5. Закрываем транзистор, подавая логический ноль на затвор:
    echo 0 > /sys/class/gpio/gpio32/value
    

Номера GPIO

Наиболее унивверсальный способ получить номер GPIO для устаревшего интерфейса sysfs - получить его по метке GPIO. Для этого нужно найти номер gpiochip, смещение внутри gpiochip и базовый адрес gpiochip.

Пример:

~# gpiofind "A1 OUT"
gpiochip0 109
~# cat /sys/class/gpio/gpiochip0/base 
0

Т.е. для A1 OUT будет старый номер 0 (base) + 109 (offset) = 109.

Номера по метке можно получить также через отладочный интерфейс ядра. Это не требует использования утилит gpiod, но формат вывода может быть изменён в новых версиях ядра. "Старый" (глобальный) номер указан в первом столбце:


~# cat /sys/kernel/debug/gpio  | grep "A1 OUT"
 gpio-109 (A1 OUT              |wb-mqtt-gpio        ) out lo

GPIO для дискретных входов и выходов модулей расширения и модулей ввода-вывода доступны таким же образом. Не забудьте выбрать модуль в интерфейсе Hardware Modules Configuration.



Работа с прерываниями

Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора.

Установка прерывания производится путём записи значения в файл "edge". Значения могут быть:

  • none — отключить прерывание
  • rising — включить прерывание по нисходящему фронту
  • falling — включить прерывание по восодящему фронту
  • both — включить прерывание по обеим фронтам.

Пример работы с прерываниями:

~# echo 3 >  /sys/class/gpio/export # экспортируем GPIO номер 3 (TB10 на WB3.3)
~# cat /sys/class/gpio/gpio3/edge   # проверяем состояние прерывания
none
~# echo falling > /sys/class/gpio/gpio3/edge # устанавливаем прерывание по нисходящему фронту
~# cat /proc/interrupts  | grep gpiolib # прерывание появилось в списке. 26 - внутренний номер прерывания, 0 - количество событий
 26:          0  gpio-mxs   3  gpiolib
~# cat /proc/interrupts  | grep gpiolib # после нескольких собтий, 76 - количество событий
 26:         76  gpio-mxs   3  gpiolib

Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value. Пример работы см. [3]

См. также elinux.org


Python

Для управления gpio из python был написан модуль

wb_common.gpio

Модуль представляет собой обёртку вокруг sysfs. Исходный код доступен на нашем github.

Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.