Pytanie:
Odbicie przerwania GPIO
Flavio Barisi
2013-07-22 12:02:44 UTC
view on stackexchange narkive permalink

Postępowałem zgodnie z tym przewodnikiem, Raspberry Pi GPIO przerywa w przestrzeni jądra, aby utworzyć moduł jądra obsługujący przerwania GPIO. Problem polega na tym, że ten kod nie ma zaimplementowanego usuwania oprogramowania.

Czy możesz mi dać radę, jak zaimplementować usuwanie oprogramowania lub alternatywnie, jak łatwo wdrożyć system usuwania sprzętu?

Możesz przenieść swój kod do sekcji odpowiedzi (możesz odpowiedzieć na własne pytania). W ten sposób byłoby znacznie czystsze. Pamiętaj, to nie jest forum.
Pięć odpowiedzi:
#1
+7
Butters
2013-07-22 19:37:06 UTC
view on stackexchange narkive permalink

Nigdy nie próbowałem tego robić, nie RPi, ale kilkakrotnie korzystałem z platformy Arduino i używałem czegoś podobnego do tego kodu Arduino. Zauważ, że będziesz musiał przepisać funkcję podobną do tej dla dowolnego używanego języka:

  unsigned long last_interrupt_time = 0; void my_interrupt_handler () {unsigned long przerwania_czasu = millis (); // Jeśli przerwania przychodzą szybciej niż 200 ms, załóżmy, że to odbijanie i zignoruj ​​if (przerwanie_czas - last_interrupt_time > 200) {... Przerwanie ok, zrób coś; } last_interrupt_time = przerwanie_czas;}  
ok, zrobiłem to ... millis () nie jest funkcją Raspberry, więc musiałem to zaimplementować samodzielnie. Oto zmodyfikowany kod źródłowy
@FlavioBarisi Przepraszam za to. To jest kod dla Arduino, zamieszczony tylko jako przykład. Nie miałem wczoraj czasu na przepisanie tego w Pythonie C. Zanotuję to w odpowiedzi.
#2
+1
lenik
2013-07-22 16:50:20 UTC
view on stackexchange narkive permalink

Najprostszym jest debouncer sprzętowy, który składa się z filtru RC, po którym następuje wyzwalacz schmitta lub po prostu filtr RC, jeśli jesteś leniwy. części są tanie, dostępne wszędzie i można je łatwo dostosować do dowolnego obwodu, który zamierzasz podłączyć do swojego Raspberry Pi.

#3
+1
Flavio Barisi
2013-07-23 12:03:24 UTC
view on stackexchange narkive permalink

Zrobione!

  #include <linux / module.h> # include <linux / kernel.h> # include <linux / init.h> # include Ailtigjhmknltlinux / kernel.h> # include <linux / init.h> # include Ailtigjuxknhmlio. h> # include <linux / time.h> # define DRIVER_AUTHOR "Igor <[email protected]>" #define DRIVER_DESC "Tnterrupt Test" // chcemy wygenerować pin 11 GPIO_517 (pin 11 na GPIO_17). przerwanie # zdefiniowanie GPIO_ANY_GPIO 17 // poniższy tekst będzie widoczny w poleceniu 'cat / proc / przerwać' # define GPIO_ANY_GPIO_DESC "Jakiś opis pinów GPIO" // poniżej jest opcjonalny, używany w bardziej złożonym kodzie, w naszym przypadku może to być / / NULL # define GPIO_ANY_GPIO_DEVICE_DESC "some_device" / ***************************************** *********************************** // * Przerywa blok zmiennych * // ****** ********************************* ************************************* / short int irq_any_gpio = 0; unsigned int last_interrupt_time = 0; statyczny uint64_t epochMilli; unsigned int millis (void) {struct timeval tv; uint64_t teraz; do_gettimeofday (&tv); teraz = (uint64_t) tv.tv_sec * (uint64_t) 1000 + (uint64_t) (tv.tv_usec / 1000); return (uint32_t) (teraz - epochMilli);} / ************************************** ************************************** // * Obsługa IRQ - uruchamiana po przerwaniu * // ************************************************ ************************* / static irqreturn_t r_irq_handler (int irq, void * dev_id, struct pt_regs * regs) {unsigned long flag; unsigned int breaking_time = millis (); if (czas_przerwania - last_interrupt_time < 1000) {printk (KERN_NOTICE "Ignored Interrupt !!!!! [% d]% s \ n", irq, (char *) dev_id); return IRQ_HANDLED; } last_interrupt_time = czas_przerwania;
// wyłącz twarde przerwania (zapamiętaj je pod flagą 'flagi') local_irq_save (flagi); printk (KERN_NOTICE "Przerwanie [% d] dla urządzenia% s zostało wywołane!. \ n", irq, (char *) dev_id); // przywróć twarde przerwania local_irq_restore (flagi); return IRQ_HANDLED;} / ******************************************* ******************************* // * Ta funkcja konfiguruje przerwania. * // *********************************************** ***************************** / void r_int_config (void) {struct timeval tv; do_gettimeofday (&tv); epochMilli = (uint64_t) tv.tv_sec * (uint64_t) 1000 + (uint64_t) (tv.tv_usec / 1000); if (gpio_request (GPIO_ANY_GPIO, GPIO_ANY_GPIO_DESC)) {printk ("Błąd żądania GPIO:% s \ n", GPIO_ANY_GPIO_DESC); powrót; } if ((irq_any_gpio = gpio_to_irq (GPIO_ANY_GPIO)) < 0) {printk ("Faiure mapowania GPIO na IRQ% s \ n", GPIO_ANY_GPIO_DESC); powrót; } printk (KERN_NOTICE "Zamapowany int% d \ n", irq_any_gpio); if (request_irq (irq_any_gpio, (irq_handler_t) r_irq_handler, IRQF_TRIGGER_FALLING, GPIO_ANY_GPIO_DESC, GPIO_ANY_GPIO_DEVICE_DESC)) {printk ("Błąd żądania Irq \ n"); powrót; }   powrót;}/********************************************* ******************************* // * Ta funkcja zwalnia przerwania. * // *********************************************** ***************************** / void r_int_release (void) {free_irq (irq_any_gpio, GPIO_ANY_GPIO_DEVICE_DESC); gpio_free (GPIO_ANY_GPIO); powrót;}/********************************************** ****************************** // * Blok inicjalizacji / czyszczenia modułu. * // *********************************************** ***************************** / int r_init (void) {printk (KERN_NOTICE "Witaj! \ n"); r_int_config (); return 0;} void r_cleanup (void) {
printk (KERN_NOTICE "Do widzenia \ n"); r_int_release (); return;} module_init (r_init); module_exit (r_cleanup); / ************************************ **************************************** // * Blok licencji / opisu modułu. * // *********************************************** ***************************** / MODULE_LICENSE („GPL”); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC);  
#4
+1
John D
2015-02-11 21:24:14 UTC
view on stackexchange narkive permalink

