Работа с GPIO на примере Banana Pi BPI-M64. Часть 1. Интерфейс sysfs LED и DS18B20

Banana Pi BPI-M64 sysfs led ds18b20

Начиная с версии ядра 2.6.26, в Linux появился стандартный интерфейс для работы с контактами GPIO(general-purpose input/output — интерфейс ввода/вывода общего назначения) через виртуальную файловую систему sysfs. Работа с GPIO проходит через каталог /sys/class/gpio путём обращения к файлам-устройствам. В публикации приводится пример включение  и выключение светодиода, и получение значения температуры от датчика DS18B20 по 1-Wire интерфейсу.

Что такое GPIO

GPIO (general-purpose input/output) — Интерфейс ввода/вывода общего назначения. GPIO подключены напрямую к «процессору» SoC (System-on-a-Chip — Система на кристалле), и неправильное использование может вывести его из строя.
Большинство одноплатных компьютеров, кроме обычных двунаправленных Input/Output портов, имеют один или более интерфейсов: UARTSPII²C/TWIPWM (ШИМ), но не имеют ADC (АЦП).

GPIO — порты обычно могут быть сконфигурированны на ввод или вывод (Input/Output), состояние по умолчанию обычно INPUT.

Некоторые «GPIO»-порты — являются просто питающими портами 3.3V, 5V и GND, они не связаны с SoC и не могут использоваться как либо еще.

Порты с альтернативной функцией — могут быть мультиплексированны с одним из соответствующих ему интерфейсов.

Некоторые выводы могут иметь подтягивающие pullup и pulldown резисторы, на некоторых портах они могут быть включены по умолчанию. Во время загрузки ОС и инициализации драйверов — состояния портов могут меняться.
Порты в режиме INPUT могут генерировать прерывания — по спаду, по фронту, по логическому уровню, по изменению сигнала и в асинхронном режиме по фронту и спаду. Порты в режиме INPUT имеют входную фильтрацию на триггере Шмитта (преобразовывают аналоговый сигнал в цифровой с резкими переходами между состояниями).

Электрические характеристики GPIO (Electrical Specification)

У любого порта — есть «ограничения» по току и напряжению. А т.к. GPIO — это просто выводы чипа SoC — очень важно знать и соблюдать эти характеристики. Вы всегда можете узнать их в документации на SoC (ссылка на документацию Allwinner A64).

GPIO на Allwinner A64 имеет следующие характеристики:

  • 20 mA — рекомендуемый максимальный ток GPIO на один цифровой контакт (digital pin);
  • 40 mA — максимально допустимый ток GPIO на один цифровой контакт (digital pin);
  • 3.3V — максимальное рекомендуемое входное/выходное напряжение GPIO;
  • 3.6V — максимальное предельное входное/выходное напряжение GPIO;
  • 1.08V — максимальный уровень логического 0 для линии 3.3V;
  • 2.1V — минимальный уровень логической 1 для линии 3.3V;
  • 3.6V — максимальный уровень логической 1 для линии 3.3V;

Выводы 3.3V — могут давать ток до 100mA, т.к. они фактически не являются GPIO портами, а практически напрямую соединены с питанием всей платы (а не чипа SoC). Максимальный ток вывода на 5.3V в спецификации к плате не был найден.

Все электрические характеристики можно найти в Allwinner_A64_Datasheet_V1.1 разделы 5. Electrical Characteristics. Основные таблицы с 5.1. Absolute Maximum Ratings по 5.5. Electrical Characteristics for Power Supply.

При проектировании устройств в которых используется большое количество датчиков нужно обязательно делать развязку через дополнительные буферные схемы, преобразователи уровня напряжений (логических уровней), электронные ключи и т.д.

Плата Banana Pi BPI-M64

Для дальнейшей работы с GPIO необходимо получить datasheet на SoC и плату. Рассмотрим datasheet Banana Pi BPI-M64 и SoC AllWinner A64, затем поработает с GPIO через sysfs.

Banana Pi BPI-M64

Banana Pi BPI-M64 — это 64-битный четырехъядерный мини-одноплатный компьютер, поставляемый как решение с открытым исходном кодом. Ядром системы является процессор Allwinner A64 с 4-мя ядрами Cortex-A53 с частотой 1.2 ГГц. На плате размещено 2 ГБ DDR3 SDRAM 733МГц оперативной памяти и 8 ГБ eMMC. Также есть встроенный WiFi (AP6212) и BT4.0 (AP6212), Ethernet 10/100/1000 Мбит (Realtek RTL8211E/D). Видеоускоритель GPU Mali 400 MP2 поддерживает видео 1080P 4K. Более подробно можно почитать по ссылке.

