BiNome
BiNome
3257 просмотров10 комментариев

Часть 1. Программное управление GPIO Repka Pi 3 через системные вызовы к драйверу символьных устройств. Общие понятия. Настройка RepkaOS. Использование инструментов управления GPIO из пользовательского режима

Содержание


Настоящая статья посвящена вопросу программного управлению GPIO через системные вызовы к драйверу символьных устройств и познакомит вас с возможностью использования библиотеки libgpiod2 на Repka Pi 3. В статье приведены рекомендации по настройке ОС для использования этой библиотеки. Результаты тестовой эксплуатации libgpiod2 на Repka Pi 3 обобщены в виде справочной таблицы. В заключении статьи приводятся примеры использования инструментов управления GPIO из пользовательского интерфейса.

Общие сведения #

GPIO (General-Purpose Input/Output) интерфейс ввода/вывода общего назначения чаще всего используемый на платах микроконтроллеров и одноплатных компьютеров для программного управления цифровыми сигналами.

Во внутренней архитектуре ядро Linux реализует доступ к GPIO через модель производитель/потребитель. Существуют драйверы, которые предоставляют доступ к линиям GPIO (драйверы контроллеров GPIO) и драйверы, которые используют линии GPIO (клавиатура, сенсорный экран, датчики и т. д.).

Основные особенности GPIO:

  • Контакты GPIO могут быть сконфигурированы для ввода или вывода;
  • Контакты GPIO могут быть включены / выключены;
  • Контакты для ввода доступны для чтения значения;
  • Контакты для вывода доступны для записи / чтения значения;
  • Входные значения часто могут использоваться в качестве IRQs (обычно для событий пробуждения).

В ядре Linux система gpiolib занимается регистрацией и распределением GPIO. Эта структура доступна через API как для драйверов устройств, работающих в пространстве ядра (kernel space), так и для приложений пользовательского пространства (user space).

В Linux (в том числе и в RepkaOS) доступ к аппаратным устройствам осуществляется пользователем через специальные файлы устройств. Эти файлы сгруппированы в каталоге /dev, а системные вызовы перенаправляются операционной системой на драйвер устройства, связанного с физическим устройством. Драйвер устройства - это компонент ядра ОС Linux (обычно модуль), который взаимодействует с аппаратным устройством.

В Linux существуют две категории файлов устройств, и следовательно, драйверов устройств: символьные и блочные. К первой категории относятся медленные устройства, которые управляют небольшим объемом данных, а доступ к данным не требует частых запросов seek. Примерами могут служить такие устройства, как клавиатура, мышь, последовательные порты, звуковая карта, джойстик и т.д. В общем, операции с этими устройствами (чтение, запись) выполняются последовательно, байт за байтом. Ко второй категории относятся устройства, где объем данных велик, данные организованы по блокам, а поиск является обычным делом. Примерами таких устройств являются: жесткие диски, CD-ROM, диски в оперативной памяти и т.д. Для этих устройств чтение и запись выполняются на уровне блоков данных.

Для двух типов драйверов устройств ядро Linux предлагает разные API. Для символьных устройств используются системные вызовы (ioctl) непосредственно к драйверам устройств. Как правило, системные вызовы к драйверам устройств чаще всего используются в системном программировании, а для разработки приложений пользовательского режима используются библиотеки-обвертки. Одной из таких библиотек-обверток вокруг системных вызовов драйвера символьного устройства GPIO является библиотека libgpiod2.

Примечание: сообществом разработчиков ядра Linux, см. официальную документацию, рекомендуется использовать библиотеку libgpiod2 для разработки нативных и управляемых виртуальной машиной приложений.

Библиотека libgpiod2 #

Libgpiod (Library General Purpose Input/Output device) предоставляет набор API для вызова из своих программ и несколько утилит для управления линиями GPIO из пользовательского режима.

Контроллер GPIO (gpiochip) представляет собой символьное устройство, отображается в разделе /dev. Предназначен для управления и взаимодействия с линиями GPIO. Контроллеры GPIO отображаются в каталог  /dev/gpiochipN  или  /sys/bus/gpiochipN , где N — порядковый номер чипа.

