Работа с GPIO: различия между версиями
Vdromanov (обсуждение | вклад) |
|||
(не показаны 22 промежуточные версии 4 участников) | |||
Строка 1: | Строка 1: | ||
<languages/> | |||
<translate> | |||
=Страница находится в процессе редактирования!!=<!--T:40--> | |||
<!--T:4--> | |||
<b> Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V. Ни в коем случае не подключайте к GPIO напрямую сигналы, напряжением больше 3.3V! В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более </b> | |||
<!--T:1--> | |||
В Wiren Board часть GPIO выведена на клеммники, часть выведена на разъёмы расширения, часть используется для служебных целей. | |||
GPIO также используются для управления транзисторами для коммутации низковольтной нагрузки. | |||
<!--T:2--> | |||
Соответствие между номерами GPIO в Linux и их местоположением и функцией можно найти в статье [[GPIO]]. | |||
=Именование gpio=<!--T:6--> | |||
К сожалению, четкого стандарта по именованию gpio не существует, и формирование номеров gpio зависит от производителей процессоров (а точнее - от разработчиков SDK для них). В контроллерах WirenBoard используются следующие правила: | |||
* выводы gpio сгруппированы по банкам (banks; эквивалентно gpiochips) | |||
* каждый банк содержит 32 gpio. Нумерация банков начинается с 0. | |||
= | ==Вычисление номера gpio==<!--T:6--> | ||
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio A1_IN контроллера WB6.7 (номер: 109; gpio3_io13): | |||
=Работа из userspace= | |||
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio | <!--T:7--> | ||
< | Вычислим банк gpio и offset, зная номер (109): | ||
<pre> | |||
# Поделим 109 на 32. Целая часть - номер банка, остаток - offset: | |||
109.0 / 32.0 = 3, остаток 13 | |||
</pre> | |||
=Работа из userspace=<!--T:6--> | |||
Перед началом работы из userspace, необходимо убедиться, в том, что нужный gpio не занят ядром. Для этого можно посмотреть на вывод команды | |||
<pre> | |||
cat /sys/kernel/debug/gpio | cat /sys/kernel/debug/gpio | ||
</ | </pre> | ||
В выводе команды видим примерно следующее: | В выводе команды видим примерно следующее: | ||
< | <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: | Строка 46: | ||
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 и недоступны для использования. | |||
Если | <!--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: | Строка 89: | ||
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: | Строка 105: | ||
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) | ||
0 | 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> |
Версия 12:43, 26 марта 2021
Страница находится в процессе редактирования!!
Все GPIO (как и остальные порты Wiren Board) работают с напряжением 3.3V. Ни в коем случае не подключайте к GPIO напрямую сигналы, напряжением больше 3.3V! В случае необходимости подключения устройств, работающих с более высоким напряжением, необходимо использовать схемы согласования или подключать (для 5V) через резистор в 20 кОм и более
В Wiren Board часть GPIO выведена на клеммники, часть выведена на разъёмы расширения, часть используется для служебных целей. GPIO также используются для управления транзисторами для коммутации низковольтной нагрузки.
Соответствие между номерами GPIO в Linux и их местоположением и функцией можно найти в статье GPIO.
Именование gpio
К сожалению, четкого стандарта по именованию gpio не существует, и формирование номеров gpio зависит от производителей процессоров (а точнее - от разработчиков SDK для них). В контроллерах WirenBoard используются следующие правила:
- выводы gpio сгруппированы по банкам (banks; эквивалентно gpiochips)
- каждый банк содержит 32 gpio. Нумерация банков начинается с 0.
Вычисление номера gpio
Для управления ножкой gpio нужно знать её номер. В рассматриваемых примерах будем работать с gpio A1_IN контроллера WB6.7 (номер: 109; gpio3_io13):
Вычислим банк gpio и offset, зная номер (109):
# Поделим 109 на 32. Целая часть - номер банка, остаток - offset: 109.0 / 32.0 = 3, остаток 13
Работа из 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 нужны по каким-то причинам, то нужно остановить драйвер:
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>; };