Работа с GPIO: различия между версиями
Vdromanov (обсуждение | вклад) |
Vdromanov (обсуждение | вклад) |
||
Строка 2: | Строка 2: | ||
<translate> | <translate> | ||
<!--T:1--> | <!--T:1--> | ||
Статья рассчитана на разработчиков или опытных пользователей и даёт общие рекомендации того, как использовать gpio в обход официального ПО WirenBoard. | |||
<!--T:4--> | <!--T:2--> | ||
Каноничный способ взаимодействия с gpio контроллеров WirenBoard - это драйвер '''wb-homa-gpio''' с [https://github.com/wirenboard/wb-homa-gpio открытым исходным кодом]. В readme репозитория можно почитать о конфигурации драйвера для специализированных нужд. | |||
<!--T:3--> | |||
Описание доступных ножек gpio для конкретной ревизии контроллера можно найти в статье [[GPIO]]. | |||
=Меры предосторожности=<!--T:4--> | |||
<!--T:5--> | |||
* '''Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V.''' | * '''Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V.''' | ||
* '''Подключение сигнала с напряжением > 3.3V к ножке GPIO грозит выходом из строя процессорного модуля.''' | * '''Подключение сигнала с напряжением > 3.3V к ножке GPIO грозит выходом из строя процессорного модуля.''' | ||
<!--T:6--> | |||
В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более </b> | В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более </b> | ||
<!--T: | =Именование gpio=<!--T:7--> | ||
<!--T:8--> | |||
К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил: | К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил: | ||
* выводы gpio сгруппированы по банкам (''banks''; эквивалентно ''gpiochips'') | * выводы gpio сгруппированы по банкам (''banks''; эквивалентно ''gpiochips'') | ||
* каждый банк содержит 32 gpio. Нумерация банков начинается с 0. | * каждый банк содержит 32 gpio. Нумерация банков начинается с 0. | ||
==Вычисление номера gpio==<!--T: | ==Вычисление номера gpio==<!--T:9--> | ||
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio ''A1_IN'' контроллера WB6.7 (номер: 109; gpiochip 3, offset 13): | |||
<!--T:10--> | |||
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio ''A1_IN'' контроллера WB6.7 (''номер: 109; gpiochip 3, offset 13''): | |||
<!--T: | <!--T:11--> | ||
Вычислим банк gpio и offset, зная номер (109): | Вычислим банк gpio и offset, зная номер (109): | ||
<pre> | <pre> | ||
Строка 28: | Строка 38: | ||
</pre> | </pre> | ||
<!--T:12--> | |||
То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio: | То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio: | ||
<pre> | <pre> | ||
Строка 34: | Строка 45: | ||
</pre> | </pre> | ||
=Работа из userspace=<!--T: | =Работа из userspace=<!--T:13--> | ||
<!--T: | <!--T:14--> | ||
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio - свободен. Для этого можно посмотреть на вывод команды | Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio - свободен. Для этого можно посмотреть на вывод команды | ||
<pre> | <pre> | ||
Строка 42: | Строка 53: | ||
</pre> | </pre> | ||
<!--T: | <!--T:15--> | ||
В выводе команды видим примерно следующее: | В выводе команды видим примерно следующее: | ||
<pre> | <pre> | ||
Строка 54: | Строка 65: | ||
</pre> | </pre> | ||
<!--T: | <!--T:16--> | ||
Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 | Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 - свободны. | ||
<!--T: | <!--T:17--> | ||
Если | Если нужный gpio - занят, то можно остановить драйвер: | ||
<pre> | <pre> | ||
lsmod | grep w1 # узнаем название драйвера | lsmod | grep w1 # узнаем название драйвера | ||
Строка 64: | Строка 75: | ||
</pre> | </pre> | ||
<!--T: | <!--T:18--> | ||
'''Остановка драйверов может привести к неожиданному поведению контроллера'''. Теперь | '''Остановка драйверов может привести к неожиданному поведению контроллера'''. Теперь нужный gpio свободен до следующей перезагрузки. | ||
== | ==Bash==<!--T:19--> | ||
<!--T: | <!--T:20--> | ||
В настоящий момент, для работы с gpio в userspace доступны 2 интерфейса: ''sysfs'' и ''chardev'' (начиная с версии ядра 4.8). | В настоящий момент, для работы с gpio в userspace доступны 2 интерфейса: ''sysfs'' и ''chardev'' (начиная с версии ядра 4.8). | ||
<!--T: | <!--T:21--> | ||
Различия между ''chardev'' и ''sysfs'' хорошо описаны в [https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ этой статье]. Sysfs имеет статус deprecated, поэтому, по возможности, стоит работать через chardev. | Различия между ''chardev'' и ''sysfs'' хорошо описаны в [https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ этой статье]. Sysfs имеет статус deprecated, поэтому, по возможности, <u>стоит работать через chardev</u>. | ||
===Интерфейс sysfs===<!--T: | ===Интерфейс sysfs===<!--T:22--> | ||
<!--T: | <!--T:23--> | ||
Для работы через sysfs c определённым GPIO его надо экспортировать: | Для работы через sysfs c определённым GPIO его надо экспортировать: | ||
<!--T: | <!--T:24--> | ||
Здесь и далее N - номер gpio | Здесь и далее N - номер gpio | ||
<!--T: | <!--T:25--> | ||
<pre> | <pre> | ||
echo N > /sys/class/gpio/export | echo N > /sys/class/gpio/export | ||
</pre> | </pre> | ||
<!--T: | <!--T:26--> | ||
Экспортированные gpio появляются в каталоге /sys/class/gpio : | Экспортированные gpio появляются в каталоге /sys/class/gpio : | ||
<!--T: | <!--T:27--> | ||
<pre> | <pre> | ||
root@wirenboard:~# ls -1 /sys/class/gpio/ | root@wirenboard:~# ls -1 /sys/class/gpio/ | ||
Строка 103: | Строка 114: | ||
</pre> | </pre> | ||
<!--T: | <!--T:28--> | ||
В директории <b>/sys/class/gpioN</b> теперь находятся файлы для работы с GPIO (где N - номер GPIO, как и было сказано ранее): | В директории <b>/sys/class/gpioN</b> теперь находятся файлы для работы с GPIO (где N - номер GPIO, как и было сказано ранее): | ||
<!--T: | <!--T:29--> | ||
<pre> | <pre> | ||
root@wirenboard:~# ls -1 /sys/class/gpio/gpioN/ | root@wirenboard:~# ls -1 /sys/class/gpio/gpioN/ | ||
Строка 119: | Строка 130: | ||
</pre> | </pre> | ||
<!--T: | <!--T:30--> | ||
Установка направления GPIO (ввод/вывод) производится с помощью записи в файл <b>direction</b> | Установка направления GPIO (ввод/вывод) производится с помощью записи в файл <b>direction</b> | ||
<!--T: | <!--T:31--> | ||
<pre> | <pre> | ||
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод | echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод | ||
Строка 128: | Строка 139: | ||
</pre> | </pre> | ||
<!--T: | <!--T:32--> | ||
Чтение и установка значения GPIO производится с помощью файла <b>value</b>. | Чтение и установка значения GPIO производится с помощью файла <b>value</b>. | ||
<!--T: | <!--T:33--> | ||
Чтение: | Чтение: | ||
<!--T: | <!--T:34--> | ||
<pre> | <pre> | ||
echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод | echo in > /sys/class/gpio/gpioN/direction # установим GPIO номер N на ввод | ||
Строка 140: | Строка 151: | ||
</pre> | </pre> | ||
<!--T: | <!--T:35--> | ||
Запись: | Запись: | ||
<!--T: | <!--T:36--> | ||
<pre> | <pre> | ||
echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод | echo out > /sys/class/gpio/gpioN/direction # установим GPIO номер N на вывод | ||
Строка 150: | Строка 161: | ||
</pre> | </pre> | ||
<!--T: | <!--T:37--> | ||
Пример: | Пример: | ||
# Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице [[GPIO|WB2.8]]. Для клеммника номер 2 в версии 2.8 это GPIO 32. | # Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице [[GPIO|WB2.8]]. Для клеммника номер 2 в версии 2.8 это GPIO 32. | ||
Строка 162: | Строка 173: | ||
#:<pre>root@wirenboard:~# echo 0 > /sys/class/gpio/gpio32/value</pre> | #:<pre>root@wirenboard:~# echo 0 > /sys/class/gpio/gpio32/value</pre> | ||
====Работа с прерываниями====<!--T: | ====Работа с прерываниями====<!--T:38--> | ||
<!--T: | <!--T:39--> | ||
Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора. | Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора. | ||
<!--T: | <!--T:40--> | ||
Установка прерывания производится путём записи значения в файл "edge". Значения могут быть: | Установка прерывания производится путём записи значения в файл "edge". Значения могут быть: | ||
* "none" - отключить прерывание | * "none" - отключить прерывание | ||
Строка 174: | Строка 185: | ||
* "both" - включить прерывание по обеим фронтам. | * "both" - включить прерывание по обеим фронтам. | ||
<!--T: | <!--T:41--> | ||
Пример работы с прерываниями: | Пример работы с прерываниями: | ||
<pre> | <pre> | ||
Строка 186: | Строка 197: | ||
26: 76 gpio-mxs 3 gpiolib | 26: 76 gpio-mxs 3 gpiolib | ||
<!--T: | <!--T:42--> | ||
</pre> | </pre> | ||
<!--T: | <!--T:43--> | ||
Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value. | Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value. | ||
Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs] | Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs] | ||
<!--T: | <!--T:44--> | ||
См. также [http://elinux.org/GPIO elinux.org] | См. также [http://elinux.org/GPIO elinux.org] | ||
===Работа через chardev===<!--T: | ===Работа через chardev===<!--T:45--> | ||
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку libgpiod и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod]. | |||
<!--T:46--> | |||
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod]. | |||
<!--T: | <!--T:47--> | ||
Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev'' для debian buster и новее. К сожалению, для stretch пакетов в | Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev'' для debian buster и новее. К сожалению, '''для stretch пакетов в официальных репозиториях нет'''. | ||
<!--T: | <!--T:48--> | ||
Если нужно установить libgpiod в debian stretch, можно воспользоваться сторонними репозиториями (например, [https://github.com/rcn-ee/repos этим]). '''Используйте сторонние репозитории на свой страх и риск; компания WirenBoard не контролирует их содержимое'''. | Если нужно установить libgpiod в debian stretch, можно воспользоваться сторонними репозиториями (например, [https://github.com/rcn-ee/repos этим]). '''Используйте сторонние репозитории на свой страх и риск; компания WirenBoard не контролирует их содержимое'''. | ||
<!--T: | <!--T:49--> | ||
Для работы с gpio из bash в пакете ''gpiod'' поставляются следующие утилиты: | Для работы с gpio из bash в пакете ''gpiod'' поставляются следующие утилиты: | ||
* gpiodetect - информация обо всех банках gpio в системе | * gpiodetect - информация обо всех банках gpio в системе | ||
Строка 214: | Строка 227: | ||
* gpiomon - отслеживание событий gpio | * gpiomon - отслеживание событий gpio | ||
<!--T: | <!--T:50--> | ||
Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod] | Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod] | ||
== | ==Python==<!--T:51--> | ||
<!--T: | <!--T:52--> | ||
Для управления gpio из python был написан модуль wb_common.gpio, представляющий собой обёртку вокруг sysfs. Исходный код доступен [https://github.com/wirenboard/wb-common/blob/master/wb_common/gpio.py на нашем github.] | Для управления gpio из python был написан модуль <pre>wb_common.gpio</pre>, представляющий собой обёртку вокруг sysfs. Исходный код доступен [https://github.com/wirenboard/wb-common/blob/master/wb_common/gpio.py на нашем github.] | ||
Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах. | Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах. | ||
===Прямое обращение через память процессора===<!--T: | ===Прямое обращение через память процессора===<!--T:53--> | ||
<!--T: | <!--T:54--> | ||
<b>Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs или chardev, как описано в предыдущих разделах</b>. | <b>Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs или chardev, как описано в предыдущих разделах</b>. | ||
<!--T: | <!--T:55--> | ||
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать, | Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать, | ||
если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. | если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. | ||
Рекомендуется выносить критичные ко времени задачи в ядро. | Рекомендуется выносить критичные ко времени задачи в ядро. | ||
<!--T: | <!--T:56--> | ||
См. [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] | См. [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] | ||
=Работа | =Работа в ядре Linux=<!--T:57--> | ||
Ознакомиться с ядром Linux, использующимся в контроллерах WirenBoard можно в нашем [https://github.com/wirenboard/linux репозитории ядра]. | |||
===Рекомендации по Device Tree=== <!--T: | ===Рекомендации по Device Tree=== <!--T:58--> | ||
<!--T: | <!--T:59--> | ||
Device-tree, использующиеся на контроллерах WirenBoard, доступны в репозитории ядра. | |||
Разные аппаратные ревизии контроллера используют разные dts (например, dts для WB6.X можно найти [https://github.com/wirenboard/linux/blob/dev/v4.9.x/arch/arm/boot/dts/imx6ul-wirenboard61.dts здесь]) | |||
<!--T: | <!--T:60--> | ||
Указывать GPIO в Device Tree необходимо для настройки работы GPIO в режиме программного SPI, I2C, для использования GPIO в качестве источника прерываний и т.д. | Указывать GPIO в Device Tree необходимо для настройки работы GPIO в режиме программного SPI, I2C, для использования GPIO в качестве источника прерываний и т.д. | ||
Так, например, на пин 10@UEXT1 (CS) и пины 5@UEXT2 (SCL), 6@UEXT2 (SDA), 10@UEXT2 (CS) выведены линии GPIO процессора. Их можно сконфигурировать для использования, например, в качестве chip-select для SPI или в качестве I2C. | Так, например, на пин 10@UEXT1 (CS) и пины 5@UEXT2 (SCL), 6@UEXT2 (SDA), 10@UEXT2 (CS) выведены линии GPIO процессора. Их можно сконфигурировать для использования, например, в качестве chip-select для SPI или в качестве I2C. | ||
<!--T: | <!--T:61--> | ||
GPIO процессора и периферийных устройств разбиты на банки (gpiochip). GPIO процессора разбиты на 3 банка по 32 GPIO: gpio0, gpio1, gpio2. Адресация GPIO в Device Tree происходит по номеру банка и номеру GPIO *внутри* банка. | GPIO процессора и периферийных устройств разбиты на банки (gpiochip). GPIO процессора разбиты на 3 банка по 32 GPIO: gpio0, gpio1, gpio2. Адресация GPIO в Device Tree происходит по номеру банка и номеру GPIO *внутри* банка. | ||
====Пример | ====Пример device-tree node==== <!--T:62--> | ||
<!--T: | <!--T:63--> | ||
Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице [[Special:MyLanguage/Список GPIO|Список GPIO]], сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 : | Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице [[Special:MyLanguage/Список GPIO|Список GPIO]], сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 : | ||