В данной статье рассмотрим как настроить прерывание ядра по сигналу на 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.