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

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


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


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


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


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


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


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


<!--T:7-->
В выводе команды видим примерно следующее:
В выводе команды видим примерно следующее:
<syntaxhighlight lang="bash">
<pre>
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
Строка 30: Строка 50:
  gpio-26  (                    |sysfs              ) out lo     
  gpio-26  (                    |sysfs              ) out lo     
  gpio-27  (                    |sysfs              ) out hi     
  gpio-27  (                    |sysfs              ) out hi     
</syntaxhighlight>
</pre>
Это значит, что 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 — занят, то можно остановить драйвер:
<pre>
<syntaxhighlight lang="bash">
lsmod | grep w1 # узнаем название драйвера
lsmod | grep w1 # узнаем название драйвера
rmmod w1_gpio # выгружаем драйвер, название которого узнали
rmmod w1_gpio # выгружаем драйвер, название которого узнали
</syntaxhighlight>
</pre>
 
'''ВНИМАНИЕ:''' остановка драйверов может привести к неожиданному поведению контроллера. Теперь нужный 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>.
До следующей перезагрузки контроллера желаемый gpio свободен!


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


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


Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev''. Установка:
<!--T:7-->
 
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 его надо экспортировать:


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


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


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


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


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


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


<syntaxhighlight lang="bash">
<!--T:16-->
<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 на вывод
</syntaxhighlight>
</pre>


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


<!--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
</syntaxhighlight>
</pre>


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


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


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


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


Т.е. для A1 OUT будет старый номер 0 (base) + 109 (offset) = 109.
<!--T:25-->
Пример работы с прерываниями:
<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


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


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


<syntaxhighlight lang="bash">
<!--T:28-->
~# cat /sys/kernel/debug/gpio  | grep "A1 OUT"
См. также [http://elinux.org/GPIO elinux.org]
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-->
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать,
если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки.
Рекомендуется выносить критичные ко времени задачи в ядро.


Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора.
<!--T:32-->
См. [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]


Установка прерывания производится путём записи значения в файл "edge". Значения могут быть:
=Работа из ядра Linux=<!--T:44-->
* <code>none</code> — отключить прерывание
* <code>rising</code> — включить прерывание по нисходящему фронту
* <code>falling</code> — включить прерывание по восодящему фронту
* <code>both</code> — включить прерывание по обеим фронтам.


Пример работы с прерываниями:
===GPIO и Device Tree=== <!--T:33-->
<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>


Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value.
<!--T:5-->
Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs]
На некоторых GPIO можно программно установить 47к подтяжку к +3.3В. См. [[Special:MyLanguage/Pin_pull-up|Pin_pull-up]].


См. также [http://elinux.org/GPIO elinux.org]
<!--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-->
GPIO процессора и периферийных устройств разбиты на банки (gpiochip). GPIO процессора разбиты на 3 банка по 32 GPIO: gpio0, gpio1, gpio2. Адресация GPIO в Device Tree происходит по номеру банка и номеру GPIO *внутри* банка.


==Python==
====Пример 1==== <!--T:36-->


Для управления gpio из python был написан модуль <pre>wb_common.gpio</pre>
<!--T:37-->
Модуль представляет собой обёртку вокруг sysfs. Исходный код доступен [https://github.com/wirenboard/wb-common/blob/master/wb_common/gpio.py на нашем github.]
Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице [[Special:MyLanguage/Список GPIO|Список GPIO]], сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 :


Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.
<pre>
6lowpan@0 {
compatible = "microchip,mrf24j40";
spi-max-frequency = <100000>;
reg = <6>;
interrupt-parent = <&gpio1>;
interrupts = <21 0>;
};
</pre>
</translate>

Версия 16:50, 26 марта 2021

Другие языки:

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

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

Соответствие между номерами GPIO в Linux и их местоположением и функцией можно найти в статье GPIO.

Именование gpio

К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил:

  • выводы gpio сгруппированы по банкам (banks; эквивалентно gpiochips)
  • каждый банк содержит 32 gpio. Нумерация банков начинается с 0.

Вычисление номера gpio

Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio A1_IN контроллера WB6.7 (номер: 109; gpiochip 3, offset 13):

Вычислим банк gpio и offset, зная номер (109):

# Поделим 109 на 32. Целая часть - номер банка, остаток - offset:
109.0 / 32.0 = '''3''', остаток '''13'''

То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio:

# Умножим номер банка на 32 и прибавим offset:
3 * 32 + 13 = 109

Работа из 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 свободен!


Интерфейс sysfs в Linux

GPIO в Linux поддерживаются через sysfs-интерфейс.

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

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

echo N > /sys/class/gpio/export

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

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

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

root@wirenboard:~# 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
    root@wirenboard:~# echo 32 > /sys/class/gpio/export
  3. Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
    root@wirenboard:~# echo out > /sys/class/gpio/gpio32/direction
  4. Открываем транзистор, подавая логический высокий уровень на затвор:
    root@wirenboard:~# echo 1 > /sys/class/gpio/gpio32/value
  5. Закрываем транзистор, подавая логический ноль на затвор:
    root@wirenboard:~# echo 0 > /sys/class/gpio/gpio32/value

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

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

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

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

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

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

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

См. также elinux.org

Работа через официальное ПО

Работа из python

Для управления gpio из python был написан модуль wb_common.gpio, представляющий собой обёртку вокруг sysfs. Исходный код доступен на нашем github.

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

Прямое обращение через память процессора

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

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

См. [2] , [3]

Работа из ядра Linux

GPIO и Device Tree

На некоторых GPIO можно программно установить 47к подтяжку к +3.3В. См. Pin_pull-up.

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

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

Пример 1

Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице Список GPIO, сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 :

				6lowpan@0 {
					compatible = "microchip,mrf24j40";
					spi-max-frequency = <100000>;
					reg = <6>;
					interrupt-parent = <&gpio1>;
					interrupts = <21 0>;
				};