Zrobiłem to, sprawdzając migawki zamiast czasu. Myślę, że w ten sposób jest mniej narzutów. Jednak nadal staram się ulepszyć algorytm odbijania, ponieważ nie jestem z niego w pełni zadowolony: nadal istnieją odbijania, chociaż są one rzadsze niż wcześniej.

  #include <linux / jiffies.h>extern unsigned long volatile jiffies; static irqreturn_t irq_handler (int irq, void * dev_id, struct pt_regs * regs) {static unsigned long old_jiffie = 0; unsigned long diff = jiffies - old_jiffie; if (diff < 20) {return IRQ_HANDLED; } printk (KERN_NOTICE "Przerwanie [% d] dla urządzenia% s zostało wywołane, jiffies =% lu, diff =% lu, direction:% d \ n", irq, (char *) dev_id, jiffies, diff, gpio_get_value (GPIO_BUTTON1 )); old_jiffie = jiffies; return IRQ_HANDLED;}  

Udało mi się jeszcze bardziej udoskonalić algorytm odbijania. Teraz wyzwalam przerwanie, gdy linia osiągnie LOW zamiast opadającej krawędzi. Następnie w obsłudze przerwań zmieniam przerwanie, aby następnym razem było wyzwalane na WYSOKIE, potem na NISKIE i tak dalej. To w połączeniu z metodą jiffies z góry znacznie zmniejsza odbicia.

Myślę, że to najlepsze, co można osiągnąć w oprogramowaniu. Dla dalszych ulepszeń myślę, że rzeczywiście trzeba to zrobić w sprzęcie. Kiedy będę miał czas, spróbuję z kondensatorem i tym podobnymi rzeczami.

Pełny kod poniżej:

  #include <linux / module.h> #include <linux / kernel .h> #include <linux / init.h> # include <linux / interrupt.h> # include <linux / gpio.h> # obejmują <linux / irq.h> # include <linux / jiffies.h> #define DRIVER_AUTHOR "" #define DRIVER_DESC "pad Przycisk" extern unsigned long volatile jiffies; struct _Button {unsigned gpio; int irq; const char * opis; char last_value;}; typedef struct _Button Button;
