Перейти к содержанию

Навигация

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

Нет описания правки
 
(не показано 8 промежуточных версий этого же участника)
Строка 13: Строка 13:


=Именование gpio=
=Именование gpio=
К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил:
К сожалению, четкого стандарта по именованию gpio не существует. Номера, смещения и названия gpiochip стоит брать в таблицах: [[GPIO | Таблицы GPIO разных версий контроллера]].
* выводы gpio сгруппированы по банкам (''banks''; эквивалентно ''gpiochips'')
* каждый банк содержит 32 gpio. Нумерация банков начинается с 0.
 
==Вычисление номера gpio==
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio ''A1_IN'' контроллера WB6.7 (''номер: 109; gpiochip 3, offset 13''):
Вычислим банк gpio и offset, зная номер (109):
<syntaxhighlight lang="bash">
# Поделим 109 на 32. Целая часть — номер банка, остаток - offset:
109.0 / 32.0 = 3, остаток 13
</syntaxhighlight>
 
То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio:
<syntaxhighlight lang="bash">
# Умножим номер банка на 32 и прибавим offset:
3 * 32 + 13 = 109
</syntaxhighlight>


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


В контроллерах Wiren Board доступные к использованию gpio обычно заняты сервисом wb-mqtt-gpio. Остановить его можно так:
<syntaxhighlight lang="bash">
systemctl stop wb-mqtt-gpio
</syntaxhighlight>
==Bash==
==Bash==


Строка 63: Строка 51:


Различия между ''chardev'' и ''sysfs'' хорошо описаны в [https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ этой статье]. Sysfs имеет статус deprecated, поэтому, по возможности, <u>стоит работать через chardev</u>.
Различия между ''chardev'' и ''sysfs'' хорошо описаны в [https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ этой статье]. Sysfs имеет статус deprecated, поэтому, по возможности, <u>стоит работать через chardev</u>.
===Работа через chardev===
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod].
Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev''. Установка:
<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===
===Интерфейс sysfs===
Строка 141: Строка 164:
echo 0 > /sys/class/gpio/gpio32/value
echo 0 > /sys/class/gpio/gpio32/value
</syntaxhighlight>
</syntaxhighlight>
====Номера GPIO====
Наиболее унивверсальный способ получить номер GPIO для устаревшего интерфейса sysfs - получить его по метке GPIO.
Для этого нужно найти номер gpiochip, смещение внутри gpiochip и базовый адрес gpiochip.
Пример:
<syntaxhighlight lang="bash">
~# gpiofind "A1 OUT"
gpiochip0 109
~# cat /sys/class/gpio/gpiochip0/base
0
</syntaxhighlight>
Т.е. для A1 OUT будет старый номер 0 (base) + 109 (offset) = 109.
Номера по метке можно получить также через отладочный интерфейс ядра. Это не требует использования утилит gpiod, но формат вывода может быть изменён в новых версиях ядра. "Старый" (глобальный) номер указан в первом столбце:
<syntaxhighlight lang="bash">
~# cat /sys/kernel/debug/gpio  | grep "A1 OUT"
gpio-109 (A1 OUT              |wb-mqtt-gpio        ) out lo
</syntaxhighlight>
GPIO для дискретных входов и выходов модулей расширения и модулей ввода-вывода доступны таким же образом. Не забудьте выбрать модуль в интерфейсе Hardware Modules Configuration.


====Работа с прерываниями====
====Работа с прерываниями====
Строка 169: Строка 221:
См. также [http://elinux.org/GPIO elinux.org]
См. также [http://elinux.org/GPIO elinux.org]


===Работа через chardev===
Представленный в ядре 4.8 интерфейс chardev имеет C/Python библиотеку ''libgpiod'' и userspace-утилиты для работы с gpio. Исходный код библиотеки и документация доступны в [https://github.com/brgl/libgpiod репозитории libgpiod].
Утилиты распространяются в составе debian-пакетов ''gpiod'' и ''libgpiod-dev'' для debian buster и новее. К сожалению, '''для stretch пакетов в официальных репозиториях нет'''.
Если нужно установить libgpiod в debian stretch, можно воспользоваться сторонними репозиториями (например, [https://github.com/rcn-ee/repos этим]). '''Используйте сторонние репозитории на свой страх и риск; компания WirenBoard не контролирует их содержимое'''.
Для работы с gpio из bash в пакете ''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
Примеры использования gpiod можно посмотреть в [https://www.acmesystems.it/gpiod] и [https://github.com/brgl/libgpiod]


==Python==
==Python==
Строка 193: Строка 228:


Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.
Модуль позволяет работать с gpio в синхронном и асинхронном (с регистрацией коллбэков) режимах.
==Прямое обращение через память процессора==
<b>Этот метод настоятельно НЕ РЕКОМЕНДУЕТСЯ для использования без достаточных оснований. Для работы из С/C++ стоит использовать работу через файлы в sysfs или chardev, как описано в предыдущих разделах</b>.
Управлять GPIO можно с помощью прямого доступа к регистрам процессора, в обход Linux, через интерфейс /dev/mem. При этом, по сравнению с работой через sysfs минимизируются накладные расходы. Этот метод можно использовать,
если вам необходим очень быстрый доступ к GPIO, например bitbang протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки.
Рекомендуется выносить критичные ко времени задачи в ядро.
См. [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=
Ознакомиться с ядром 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>