Линия общего назначения контроллера GPIO (line) управляется контролером GPIO, сопоставлена с физическим контактом GPIO-разъема. Управление сигналами на контактах осуществляется через запись в линию или чтение из нее.

Библиотека libgpiod2 инкапсулирует вызовы ioctl и структуры данных за простым API. Библиотека разработана для замены доступа к GPIO через виртуальную файловую систему sysfs, так как начиная версии 4.8 ядра Linux интерфейс GPIO sysfs объявлен как устаревший (deprecated). Используемый в библиотеке новый интерфейс chardev гарантирует, что все выделенные ресурсы будут освобождены после закрытия файлового дескриптора устройства, и добавляет несколько новых функций, которых нет в устаревшем интерфейсе sysfs (например, опрос событий, установка/чтение нескольких значений одновременно).

Библиотека libgpiod2 обладает весомыми преимуществами по сравнению с интерфейсом sysfs, а именно:

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

В RepkaOS 1.0.14 (от 06.10.2023) библиотека libgpiod2 версии 1.3 установлена “из коробки”, но для начала работы с GPIO в пользовательском режиме необходимо дополнительно установить пакет gpiod. А использование библиотеки для разработки программ станет возможно только после установки пакета libgpiod-dev. Библиотека libgpiod2 может быть использована при написании программ на ЯП: C, C++, C#, Java (Kotlin), Python. В настоящее время разработчики библиотеки работают над реализацией ее поддержки в ЯП Rust.

Для полной установки libgpiod2 из общего репозитория в RepkaOS введите команду:

sudo apt install libgpiod2 gpiod libgpiod-dev

Для удаления:

sudo apt remove libgpiod2 gpiod libgpiod-dev

Для установки более новых бинарных версий версий библиотеки (актуальная версия 2.1) можно воспользоваться скриптом setup-libgpiod.sh, а для ее удаления remove-libgpiod.sh.

Для прямого доступа к линиям GPIO в RepkaOS пользователь должен обладать правами администратора (root) или получать привилегии администратора через команду sudo при работе с линиями GPIO.

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

  1. Создадим группу gpiod и добавим в нее обычного пользователя user (не обладающего административными правами, пользователь должен быть зарегистрирован в ОС заранее):

    sudo groupadd gpiod
    sudo usermod -G gpiod user
    
  2. Разрешим пользователям группы gpiod управлять контроллерами GPIO № 0 и 1, создадим файл 60-gpiod.rules в каталоге /etc/udev/rules.d следующего содержания:

    #udev rules for gpio port access
    SUBSYSTEM=="gpio", KERNEL=="gpiochip[0-1]", GROUP="gpiod", MODE="0660"
    
  3. Перезагрузите устройство:

    sudo reboot
    

Особенности управления GPIO из пользовательского режима #

Прежде чем начать работу с инструментами рассмотрим справочную таблицу (рис. 1), которая пригодится нам для работы с линиями GPIO.

Таблица составлена на основе опытного тестирования программного управления GPIO из приложения на ЯП Python с использованием библиотеки libgpiod2 версии 1.3. В процессе исследования проверялось:

  • переключение режимов работы линий ввод/вывод;
  • программное включение резистора для подтяжки линии вверх и вниз;
  • доступность обработчиков событий изменения состояния сигнала (высокое / низкое) в линии с программным включением резистора подтяжки вверх и вниз.

Примечание:

  • использовался первый вариант распиновки 40 pin разъема;
  • тестирования линий 4 и 5 контроллера gpiochip1 осуществлялось при выключенном выводе сообщений на UART0 (по умолчанию включена);
  • подтяжка вниз на линиях, сопоставленных с пинами 3, 5, 10, 27 и 28 GPIO работает как подтяжка вверх, соответственно обработка событий с подтяжкой вниз не доступна;
  • на линиях, сопоставленных с пинами 19, 21, 23 и 24, обработка событий не доступна;
  • пороговое напряжения вызова прерывания на изменение состояния сигнала высокое / низкое не измерялось, в виду отсутствия технической возможности;
  • состав используемого оборудования при тестировании: Repka Pi 3 1.4 GHz ОЗУ 2 Gb (версия платы 1.4), монитор, клавиатура, мышь, макетная плата, резистор 220 Ом, светодиод, кнопка, комплект проводов, мультиметр.

