Меню Рубрики

Linux irq to gpio

Прерывания GPIO в модуле ядра Raspberry Pi B+

В данной статье рассмотрим как настроить прерывание ядра по сигналу на GPIO, замерим сколько времени на это уходит.
О том как настроить GPIO в модуле ядра linux.

Для замера скорости обработки прерывания я решил сделать модуль ядра, в нем настроим два вывода GPIO. Один настроим на прерывание, у другой будем переключаться в обработчике этого прерывания.

Для работы с GPIO и прерываниями включаем такие заголовки:

Определим переменные для хранения настроек gpio и прерывания.

В функции инициализации модуля настроим выводы GPIO и запросим прерывание.

Запрос номера прерывания делается при помощи функции gpio_to_irq, которая принимает номер ножки, а возвращает номер прерывания или код ошибки. После чего нужно собственно запросить прерывание у системы при помощи функции request_irq, которая принимает указатель на функцию обработчик, флаги и символьное имя прерывания.

Обработчик прерывания выглядит следующим образом:

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

Загружаем модуль и вещаем источник прямоугольных импульсов на GPIO 17 нашего Raspberry. На выводе 21 же смотрим результат.
В качестве источника сигнала я использовал stm32f4 discovery.

Время с момента прихода сигнала до обработки довольно сильно колеблется. Поэтому настроил на осциллографе остаточные следы.

Не сказать, чтобы я особо порадовался таким результатам, но ждать лучшего от не риалтайм системы было бы опрометчиво.
Начало обработки прерывания в среднем через 10мкс после запроса — это довольно не плохой результат.

Источник

Пишем модуль ядра Linux: GPIO с поддержкой IRQ

Данная статья посвящена разработке GPIO (General-Purpose Input/Output) модуля ядра Linux. Как и в предыдущей статье мы реализуем базовую структуру GPIO драйвера с поддержкой прерываний (IRQ: Interrupt Request).

Входные данные аналогичны предыдущей статье: разработанный GPIO блок для нового процессора «зашитый» на ПЛИС и запущенный Linux версии 3.18.19.

Для того чтобы разработать GPIO драйвер, нам потребуется выполнить следующие шаги:

  1. Понять принцип взаимодействия GPIO драйвера с user space интерфейсом;
  2. Добавить модуль ядра в сборку и описать аппаратную часть в device tree;
  3. Реализовать базовый скелет драйвера, а также его точки входа и извлечения;
  4. Реализовать функциональную часть GPIO драйвера;
  5. Добавить к реализации драйвера поддержку IRQ.

Примеры GPIO драйверов можно посмотреть тут.

Шаг первый

Для начала познакомимся с принципом взаимодействия GPIO драйвера через консоль пользователя.

С помощью небольшого bash скрипта, создадим в /sysfs элементы управления каждого GPIO. Для этого в командой строке нужно написать следующий скрипт:

Далее посмотрим какие возможности предоставляет /sysfs для конфигурации каждого GPIO:

В данный момент нас интересуют следующие поля:

  • direction — задает направление линии. Может принимать значения «in» или «out»;
  • value — позволяет выставить высокий или низкий сигнал на линии (если direction установлен в «out»), в противном случае (direction установлен в «in») позволяет прочитать состояние линии;
  • edge — позволяет настроить событие по которому происходит прерывание. Может принимать следующие значения: «none», «rising», «falling» или «both».

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

  • direction_input: настраивает линию на вход. Вызывается при следующей записи: echo «in» > /sys/class/gpio/gpio248/direction;
  • direction_output: настраивает линию на выход. Вызывается при следующей записи: echo «out» > /sys/class/gpio/gpio248/direction;
  • get: считывает установленное на линии значение. Вызывается при следующей записи: cat /sys/class/gpio/gpio248/value;
  • set: устанавливает значение на линии. Вызывается при следующей записи: echo 1/0 > /sys/class/gpio/gpio248/value;

Для описания конфигурации IRQ в Linux существует структура irq_chip, которая содержит следующие поля:

  • irq_set_type: настраивает тип события по которому будет происходить прерывание. Вызывается при следующей записи: echo > «rising»/«falling»/«both» > /sys/class/gpio/gpio248/edge;
  • irq_mask: запрещает прерывания. Вызывается при следующей записи: echo «none» > /sys/class/gpio/gpio248/edge;
  • irq_unmask: разрешает прерывание по событию, которое было установлено в irq_set_type. Вызывается сразу после выполнения irq_set_type.

Шаг второй

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

После добавим конфигурацию драйвера в drivers/gpio/Kconfig:

Добавим в сборку драйвер в drivers/gpio/Makefile:

И, наконец, добавим в devicetree (*.dts) описание GPIO блока:

Более подробную информацию про devicetree можно прочитать тут.

Шаг третий

Перейдем к самой интересной для нас части!

Разработку драйвера начнем с подключения необходимых заголовочных файлов и описания полного скелета драйвера без поддержки IRQ. Далее последовательно будем наполнять каждую функцию кодом и сопровождать необходимыми пояснениями.

Как видно из реализации, скелет драйвера выглядит достаточно просто и содержит не так много необходимых функций и структур.

Для того чтобы описать будущий драйвер нам потребуются следующие элементы:

  • platform_driver skel_gpio_driver — описывает точку входа skel_gpio_probe при загрузке драйвера и skel_gpio_remove при его извлечении из ядра;
  • struct of_device_id skel_gpio_of_match — содержит таблицу, которая описывает аппаратную часть GPIO блока;
  • struct skel_gpio_chip — содержит необходимые поля для управления драйвером GPIO блоком.