// chcemy, aby GPIO 17,27,22 (pin 11,13,15 na płytce pinout raspberry pi rev. 2 P5) generowało przerwanieButton button1 = {17, 0, "Gpio dla przycisku 1", 1}; Button button2 = {27, 0, "Gpio dla przycisku 2", 1}; Button button3 = {22, 0, "Gpio dla przycisku 3", 1}; / **************** ************************************************ ********** // * Obsługa IRQ - uruchamiana przy przerwaniu * // **************************** ************************************************/statyczny irqreturn_t irq_handler (int irq, void * dev_id, struct pt_regs * regs) {Button * button = (Button *) dev_id; wartość znaku = gpio_get_value (przycisk->gpio); if (wartość == button->last_value) return IRQ_HANDLED; if (0 == wartość) {static unsigned long old_jiffie = 0; unsigned long diff = jiffies - old_jiffie; if (diff < 23) {button->last_value = wartość; irq_set_irq_type (irq, IRQ_TYPE_LEVEL_HIGH); // old_jiffie = jiffies; return IRQ_HANDLED; } printk (KERN_NOTICE "Przerwanie [% d] dla urządzenia% s zostało wywołane, jiffies =% lu, diff =% lu, direction:% d \ n", irq, button->description, jiffies, diff, value); irq_set_irq_type (irq, IRQ_TYPE_LEVEL_HIGH); old_jiffie = jiffies; } else {irq_set_irq_type (irq, IRQ_TYPE_LEVEL_LOW); } button->last_value = wartość; return IRQ_HANDLED;} / ******************************************* ******************************* // * Ta funkcja konfiguruje przerwania. * // *********************************************** ***************************** / void int_config (przycisk * przycisk) {if (! przycisk || gpio_request (przycisk->gpio, button->description)) {printk ("Błąd żądania GPIO:% s \ n", button->description); powrót; } gpio_direction_input (button->gpio);
if ((button->irq = gpio_to_irq (button->gpio)) < 0) {printk ("Faiure mapowania GPIO na IRQ% s \ n", button->description); powrót; } printk (KERN_NOTICE "Mapowany int% d \ n", przycisk->irq); if (request_irq (button->irq, (irq_handler_t) irq_handler, IRQF_TRIGGER_LOW, button->description, button)) {printk ("Błąd żądania Irq \ n"); powrót; }   powrót;}/********************************************* ******************************* // * Ta funkcja zwalnia przerwania. * // *********************************************** ***************************** / void int_release (przycisk * przycisk) {free_irq (przycisk->irq, przycisk); gpio_free (button->gpio); return;} int init_module (void) {printk (KERN_INFO "init_module () o nazwie \ n"); int_config (&button1); int_config (&button2); int_config (&button3); return 0;} void cleanup_module (void) {printk (KERN_INFO "cleanup_module () o nazwie \ n"); int_release (&button1); int_release (&button2); int_release (&button3);} / ***************************************** ********************************* // * Blok licencji / opisu modułu. * // *********************************************** ***************************** / MODULE_LICENSE ("GPL"); MODULE_AUTHOR (""); MODULE_DESCRIPTION ("Sterownik GPIO RaspeberryPi ");  
#5
+1
electron1979
2018-10-03 10:48:13 UTC
view on stackexchange narkive permalink

A co jeśli monitorujesz poprzednią wartość / stan pinu / GPIO?

Musiałem użyć usleep () w pętli while, aby uniknąć szarpania się / wyścigów procesora, Zobacz tę odpowiedź na C, błąd kompilacji podczas używania funkcji „usleep”.

Działa to w moim celu:

  #include <unistd.h>uint8_t prevStatus; void sendStatus (void) {uint8_t status = digitalRead (ISR_Pin); if (prevStatus! = status) {if (status == 0) spada (); jeszcze rośnie (); } prevStatus = status;} int main (void) {/// Upewnij się, że WiringPi jest zainstalowane i skonfigurowane if (iringPiSetup () == -1) exit (1); /// Ustaw GPIO jako INPUT, z rozwijanym pinMode (ISR_Pin, INPUT); pullUpDnControl (TISR_Pin, PUD_DOWN); // Jeśli potrzebujesz tego lub PUD_UP do podciągania /// Konfiguracja przerwań sprzętowych dla OBU spadających & Rising Edge okablowaniePiISR (ISR_Pin, INT_EDGE_BOTH, &sendStatus); /// Czekaj na zmianę kodu PIN ISR_Pin while (1) {usleep (50000); } return (0);}  


To pytanie i odpowiedź zostało automatycznie przetłumaczone z języka angielskiego.Oryginalna treść jest dostępna na stackexchange, za co dziękujemy za licencję cc by-sa 3.0, w ramach której jest rozpowszechniana.
Loading...