LINUX.ORG.RU

Arm,GPIO не все IRQ отрабатывают по IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING

 , , ,


1

2

есть необходимость прочитать данные через GPIO по протоколу wiegand 26 на pcduino. пробовали читать через скетч ардуиновский в непрерывном цикле - читает нормально, но при загрузке процессора пропадают данные. Попробовал написать модуль ядра, с надеждой что ситуация улучшиться.

Делаю два прерывания на data0 и data1 пины GPIO if(request_irq(irq_gpio02, wiegand_data_isr1, IRQF_DISABLED|IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, «wiegand_data1», &wiegand))

прерывания назначаются и отрабатывают. Но из 26 бит приходит все время разное количество. Уже убрал printk из обрабочика прерывания, все равно пропадаю. Есть подозрение, что установка таймера вызывает задержку и пропадание прерывания. уже и чтение с gpio убрал, анализирую какое прерывание 1 или 0 вызвалось, все равно пропадают биты. Подскажите как правильно работать с GPIO в контексте реалтайма из модуля ядра ?


Уже убрал printk из обрабочика прерывания,

воу воу полегче.

какой реалтайм, ставь буфер аппаратный.

anonymous
()
Ответ на: комментарий от anonymous

Не совсем понял про «ставь буфер аппаратный». Вернее совсем не понял. Я сделал в структуре массив static struct wiegand { char bufferbit[MAX_WIEGAND_BIT]; int currentBit; }wiegand; потов в каждом обработчике прерывания делаю: rqreturn_t wiegand_data_isr1(int irq, void *dev_id) { struct wiegand *w = (struct wiegand *)dev_id; // int data1 = gpio_get_value(Readers[0][2]);

w->bufferbit[w->currentBit]=«1»; или «0» И все равно фигня какая-то получается. Может быть потому что там работаю с таймером, чтобы проверить что считывание закончилось ? del_timer(&timer); w->currentBit++;

//if we don't get another interrupt for 50ms we //assume the data is complete.... timer.expires = jiffies + msecs_to_jiffies(50); add_timer(&timer);

пример кода я конечно содрал. Если убрать из обработчика прерывания работу с таймером - как тогда определить конец считывания? Или занести этот анализ в тасклет и там уже проверять текущий бит, сколько считано и тп. Но это все имеет смысл, если все биты четко будут обрабатываться прерываниями. А пока такой резльтат не достигнут

gabirx
() автор топика

проверил на осцилоскопе - все 26 бит приходят нормально. проблема в том, что не все обработчики прерываний успевают отрабатывать :(

gabirx
() автор топика
Ответ на: комментарий от gabirx

Убрал все кроме назначения таймера в обработчике прерывания. Все время разный результат. от 10 до 22 срабатываний обработчика. разве может такое быть ?Как тогда сеть работает и карточки, если половина прерываний может пропасть

gabirx
() автор топика

Подскажите как правильно работать с GPIO в контексте реалтайма из модуля ядра ?

Если кратко - никак. Linux не rtos и не ос для микроконтроллеров, хотя судя по хактеристикам протокола

Ширина импульсов обычно в диапазоне 20…200 мкс. Период следования импульсов — 300…3000 мкс.

ты что-то не так делаешь - не такие уж тут великие скорости

IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING

Зачем тебе прерывания по обоим фронтам - одного разве недостаточно ? или у дубины контроллер gpio нельзя так настроить ? Попробуй тогда по уровню а не по фронту триггер настроить.

anonymous
()
Ответ на: комментарий от anonymous

Я правильно понимаю что на момент падения напряжения с 3.3в до 0 ан GPIO1 сработает триггер IRQF_TRIGGER_FALLING и управление передается на мой обработчик прерывания по этому IRQ? Пробовал читать состояние GPIO через int data1 = gpio_get_value(Readers[0][2]); всегда в обработчике прерывания выдается 1. т.е. судя по всему не хватает скорости и на момент чтения на GPIO1 уже будет напряжение 3.3 вольта ? Что еще может влиять на обработку прерывания ?

gabirx
() автор топика
Ответ на: комментарий от gabirx

Я правильно понимаю что на момент падения напряжения с 3.3в до 0 ан GPIO1 сработает триггер IRQF_TRIGGER_FALLING

Да, а потом еще раз при переходе с 0 на 3.3 В при таких настройках - одно лишнее прерывание/2 переключения контекста

Пробовал читать состояние GPIO через int data1 = gpio_get_value(Readers[0][2]); всегда в обработчике прерывания выдается 1.

Покажи код - по одной строке ничего невозможно сказать.

Что еще может влиять на обработку прерывания ?

Говенный китайский allwinner который установлен в дубине - есть вообще примеры кода для него ? документации внятной понятное дело нет, но хз - он может вообще не способен по обоим фронтам работать, а в linux просто ошибка - порт для него же теже тупоголовые китайцы делали.

anonymous
()
Ответ на: комментарий от anonymous

Вот в инициализации модуля: irq_gpio01 = gpio_to_irq(Readers[0][1]); if (irq_gpio01<0) { printk(KERN_DEBUG"Unable to get irq number, %d\n",irq_gpio01); } if(request_irq(irq_gpio01,wiegand_data_isr,IRQF_TRIGGER_HIGH|IRQF_TRIGGER_LOW, «wiegand_data», &wiegand)) { printk(KERN_DEBUG"Can't register IRQ %d\n", irq_gpio01); return -EIO; }

irq_gpio02 = gpio_to_irq(Readers[0][2]); if (irq_gpio02<0) { printk(KERN_DEBUG"Unable to get irq number, %d\n",irq_gpio02);}

if(request_irq(irq_gpio02,wiegand_data_isr,IRQF_TRIGGER_HIGH|IRQF_TRIGGER_LOW, «wiegand_data», &wiegand)) { printk(KERN_DEBUG"Can't register IRQ %d\n", irq_gpio02); return -EIO; } init_timer(&timer); timer.function = wiegand_timer; timer.data = (unsigned long) &wiegand;

Вот сам обработчик прерывания: irqreturn_t wiegand_data_isr(int irq, void *dev_id) { struct wiegand *w = (struct wiegand *)dev_id; w->currentBit++; del_timer(&timer); timer.expires = jiffies + msecs_to_jiffies(50); add_timer(&timer); return IRQ_HANDLED; }

И вот по таймеру отслеживаем окончание передачи: void wiegand_timer(unsigned long data) { char *lcn; struct wiegand *w = (struct wiegand *) data; printk(«wiegand read %d bit complete\n»,w->currentBit); w->currentBit=0;

Вроде все по логике: повесили один обработчик прерывания на два прерывания по gpio1 и gpio0 И в примере модуля работы с GPIO только с userspace https://learn.sparkfun.com/tutorials/programming-the-pcduino/accessing-gpio-pins

gabirx
() автор топика
Ответ на: комментарий от gabirx

Вот в инициализации модуля

Нельзя было форматирование сделать или выложить на внешний ресурс ?

irq_gpio01 = gpio_to_irq(

а перед этим было сделано

gpio_request()

gpio_direction_input() ?

IRQF_TRIGGER_HIGH|IRQF_TRIGGER_LOW

Пипец, зачем вам _два_ прерывания на каждый бит ? LOW - этого достаточно.

anonymous
()
Ответ на: комментарий от anonymous

https://github.com/markjasonanderson/wiegand-linux/blob/master/wiegand-gpio.c Вот отсюда взят пример. Делаю вначале if(gpio_direction_input(Readers[0][1])) А вот gpio_request() не делал. Сейчас на ардуино леонардо сделали генератор сигнала падение на 200 мксек, потом поднятие на 1800 мк сек и так 26 раз. Отработали все 52 прерывания на rising и falling. Сделали по минимальным параметрам wiegand - не отрабатывает 20мк сек не хотит

gabirx
() автор топика
Ответ на: комментарий от gabirx

Посмотрел этот китайский говнокод - он никогда не возвращает ошибку, даже для не поддерживаемого режима IRQF_TRIGGER_RISING

https://github.com/linux-sunxi/linux-sunxi/blob/sunxi-3.4/drivers/gpio/gpio-s...

но он поддерживает генерацию прерываний только по спадающему фронту так что не надо тебе 2 прерывания на бит делать, достаточно IRQF_TRIGGER_FALLING, по уровню тут не совсем корректно.

А вот gpio_request() не делал.

ну и напрасно судя по этому

https://github.com/linux-sunxi/linux-sunxi/commit/dc010a6af0ecfbbbd1ce9142a44...

anonymous
()
Ответ на: комментарий от anonymous

Сделал gpio_request, убрал printk и gpio_get_value из обработчика - все равно не успевает прочитать. Как бы убрать таймер еще ? но все равно странно - как тогда все остальное по IRQ успевает работать, USB и тп...

gabirx
() автор топика
Ответ на: комментарий от gabirx

https://github.com/pcduino/c_enviroment/blob/master/sample/adxl345_test.c А тут у них тоже работа на уровне ядра. Ау гуру, почему прерывания не успевают отрабатывать ? Убрал даже все лишние модули, тепреь lsmod: Module Size Used by wiegand_gpio 2685 0 ubuntu@ubuntu:~$ cat /proc/interrupts CPU0 1: 7 sw_vic serial 7: 0 sw_vic sun4i-i2c.0 8: 0 sw_vic sun4i-i2c.1 9: 0 sw_vic sun4i-i2c.2 22: 4 sw_vic timer0 23: 43885 sw_vic aw clock event irq 24: 0 sw_vic sunxi-rtc alarm 27: 219 sw_vic dma_irq 28: 499 sw_vic sunxi-gpio 32: 114168 sw_vic sunxi-mmc 33: 0 sw_vic sunxi-mmc 35: 0 sw_vic sunxi-mmc 37: 0 sw_vic nand 38: 0 sw_vic sw_hcd_host0 39: 0 sw_vic ehci_hcd:usb2 40: 0 sw_vic ehci_hcd:usb4 46: 0 sw_vic g2d 53: 0 sw_vic cedar_dev 55: 15584 sw_vic eth0 60: 0 sw_vic ace_dev 64: 0 sw_vic ohci_hcd:usb3 65: 0 sw_vic ohci_hcd:usb5 101: 215 gpio-sunxi wiegand_data 103: 288 gpio-sunxi wiegand_data Err: 0 какие прерывания еще можно отключить ? или это не поможет ?

gabirx
() автор топика
Ответ на: комментарий от gabirx

Я использую следующие заголовки: #include <linux/module.h><----->/* Needed by all modules */ #include <linux/kernel.h><----->/* Needed for KERN_INFO */ #include <linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/timer.h>

#include <linux/tty.h> /* console_print() interface */ #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h>

#include <asm/irq.h> #include <mach/gpio.h>

gabirx
() автор топика
Ответ на: комментарий от gabirx

А тут мысль пришла, что если вернуться к чтению в цикле, раз уж прерывания не успевают отрабатывать ?

gabirx
() автор топика
Ответ на: комментарий от gabirx

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

Dennis7
()
Ответ на: комментарий от Dennis7

Да вижу, не ожидал что они в таком формате тут будут. Впрочем, замерял latency - минимальное 23, средняя 33. https://gist.github.com/gabirx/7264385 вот в удобоваримом виде.

gabirx
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.