Из спецификации представляет интерес, то что на плате размещен 40-контактный совместимый с Raspberry Pi разъем который содержит: GPIO (x28), Power (+5V, +3.3V and GND), UART, I2C, SPI. И 40-контактный интерфейс MIPI DSI.

SoC AllWinner A64

AllWinner A64 — встречается очень часто в бюджетных смартфонах, построен на ядре Cortex-A53. Более подробно можно почитать по ссылке. Из документации представляет интерес информация об интерфейсах: UART, I2C, SPI, PWM.

Процессор содержит:

PWM (ШИМ)

  • Поддержка вывода двух видов сигнала: непрерывного сигнала и импульсного сигнала.
  • Регулируемый рабочий цикл от 0% до 100%
  • Выходная частота до 24 МГц

UART

  • Шесть контроллеров UART
  • Два из шести контроллеров UART поддерживают 2-проводную схему, а другие — 4-проводную
  • 64-байтовые FIFO для передачи и приема данных для всех UART
  • Соответствует отраслевым стандартам 16550 UART
  • Поддержка Infrared Data Association (IrDA) 1.0 SIR
  • Поддержка скорости до 3 МГц

SPI

  • Два контроллера SPI
  • Полнодуплексный синхронный последовательный интерфейс
  • Настраиваемый ведущий/ведомый
  • Mode0 ~ 3 поддерживаются как для передачи, так и для приема.
  • Два 64-байтовых FIFO для работы SPI-TX и SPI-RX
  • Работа на основе DMA или прерываний
  • Полярность и фаза выбора кристалла (SPI_SS) и SPI_Clock (SPI_SCLK) настраиваются
  • Поддержка одиночного и двойного режима ввода-вывода

Two Wire Interface(TWI)/I2C

  • Четыре контроллеров TWI/I2C
  • Поддержка стандартного режима (до 100 Кбит/с) и быстрого режима (до 400 Кбит/с)
  • Настраиваемый Master/Slave
  • Позволяет 10-битные транзакции адресации
  • Выполнять арбитраж и синхронизацию часов
  • Может работать в широком диапазоне входных тактовых частот

Распиновка контактов GPIO

Большой плюс плат Banana Pi является наличие совместимого 40-контактного разъема Raspberry Pi 3.

Raspberry Pi GPIO Header

Позиция [1] 3V3 power соответствует позиции на плате со стрелочкой.

Banana Pi BPI-M64 GPIO Header Position

Banana Pi BPI-M64 GPIO Header Position

На 40-контактом разъеме Raspberry Pi определим какие из перечисленных интерфейсов нам доступны. На странице wiki опубликована спецификация 40-контактного разъема совместимого с Raspberry Pi 3. Совместим с данными WiringPi [BPI-WiringPi2], и получим сводную диаграмму:

Banana Pi BPI-M64 pinout diagram

Формула для вычисления номера GPIOXX
В схеме обозначены порядковые номера физических ножек процессора SoC, эти данные в спецификациях отсутствую, т.к. порядковый номер получаем путем простого расчета. Например, из схемы возьмем 32-контакт на  разъеме типа Raspberry Pi. Название контакта PB7, для получения номера контакта на процессоре произведем расчет по формуле:
(позиция буквы в алфавите — 1) * 32 + позиция вывода. Первая буква не учитывается т.к. P — PORT, позиция буквы B в алфавите = 2, получаем (2-1) * 32 + 7 = 39. Физический номер контакта PB7 является номер 39, его будем в дальнейшем использовать для управления GPIO через sysfs.

Banana Pi BPI-M64 GPIOXX
 

Программирование GPIO

Существует несколько способов обращения к GPIO:

  • Посредством файл-устройством GPIO;
  • Используя языки программирования:
    • Через прямое обращение к регистрам чипа;
    • Используя уже готовые библиотеки.

Каждый из методов имеет свои преимущества и недостатки.

Работа с GPIO как файл-устройство через интерфейс sysfs

Существует три типа записей в /sys/class/gpio:

  • Интерфейсы управления пользовательскими GPIO;
  • Сами GPIO;
  • Порты ввода-вывода (gpio_chip).

Для доступа к контакту GPIO необходимо его зарегистрировать в системе, для этого используются интерфейсы управления по пути /sys/class/gpio, доступны только на запись:

export — запрашивает экспорт управления GPIO пользователю с записью его номера в файл.
Например, команда echo 364 > /sys/class/gpio/export создаст файл-устройство gpio364.
unexport — отменяет экспорт.
Например, команда echo 364 > /sys/class/gpio/unexport удалит файл-устройство gpio364.

Контакты GPIO для управления доступны по пути /sys/class/gpio/gpioN, где N — номер контакта GPIO на процессоре и содержат атрибуты чтения/записи:

  • direction — направление, может принимать значения in (вход) или out (выход), как правило, пишется. Например, команда echo out > /sys/class/gpio/gpio364/direction установит направление на выход файл-устройство gpio364.
  • value — состояние, может принимать значение 0 (низкий) или 1 (высокий). Если GPIO настраивается на выход, то значение пишется. Ненулевое значение считается высоким. Например, команда echo 1 > /sys/class/gpio/gpio364/value установит состояние 1 Higth на выход файл-устройство gpio364.
  • edge — реакция на изменение состояния, может принимать значения none (нет), rising (фронт) falling (спад) или both (перепад), необходима поддержка прерывания (interrupt). Не все контакты GPIO поддерживают прерывания.
  • active_low Инвертирование значения value, может принимать значение 0 (нет) или 1 (да). Ненулевое значение считается единицей.

Порты GPIO располагаются по пути /sys/class/gpio/gpiochipN (для порта GPIO начиная с вывода #N) и имеют атрибуты только для чтения:

  • base — номер первого GPIO управляемого портом.
  • label — диагностическая метка, но здесь нет стандарта.
  • ngpio — сколько выводов GPIO управляется портом.

Практика

Для работы будем использовать дистрибутив Armbian. Все дальнейшие действия выполнялись в версии Armbian_20.08.2_Bananapim64_bionic_current_5.8.6_minimal.img.xz, основанной на Ubuntu 18.04.5 LTS Linux bananapim64 5.8.6-sunxi64 #20.08.2 SMP Fri Sep 4 08:52:31 CEST 2020 aarch64 aarch64 aarch64 GNU/Linux.

Возьмем:

  • Обычный светодиод, в данном случае используется Gravity: Digital Blue LED Light Module, лучше брать с отдельным питанием для снижение нагрузки на GPIO. Потребление светодиода по линии управления составляет 4.5 mA .  Если подобного светодиода нет в наличие, то можно взять любой другой с небольшой яркостью, и подключить его обязательно вместе с резистором в цепь, как на примере в Использование библиотеки WiringPi [BPI-WiringPi2] на Banana Pi BPI-M64.
  • Цифровой температурный датчик DS18B20 от DFRobot.com
    на 1-Wire интерфейсе, диапазон температур от -55 до +125 градусов Цельсия.

Схема подключения датчиков:

Подключим оба датчика к линии питания 3.3 V и земли GND. Контакт управления LED будет подключен к 32-контакту разъема  типа Raspberry Pi. Контакт 1-Wire датчика DS18B20 подключим к 18-контакту разъема  типа Raspberry Pi. Изобразим на схеме:
Banana Pi BPI-M64 led ds18b20
 

Управление светодиодом LED

Для получение ссылки управление необходимо экспортировать GPIO для создания файл-устройства т.к. для оперирования контактом через sysfs нужен не порядковый номер 32-pin на разъеме типа Raspberry Pi, а номер ножки на процессоре. Для этого воспользуемся THE UNOFFICIAL BANANA PI BPI-M64 (r.23.01.2021) PINOUT DIAGRAM. Исходя из данной схемы 32-контакт соответствует 39-ножке  процессора:

Banana Pi BPI-M64 GPIOXX

Поэтому необходимо экспортировать 39-контакт на процессоре, выполним команду:

echo 39 > /sys/class/gpio/export

В результате в каталоге /sys/class/gpio должно появиться файл-устройство gpio39:

Banana Pi BPI-M64

Это означает, что виртуальный GPIO39 теперь доступен для работы. Поскольку нужно управлять светодиодом, нужно порт настроить его на выход:

echo out > /sys/class/gpio/gpio39/direction

Теперь виртуальный GPIO39 настроен на выход и можно включить светодиод, отправляя в порт единицу:

echo 1 > /sys/class/gpio/gpio39/value

Работает! Светодиод загорелся:

Banana Pi BPI-M64

Также можно погасить светодиод, просто отправив логический 0, командой:

echo 0 > /sys/class/gpio/gpio39/value

Banana Pi BPI-M64

Особенности светодиода Gravity: Digital Blue LED Light Module от DFRobot.com
Отправляя логическую «1» в порт, мы ожидаем что светодиод зажжется, но светодиод от DFRobot.com погаснет, т.е. работает инверсно. Для решения этой проблемы как раз воспользуемся опцией active_low, которая позволит на логическую «1» отправить в порт 0, и наоборот. Для этого выполним команду:

echo 1 > /sys/class/gpio/gpio39/active_low

Теперь управление светодиодом логически соответствует задаваемым уровням.

Теперь можно вернуть контроль GPIO39 операционной системе, и освободить все ресурсы связанные с GPIO39: 

echo 39 > /sys/class/gpio/unexport

К выводам GPIO можно подключить через транзисторные ключи обычные электромагнитные реле, и управлять нагрузкой через сеть Интернет. Работать напрямую с GPIO через терминал не всегда бывает удобно, поэтому для демонстрации автоматизации создадим простейший bash-скрипт который выполнит регистрацию контакта, помигает 5-раз с интервалом раз в 0.5 секунды, и обратно вернет управление используемым контактом ОС.

Скрипт bash
1) Создадим скрипт в домашней папке пользователя root, путь /root, для редактирования файлом используется редактор mcedit (apt-get install mc):

mcedit /root/blink.sh

2) Поместим в редактор код:

#!/bin/bash
echo 39 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio39/direction
echo 1 > /sys/class/gpio/gpio39/active_low
echo 0 > /sys/class/gpio/gpio39/value

echo "Start blink"
for ((a=1; a<=5 ; a++))
do echo 1 > /sys/class/gpio/gpio39/value
sleep 0.5
echo 0 > /sys/class/gpio/gpio39/value
sleep 0.2
done

echo 0 > /sys/class/gpio/gpio39/value
echo 39 > /sys/class/gpio/unexport
echo "End blink"

3) Сохраним файл(F2) и выйдем из редактора(F10).

4) Установим права выполнения на файл:

chmod +x /root/blink.sh

5) Запустим скрипт:

/root/blink.sh

Светодиод 5 раз будет мигать.

Banana Pi BPI-M64

Реализуем тоже самое, только на языке С:

1) Создадим файл:

mcedit /root/blink.c

2) Поместим в редактор код:

#include
#include
#define GPIO_PATH "/sys/class/gpio"
#define GPIO_PIN_PATH "/sys/class/gpio/gpio39"
unsigned long c=0;
unsigned long i=0;
int main()
{
FILE *fp;
fp=fopen(GPIO_PATH"/export","w");
fprintf(fp,"39");
fclose(fp);
fp=fopen(GPIO_PIN_PATH"/direction","w");
fprintf(fp,"out");
fclose(fp);
//***for LED DFRobot.com
fp=fopen(GPIO_PIN_PATH"/active_low","w");
fprintf(fp,"1");
fclose(fp);
//***
fp=fopen(GPIO_PIN_PATH"/value","w");
fprintf(fp,"0");
fclose(fp);
printf("Набери количество циклов\n");
scanf("%d",&c);
for (i=c;i>0;i--)
{
fp=fopen(GPIO_PIN_PATH"/value","w");
fprintf(fp,"1");
fclose(fp);
usleep(500000);
fp=fopen(GPIO_PIN_PATH"/value","w");
fprintf(fp,"0");
fclose(fp);
usleep(500000);
}
fp=fopen(GPIO_PIN_PATH"/direction","w");
fprintf(fp,"in");
fclose(fp);
fp=fopen(GPIO_PATH"/unexport","w");
fprintf(fp,"39");
fclose(fp);
printf("PROFIT!\n");
return EXIT_SUCCESS;
}

3) Сохраним файл(F2) и выйдем из редактора(F10).

4) Теперь скомпилируем программу:

gcc -Wall blink.c -o blink

5) И так же как и в предыдущем примере запустим скомпилированную программу:

./blink

Если укажем значение «5», то светодиод моргнет 5 раз.
Banana Pi BPI-M64

 

Получение значения температуры от датчика DS18B20