Рис. 1. Справочная таблица для работы с линиями контроллера GPIO с использованием библиотеки libgpiod2 на Repka Pi 3 (версия прошивки 1.0.8 и выше).

Для управления линиями GPIO через libgpiod2 из пользовательского режима можно использовать следующие утилиты (входят в пакет gpiod):

  • gpiodetect — выведет список всех чипов GPIO, их метки и количество линий;
  • gpioinfo — выводит информацию о линиях GPIO конкретного контроллера GPIO. Информация выводится в виде таблицы со следующими столбцами: номер линии, название контакта (для Repka Pi 3 к сожалению не заданы), направление ввода/вывода, текущее состояние;
  • gpioget — считывает текущее состояние линии GPIO;
  • gpioset — устанавливает значение для линии GPIO;
  • gpiomon — осуществляет мониторинг состояния линии GPIO и выводит значение при изменение состояния;
  • gpionotify — ожидает определенное состояние линии GPIO и выводит статус изменения в консоль.

Примечание: все перечисленные утилиты имеют параметр -h (—help) для вывода списка допустимых параметров, а также man-страницы с подробным описанием.

Тест работоспособности библиотеки libgpiod2 #

Для проверки работоспособности библиотеки libgpiod2 соберем макет схемы с двумя светодиодами (рис. 2).

Рис. 2. Макет схемы для теста (номера контактов: черный - 40, красный - 32, зеленый - 23).

Запросим информацию о доступных в Repka Pi 3 контролерах:

~/gpiodetect

и их линиях:

~/gpioinfo gpiochip0
~/gpioinfo 1

Примечание: в Repka Pi 3 контакты PL 2, 3, 10 и 11 управляются контроллером gpiochip0, все остальные контроллером gpiochip1.

Подадим питание на красный светодиод, подключенный к линии 11 gpiochip0 (контакт № 32)

~/gpioset gpiochip0 11=1

или

~/gpioset 0 11=1

Отключим питание от красного светодиода:

~/gpioset gpiochip0 11=0

или

~/gpioset 0 11=0

Задание для самостоятельного выполнения:

  1. Повторите операции включения и выключения питания для зеленого светодиода. Для определения номера контроллера и линии, к которой он подключен, используйте справочную таблицу (рис. 1).
  2. Посмотрите с помощью утилиты gpioinfo как изменяется информация о состоянии линии при включении и выключении светодиодов.
  3. Получите значения используемых вами линий с помощью утилиты gpioget, до и после включения светодиодов.

Примеры использования библиотеки в различных ЯП #

Ниже приведены примеры для мигания красным светодиодом (см. рис. 2), подключенным к 11 линии gpiochip0.

Python

import gpiod
import sys
import time

LED_CHIP = 0
LED_LINE_OFFSET = 11

chip = gpiod.chip(LED_CHIP)
led = chip.get_line(LED_LINE_OFFSET)

config = gpiod.line_request()
config.consumer = "Blink"
config.request_type = gpiod.line_request.DIRECTION_OUTPUT
led.request(config)

while True:
    led.set_value(0)
    time.sleep(0.1)
    led.set_value(1)
    time.sleep(0.1)

Для установки модуля gpiod для Python выполните следующую команду:

pip3 gpiod

С++

// в разделе #include <> заменены на "" из-за некорректного вывода кода 
// (пропадают названия заголовочных файлов)
#include "chrono"
#include "cstdlib"
#include "gpiod.hpp"
#include "iostream"
#include "string"
#include "thread"

int main(int argc, char **argv) {
    std::string LED_CHIP = "gpiochip0";
    int         LED_LINE_OFFSET = 11;

    gpiod::chip chip(LED_CHIP);
    gpiod::line led = chip.get_line(LED_LINE_OFFSET);

    gpiod::line_request config;
    config.consumer     = "Blink";
    config.request_type = gpiod::line_request::DIRECTION_OUTPUT;
    led.request(config);

    while(1) {
        led.set_value(0);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        led.set_value(1);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}
gcc -o blink blink.o -lgpiod
./blink

C# & .NET 6

dotnet new console dotnet_iot_blink
vim ./dotnet_iot_blink/Program.cs
using System;
using System.Device.Gpio;
using System.Device.Gpio.Drivers;
using System.Threading;
namespace dotnet_iot_blink
{
 class Program
 {
  static void Main(string[] args)
  {   
   const int GPIOCHIP = 0;
   const int LED_PIN = 11;
   GpioController controller;
   var drvGpio = new LibGpiodDriver(GPIOCHIP);
   controller = new GpioController(PinNumberingScheme.Logical, drvGpio);
   controller.OpenPin(LED_PIN, PinMode.Output);
   bool ledOn = true;
   while (true)
   {
    controller.Write(LED_PIN, ((ledOn) ? PinValue.High : PinValue.Low));
    Thread.Sleep(100);
    ledOn = !ledOn;
   }
  }
 }
}
cd ./dotnet_iot_blink
dotnet run

Для работы на Repka Pi 3 с GPIO в .NET 6 и выше рекомендуется обновить библиотеку libgpiod-dev до версии 1.6.3.

Примечание: из личного опыта, .NET 6 отлично работает с libgpiod-dev версии 1.3, установленной в RepkaOS 1.4 по умолчанию.

Заключение #

В следующих статьях будут опубликованы учебные материалы по управлению GPIO на Repka Pi 3 с примерами на ЯП Python в связке с библиотекой libgpiod2. В частности, рассмотрим вопросы настройки линий для вывода сигнала, помигаем светодиодами и решим несколько интересных задач с ними.

Часть 2. Программное управление линиями GPIO Repka Pi 3 в режиме вывода с примерами на Python (libgpiod).


Комментарии (10)

Для участия в обсуждении Вы должны быть авторизованным пользователем
Команда Репки
Команда Репки  

Это мега крутая статья!
Лучший пятничный подарок проекту Репка! Спасибо Вам большое!!!!

BiNome
BiNome  

Грех не помочь такому смелому проекту, тем более отечественному. Главное чтобы впрок пошло.

BiNome
BiNome  

Добавлен раздел "Примеры использования библиотеки в различных ЯП"

Denis-pimenov  

Скажите, а в чём код писать то? Не vscode же на репку ставить! И... я ведь могу прям на репке писать? Вопросы наверно глупые, я второй день с ней вожусь.
ЗЫ. накатил на репку alt linux, т.к. на ноуте он же

BiNome
BiNome  

Я пишу в VS Code (непосредственно на Репке, 1,4 гГц, 2 Гб ОЗУ). Можно использовать предустановленный Geany. Если планируете писать на Python, то можно установить Thonny из репозитория, он адаптирован для одноплатников. Во второй части статьи (п. 4.1, https://repka-pi.ru/blog/post/59), описан порядок настройки VS Code (в примечаниях). Если в двух словах, после установки нужно отключить аппаратное ускорение графики, так как из-за него некорректно работает отображение текста в терминале.

Denis-pimenov  

Спасибо! Меня как раз больше плюсы и шарп интересует. Пойду пытаться! :)

BiNome
BiNome  

Дополнительно по VS Code. Расширения для Python и C/C++ (в т.ч. CMake) работают без нареканий. Для работы с C# нужно ставить расширения C# (base language support), который за собой тянет .NET Install Tool тянет за собой .NET 7 Runtime. Настоятельно (пока) не рекомендую ставить C# Dev Kit и IntelliCode for C# Dev Kit, так как они очень ресурсоемкие, даже не все настольники с ними справляются. P.s. последние 2 расширения используются для интеллектуального анализа кода и умных подсказок (не путать с обычным IntelliSense, который включен в первое расширение).

k_s_corp
k_s_corp  

Для того, чтобы gpiod заработал "без рута" сделал:
sudo chmod a+rw /dev/gpiochip0
так как ругался что нет прав...

BiNome
BiNome  

Как один из вариантов подойдет, но у него есть минус - после перезагрузки придется это делать снова... лучше воспользоваться способом описанным в подразделе "Линия общего назначения контроллера GPIO (line) " настоящей статьи

k_s_corp
k_s_corp  

Для С++ правильно (у меня только так заработало)
g++ -o name name.cpp -lgpiodcxx (name - имя файла)

Темы

Навигация

ВойтиРегистрация