Далее, чтобы загрузить/извлечь драйвер в/из Linux, необходимо реализовать указанные в структуре skel_gpio_driver методы .probe и .remove.

Функция skel_gpio_remove просто удаляет зарегистрированный GPIO драйвер из ядра, поэтому рассмотрим основные моменты в skel_gpio_probe:

  • devm_kzalloc — выделяет память под структуру skel_gpio_chip;
  • platform_get_resource — читает адрес начала регистровой карты GPIO из devicetree;
  • devm_ioremap_resource — выполняет mapping физического адреса на виртуальный;
  • of_property_read_u32 — читает количество доступных GPIO из devicetree;
  • skel_gc->gchip.* — заполняет необходимые для работы поля структуры;
  • gpiochip_add — добавляет GPIO контроллер в драйвер;

До сих пор не было описано почему же используется такие магические числа как 248… 255. Запись skel_gc->gchip.base = -1; просит ядро динамически выделить номера используемых GPIO. Чтобы узнать данные номера в конце драйвера добавлен вывод:

Конечно, Linux предоставляет возможность задать номера вручную, но давайте посмотрим на комментарий в исходном коде:

Шаг четвертый

Рассмотрим функциональную часть драйвера, а именно реализуем следующие методы:
.direction_output, .direction_input, .get и .set. Далее будет показан аппаратно-зависимый код, который в большинстве случаев будет отличаться.

Метод skel_gpio_direction_input выполняет следующие действия:

  • Вызывается при следующей команде echo «in» > /sys/class/gpio/gpioN/direction;
  • Считывает регистр SKEL_GPIO_PAD_DIR, который отвечает за установку направления пина GPIO;
  • Устанавливает необходимую маску;
  • Записывает полученное значение обратно в SKEL_GPIO_PAD_DIR.

Метод skel_gpio_direction_output выполняет действия аналогичные skel_gpio_direction_inut за исключением того, что вызывается при следующих командах:

  • echo «out» > /sys/class/gpio/gpioN/direction;
  • echo «high» > /sys/class/gpio/gpioN/direction, при этом устанавливает значение value в 1;
  • echo «low» > /sys/class/gpio/gpioN/direction, при этом устанавливает значение value в 0.

value — значение, определяющее уровень сигнала на выходной линии.

Метод skel_gpio_set выполняет следующие действия:

  • Вызывается при следующей команде echo 1/0 > /sys/class/gpio/gpioN/value;
  • Считывает регистр SKEL_GPIO_WR_DATA, который показывает значение текущего сигнала на линии;
  • Устанавливает или сбрасывает необходимый бит по offset;
  • Записывает полученное значение обратно в SKEL_GPIO_WR_DATA.

Метод skel_gpio_get считывает значение сигнала на линии, прочитав регистр SKEL_GPIO_RD_DATA.

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

Реализованный драйвер содержит необходимый функционал для управления GPIO, но в данный момент в драйвере отсутствует поддержка работы с прерываниями, поэтому можно перейти к следующему шагу.

Шаг пятый

Добавление IRQ в GPIO драйвер можно разделить на три шага:

  • Описание поддерживаемых методов в структурах данных ядра;
  • Включение поддержки IRQ в момент загрузки драйвера в систему;
  • Реализация поддерживаемых методов.

Первоначально опишем необходимый набор операций:

Следовательно драйвер может разрешать(skel_gpio_irq_unmask)/запрещать(skel_gpio_irq_mask) прерывания и указать тип события по которому оно будет генерироваться (skel_gpio_irq_set_type).
Далее опишем единственный метод, который отвечает за сопоставление виртуального irq number с аппаратным.

Затем укажем ядру, что загружаемый драйвер поддерживает работу с IRQ. Для этого необходимо добавить в probe функцию следующий код:

В выше приведенном коде происходит:

  • Выделение и инициализация области под irq_domain;
  • Считывание номера прерывания с devicetree;
  • mapping между виртуальным и аппаратным прерыванием;
  • Регистрация обработчика прерывания и установка данных на передачу в обработчик;

Приступим к реализации некоторых выше описанных методов.
skel_gpio_to_irq — создает mapping между аппаратным и виртуальным прерыванием. Если же данный mapping уже был создан, то возвращает номер созданного виртуального прерывания.

skel_irq_handler — обработчик прерывания, который:

  • Считывает регистр статуса прерывания;
  • Считывает регистр маски прерывания;
  • Выделяет прерывания ожидающие обработки;
  • Для каждого GPIO в котором возникло прерывание вызывает generic_handle_irq.

Вот и все, в данной статье мы узнали как происходит взаимодействие GPIO драйвера с виртуальной файловой системой sysfs, реализовали базовую структуру GPIO драйвера, а также рассмотрели методы которые требуются для поддержки IRQ.

В статье не приведена реализация методов skel_gpio_irq_unmask, skel_gpio_irq_mask и skel_gpio_irq_set_type по двум причинам. Во-первых, данные методы просты в реализации. Во-вторых, аппаратно-зависимы. Они отвечают за разрешение или запрет прерываний по определенным событиям, которые поддерживает GPIO контроллер.

Пожалуйста, если вы нашли ошибки/неточности, или вам есть что добавить — напишите в ЛС или в комментарии.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

  • Mac os принт скрин
  • Mac os при загрузке синий экран
  • Mac os правильное удаление программ
  • Mac os правая кнопка mac мыши
  • Mac os пошаговая стратегия