Работа с GPIO: различия между версиями
Vdromanov (обсуждение | вклад) |
|||
(не показано 18 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
<languages/> | |||
<translate> | |||
<!--T:1--> | |||
В Wiren Board часть GPIO выведена на клеммники, часть выведена на разъёмы расширения, часть используется для служебных целей. | |||
GPIO также используются для управления транзисторами для коммутации низковольтной нагрузки. | |||
<!--T:4--> | |||
<b> Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V. Ни в коем случае не подключайте к GPIO напрямую сигналы, напряжением больше 3.3V! В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более </b> | |||
<!--T:2--> | |||
Соответствие между номерами GPIO в Linux и их местоположением и функцией можно найти в статье [[GPIO]]. | |||
= | =Именование gpio=<!--T:6--> | ||
* ''' | К сожалению, четкого стандарта по именованию gpio не существует, но при работе с контроллерами WirenBoard стоит придерживаться следующих правил: | ||
* выводы gpio сгруппированы по банкам (''banks''; эквивалентно ''gpiochips'') | |||
* | * каждый банк содержит 32 gpio. Нумерация банков начинается с 0. | ||
В | ==Вычисление номера gpio==<!--T:6--> | ||
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio ''A1_IN'' контроллера WB6.7 (номер: 109; gpiochip 3, offset 13): | |||
<!--T:7--> | |||
Вычислим банк gpio и offset, зная номер (109): | |||
<pre> | |||
# Поделим 109 на 32. Целая часть - номер банка, остаток - offset: | |||
109.0 / 32.0 = 3, остаток 13 | |||
</pre> | |||
=Работа из userspace= | То же самое справедливо и наоборот. Зная банк и offset (3 и 13, соответственно), можно вычислить номер gpio: | ||
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio | <pre> | ||
< | # Умножим номер банка на 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 | ||
</ | </pre> | ||
<!--T:7--> | |||
В выводе команды видим примерно следующее: | В выводе команды видим примерно следующее: | ||
< | <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 | ||
</ | </pre> | ||
Это значит, что gpio 0, 26 и 27 уже экспортированы в sysfs и доступны для управления. Gpio 11 и 13 заняты ядерным драйвером onewire и недоступны для использования. Остальные gpio банка 0 доступны для экспорта. | |||
<!--T:7--> | |||
Если эти gpio нужны по каким-то причинам, то нужно остановить драйвер: | |||
Если | <pre> | ||
< | |||
lsmod | grep w1 # узнаем название драйвера | lsmod | grep w1 # узнаем название драйвера | ||
rmmod w1_gpio # выгружаем драйвер, название которого узнали | rmmod w1_gpio # выгружаем драйвер, название которого узнали | ||
</ | </pre> | ||
До следующей перезагрузки контроллера желаемый gpio свободен! | |||
==Интерфейс sysfs в Linux==<!--T:6--> | |||
<!--T:7--> | |||
GPIO в Linux поддерживаются через sysfs-интерфейс. | |||
<!--T:8--> | |||
Для работы через sysfs c определённым GPIO его надо экспортировать: | Для работы через sysfs c определённым GPIO его надо экспортировать: | ||
Здесь и далее N | <!--T:9--> | ||
Здесь и далее N - номер gpio | |||
< | <!--T:10--> | ||
<pre> | |||
echo N > /sys/class/gpio/export | echo N > /sys/class/gpio/export | ||
</ | </pre> | ||
Экспортированные gpio появляются в каталоге | <!--T:11--> | ||
< | Экспортированные 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 | ||
</ | </pre> | ||
В директории < | <!--T:13--> | ||
В директории <b>/sys/class/gpioN</b> теперь находятся файлы для работы с GPIO (где N - номер GPIO, как и было сказано ранее): | |||
< | <!--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 | ||
</ | </pre> | ||
Установка направления GPIO (ввод/вывод) производится с помощью записи в файл < | <!--T:15--> | ||
Установка направления GPIO (ввод/вывод) производится с помощью записи в файл <b>direction</b> | |||
< | <!--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 на вывод | ||
</ | </pre> | ||
Чтение и установка значения GPIO производится с помощью файла < | <!--T:17--> | ||
Чтение и установка значения GPIO производится с помощью файла <b>value</b>. | |||
<!--T:18--> | |||
Чтение: | Чтение: | ||
< | |||
<!--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> | ||
<!--T:20--> | |||
Запись: | Запись: | ||
< | |||
<!--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> | ||
<!--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> | ||
echo 32 > /sys/class/gpio/export | |||
</ | |||
# Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии. | # Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии. | ||
#:< | #:<pre>root@wirenboard:~# echo out > /sys/class/gpio/gpio32/direction</pre> | ||
echo out > /sys/class/gpio/gpio32/direction | |||
</ | |||
# Открываем транзистор, подавая логический высокий уровень на затвор: | # Открываем транзистор, подавая логический высокий уровень на затвор: | ||
#:< | #:<pre>root@wirenboard:~# echo 1 > /sys/class/gpio/gpio32/value</pre> | ||
echo 1 > /sys/class/gpio/gpio32/value | |||
</ | |||
# Закрываем транзистор, подавая логический ноль на затвор: | # Закрываем транзистор, подавая логический ноль на затвор: | ||
#:< | #:<pre>root@wirenboard:~# echo 0 > /sys/class/gpio/gpio32/value</pre> | ||
echo 0 > /sys/class/gpio/gpio32/value | |||
</ | |||
==== | ===Работа с прерываниями===<!--T:22--> | ||
<!--T:23--> | |||
Через интерфейс sysfs можно запросить прерывания по изменению состояния процессора. | |||
< | <!--T:24--> | ||
Установка прерывания производится путём записи значения в файл "edge". Значения могут быть: | |||
* "none" - отключить прерывание | |||
* "rising" - включить прерывание по нисходящему фронту | |||
* "falling" - включить прерывание по восодящему фронту | |||
* "both" - включить прерывание по обеим фронтам. | |||
<!--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 | |||
<!--T:26--> | |||
</pre> | |||
<!--T:27--> | |||
Прерывания можно ловить из userspace с помощью системного вызова epoll() и select() на файл value. | |||
Пример работы см. [https://github.com/contactless/wiegand-linux-sysfs] | |||
< | <!--T:28--> | ||
См. также [http://elinux.org/GPIO elinux.org] | |||
==Работа через официальное ПО==<!--T:29--> | |||
==Работа из 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 протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. | |||
Рекомендуется выносить критичные ко времени задачи в ядро. | |||
<!--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] | |||
=Работа из ядра Linux=<!--T:44--> | |||
===GPIO и Device Tree=== <!--T:33--> | |||
<!--T:5--> | |||
На некоторых 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--> | |||
GPIO процессора и периферийных устройств разбиты на банки (gpiochip). GPIO процессора разбиты на 3 банка по 32 GPIO: gpio0, gpio1, gpio2. Адресация GPIO в Device Tree происходит по номеру банка и номеру GPIO *внутри* банка. | |||
== | ====Пример 1==== <!--T:36--> | ||
<!--T:37--> | |||
Определим сигнал 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> |
Версия 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
Пример:
- Находим номер GPIO, соответсвующий вашей версии контролера нужному клеммнику в таблице WB2.8. Для клеммника номер 2 в версии 2.8 это GPIO 32.
- Экспортируем GPIO в sysfs
root@wirenboard:~# echo 32 > /sys/class/gpio/export
- Устанавливаем GPIO в режим вывода для управления транзистором. Это обязательно, т.к. GPIO может находится в режиме ввода и иметь высокий импенданс, оставляя транзистор в неопределённом состоянии.
root@wirenboard:~# echo out > /sys/class/gpio/gpio32/direction
- Открываем транзистор, подавая логический высокий уровень на затвор:
root@wirenboard:~# echo 1 > /sys/class/gpio/gpio32/value
- Закрываем транзистор, подавая логический ноль на затвор:
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 протоколов или ШИМ. Стоит иметь в виду, что планировщик процессов всё ещё может вносить в работу программы значительные задержки. Рекомендуется выносить критичные ко времени задачи в ядро.
Работа из ядра 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>; };