Датчик DS18B20 подключен к 18-контакту разъема  типа Raspberry Pi. Получение значения температуры осуществляется путем конфигурирования контактов для протокола 1-Wire с указанием драйвера обработчика. Для этого необходимо внести изменения в Device Tree overlays. Device Tree — это описание оборудования в системе. Дерево должно включать имя базового процессора, конфигурацию его памяти и любые периферийные устройства (внутренние и внешние). DT не используется для описания программного обеспечения, хотя перечисление аппаратных модулей вызывает загрузку модулей драйверов. В DT описываются контакты и им назначается обработчик в виде драйвера для DS18B20. Драйвер создает файл-устройство в sysfs, при чтение которого получим значение температуры. В данной публикации не раскрывается принцип построения DT. Armbian уже содержит необходимый драйвер обработчик и шаблон конфигурации для DT. После подключения датчика DS18B20 необходимо применить шаблон DT 1-Wire протокола. Для этого необходимо запустить утилиту конфигурирования платы:

armbian-config

И выбрать пункт System из списка: 

Banana Pi BPI-M64 ds18b20

Затем выбрать пункт Hardware:

Banana Pi BPI-M64 ds18b20

И отметить w1-gpio:

Banana Pi BPI-M64 ds18b20

Затем сохранить <Save> и < Back >. Будет предложено перезагрузить палату, соглашаемся и ждем перезагрузки:

Banana Pi BPI-M64 ds18b20

После перезагрузки выполняем команду: 

dmesg | grep -E 'w1|wire'

В результате должны получить примерно такой результат:

Banana Pi BPI-M64 ds18b20

Из которого следует что драйвер поддержки включен и был обнаружен один датчик 28.0000034aa0ba. Если установлена библиотека WiringPi [BPI-WiringPi2], то выполнив команду

gpio readall

, увидим что в строке с 18-контактом изменился режим работы на IN (input)

Banana Pi BPI-M64 ds18b20

Это означает, что на 18-контакт добавился драйвер обработчик протокола 1-Wire. Драйвер поддерживает работу с несколькими датчиками DS18B20. Перейдем по пути: /sys/bus/w1/devices и посмотрим какие новый устройства появились:

tree /sys/bus/w1/devices

Banana Pi BPI-M64 ds18b20

В списке как раз есть один датчик DS18B20 — 28-0000034aa0ba. В разных системах название может отличаться. Для получения значения температуры выполним чтение, командой:

cat /sys/bus/w1/devices/28-0000034aa0ba/w1_slave

Banana Pi BPI-M64 ds18b20

Текущее значение температуры составляет: 24.5 градусов Цельсия. Задача выполнена!

Но если понаблюдать за изменением температуры, то можно заметить, что точность показаний составляет 0.5 градусов. Драйвер устройства позволяет получать температуру с разной точностью. Согласно таблицы из спецификации к датчику, следует:

Banana Pi BPI-M64 ds18b20

  • 9 бит: точность 0.5 °C, время получения данных 93.75 ms
  • 10 бит: точность 0.25 °C, время получения данных 187,5 ms
  • 11 бит: точность 0.125 °C, время получения данных 375 ms
  • 12 бит: точность 0.0625 °C, время получения данных 750 ms

Чем выше точность, тем больше требуется времени на получение значения температуры. Для установки точности необходимо выполнить команду:

echo 9..12 > /sys/bus/w1/devices/28-xxxxxxx/w1_slave

где 9..12 — точность, 28-xxxxxxx — название датчика.

Установим максимальную точность, и получим значение температуры, команда:

echo 12 > /sys/bus/w1/devices/28-0000034aa0ba/w1_slave

Banana Pi BPI-M64 ds18b20

В результате, температура составила: 24.437 °C

Вывод использование интерфейса sysfs

Недостатки:

  • Не максимальная возможная скорость работы с GPIO;
  • Невозможно включить выключить сразу несколько линий одним вызовом;
  • В случае краха приложения GPIO линии остаются в «инициализированном» состоянии.

На деле область работы с GPIO через sysfs ограничивается управлением электромагнитными и твердотельными реле, светодиодной иллюминацией и тому подобными задачам, не требующими высокого быстродействия и точной привязки по времени. Невысокая скорость работы — плата за простоту управления через файловую систему.

Преимущества:

Будет работать на любом Linux-дистрибутиве и любом устройстве (GPIO имеют не только одноплатные компьютеры, но и некоторые роутеры и т.д. ) — если имеется драйвер GPIO в ядре Linux для данного SoC.
Существует некоторые готовые утилиты: https://github.com/torvalds/linux/tree/master/tools/gpio

Ссылки

Вам также может понравиться

About the Author: Anton

Programistik