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

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

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

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

#include <linux/gpio.h>
#include <linux/interrupt.h>

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

static struct gpio out;
static struct gpio in;
static int irq_num;
static int gpio_val = 0;

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

static int __init blablamod_init(void)
{
    int ret;
    out.gpio = 21;
    out.flags = GPIOF_OUT_INIT_LOW;
    out.label = "Output Gpio";

    in.gpio = 17;
    in.flags = GPIOF_IN;
    in.label = "In Gpio";

    ret = gpio_request(out.gpio, out.label);
    if (ret)
    {
        printk(KERN_ALERT "OUT Gpio request failed");
        return -1;
    }
    gpio_direction_output(out.gpio, 0);
    gpio_set_value(out.gpio, 1);

    ret = gpio_request(in.gpio,in.label);
    if (ret)
    {
        printk(KERN_ALERT "In Gpio request failed");
        return -2;
    }

    ret = gpio_to_irq(in.gpio);
    if (ret < 0)
    {
        printk(KERN_ERR "Unable to request IRQ: %d\n", ret);
        return -3;
    }
    irq_num = ret;
    printk(KERN_INFO "Successfully requested IRQ#%d.\n", irq_num);
    ret = request_irq(irq_num,gpio_isr,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED, "gpio_irq", NULL);
    if (ret)
    {
        printk(KERN_ERR "Unable to request irq\n");
        return -4;
    }


    printk(KERN_NOTICE "Blablamod loaded\n");
    return 0;
}

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

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

static irqreturn_t gpio_isr(int irq, void *data)
{
    gpio_set_value(out.gpio,gpio_val);
    gpio_val = (gpio_val) ? 0 : 1; 
    return IRQ_HANDLED;
}

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

static void __exit blablamod_exit(void)
{
    free_irq(irq_num,NULL);
    gpio_free(in.gpio);
    gpio_free(out.gpio);
    printk(KERN_NOTICE "Blablamod unloaded!\n");
}

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

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

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

Исходники как всегда на GitHub.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий