Работа с GPIO: различия между версиями
(не показаны 4 промежуточные версии этого же участника) | |||
Строка 56: | Строка 56: | ||
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod]. | Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod]. | ||
Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev''. | Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev'' для debian buster и новее. К сожалению, '''для stretch пакетов в официальных репозиториях нет'''. | ||
Если нужно установить libgpiod в debian stretch, можно воспользоваться сторонними репозиториями (например, [https://github.com/rcn-ee/repos этим]). '''Используйте сторонние репозитории на свой страх и риск; компания WirenBoard не контролирует их содержимое'''. | |||
Для работы с gpio в пакете ''gpiod'' поставляются следующие утилиты: | Для работы с gpio из bash в пакете ''gpiod'' поставляются следующие утилиты: | ||
* <code>gpiodetect</code> — информация обо всех банках gpio в системе | * <code>gpiodetect</code> — информация обо всех банках gpio в системе | ||
* <code>gpioinfo</code> — подробная информация обо всех линиях gpio определённого банка | * <code>gpioinfo</code> — подробная информация обо всех линиях gpio определённого банка | ||
Строка 70: | Строка 68: | ||
* <code>gpiomon</code> — отслеживание событий gpio | * <code>gpiomon</code> — отслеживание событий gpio | ||
Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod] | |||
Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod] | |||
===Интерфейс sysfs=== | ===Интерфейс sysfs=== | ||
Строка 164: | Строка 147: | ||
echo 0 > /sys/class/gpio/gpio32/value | echo 0 > /sys/class/gpio/gpio32/value | ||
</syntaxhighlight> | </syntaxhighlight> | ||
====Работа с прерываниями==== | ====Работа с прерываниями==== | ||
Строка 228: | Строка 182: | ||
Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах. | Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах. | ||
==Прямое обращение через память процессора== | |||
<b>Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs или chardev, как описано в предыдущих разделах</b>. | |||
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать, | |||
если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. | |||
Рекомендуется выносить критичные ко времени задачи в ядро. | |||
Обратитесь в техподдержку за дальнейшей консультацией. | |||
=Работа в ядре Linux= | |||
Ознакомиться с ядром Linux, использующимся в контроллерах WirenBoard можно в нашем [https://github.com/wirenboard/linux репозитории ядра]. | |||
===Рекомендации по Device Tree=== | |||
Device-tree, использующиеся на контроллерах WirenBoard, доступны в репозитории ядра. | |||
Разные аппаратные ревизии контроллера используют разные dts (например, dts для WB6.X можно найти [https://github.com/wirenboard/linux/blob/dev/v4.9.x/arch/arm/boot/dts/imx6ul-wirenboard61.dts здесь]) | |||
Указывать 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 *внутри* банка. | |||
====Пример device-tree node==== | |||
Определим сигнал 6@UEXT2 (SDA) в качестве источника прерываний для драйвера mrf24j40. Согласно таблице [[Список GPIO]], сигнал соответствует GPIO 53 процессора. 53 принадлежит второму банку gpio (от 32 до 63). Номер GPIO внутри банка 53-32=21 : | |||
<syntaxhighlight lang="json"> | |||
6lowpan@0 { | |||
compatible = "microchip,mrf24j40"; | |||
spi-max-frequency = <100000>; | |||
reg = <6>; | |||
interrupt-parent = <&gpio1>; | |||
interrupts = <21 0>; | |||
}; | |||
</syntaxhighlight> |
Версия 17:36, 24 декабря 2022
ВНИМАНИЕ: статья рассчитана на разработчиков или опытных пользователей и даёт общие рекомендации того, как использовать 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 для debian buster и новее. К сожалению, для stretch пакетов в официальных репозиториях нет.
Если нужно установить libgpiod в debian stretch, можно воспользоваться сторонними репозиториями (например, этим). Используйте сторонние репозитории на свой страх и риск; компания WirenBoard не контролирует их содержимое.
Для работы с gpio из bash в пакете gpiod поставляются следующие утилиты:
gpiodetect
— информация обо всех банках gpio в системеgpioinfo
— подробная информация обо всех линиях gpio определённого банкаgpioget <чип> <линия>
— возвращает значение определённого gpiogpioset <чип> <линия1>=<значение1> <линия2>=<значение2>
— устанавливает состояние на определенные линии gpiogpiofind <название>
— возвращает номер gpiogpiomon
— отслеживание событий gpio
Примеры использования 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
Пример:
- Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице WB2.8. Для клеммника номер 2 в версии 2.8 это GPIO 32.
- Экспортируем GPIO в sysfs
echo 32 > /sys/class/gpio/export
- Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
echo out > /sys/class/gpio/gpio32/direction
- Открываем транзистор, подавая логический высокий уровень на затвор:
echo 1 > /sys/class/gpio/gpio32/value
- Закрываем транзистор, подавая логический ноль на затвор:
echo 0 > /sys/class/gpio/gpio32/value
Работа с прерываниями
Через интерфейс 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 в синхронном и асинхронном (с регистрацией коллбэков) режимах.
Прямое обращение через память процессора
Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs или chardev, как описано в предыдущих разделах.
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать, если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. Рекомендуется выносить критичные ко времени задачи в ядро.
Обратитесь в техподдержку за дальнейшей консультацией.
Работа в ядре Linux
Ознакомиться с ядром Linux, использующимся в контроллерах WirenBoard можно в нашем репозитории ядра.
Рекомендации по Device Tree
Device-tree, использующиеся на контроллерах WirenBoard, доступны в репозитории ядра. Разные аппаратные ревизии контроллера используют разные dts (например, dts для WB6.X можно найти здесь)
Указывать 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 *внутри* банка.
Пример device-tree node
Определим сигнал 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>;
};