Hallo, folgende Ausgangssituation: Ich möchte von einem Linux-System (Pandaboard) über die SPI-Schnittstelle Daten von einem AD-Wandler (ADS1255 von Texas Instruments) lesen. Der AD-Wandler hat einen DATA-READY Ausgang, der kurzzeitig high wird wenn eine Wandlung fertig ist. Nun möchte ich auf dem Pandaboard folgende Schritte durchführen: - Interrupt an GPIO-Pin um DATA-READY Signal auszuwerten (bei steigender Flanke) - anschließend Daten auslesen mit spidev-Treiber (kommt später dran) Der zugehörige GPIO-Pin ist unter /sys/class/gpio/gpioXX als input konfiguriert. Unter edge habe ich "rising" eingetragen. Wie kann ich in einem Linux-System einen Interrupt einrichten? Muss ich dazu einen eigenen Treiber schreiben? Bzw. ist mein GPIO-Pin so ausreichend konfiguriert? Ich hoffe ich habe mich einigermaßen verständlich ausgedrückt. Grüße Ruben
ob es der einzige Weg ist, weiss ich nicht, aber es geht auf jeden Fall sehr elegant mit einem Kernel-Modul. Hier kann man z.B. in der init-Funktion GPIOs auf Interrupts mappen und dann einen entsprechenden Callback hinterlegen:
1 | static int __init hirc_modinit(void) |
2 | {
|
3 | int result; |
4 | int i, nlow, nhigh; |
5 | |
6 | printk(KERN_INFO PFX "init starts\n"); |
7 | |
8 | /* Init read buffer. */
|
9 | result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); |
10 | if (result < 0) |
11 | return -ENOMEM; |
12 | |
13 | result = gpio_request (HIRC_GPIO, "hirc"); |
14 | |
15 | if (result) { |
16 | printk (KERN_ERR PFX "failed to request GPIO %d: %d\n", HIRC_GPIO, result); |
17 | return result; |
18 | }
|
19 | |
20 | gpio_direction_input (HIRC_GPIO); |
21 | |
22 | irq = gpio_to_irq (HIRC_GPIO); |
23 | |
24 | if (irq < 0) { |
25 | printk (KERN_ERR PFX "failed to map GPIO %d to interrupt: %d\n", HIRC_GPIO, irq); |
26 | |
27 | gpio_free (HIRC_GPIO); |
28 | |
29 | return irq; |
30 | |
31 | }
|
32 | |
33 | printk (KERN_INFO PFX "GPIO %d mapped to IRQ %d\n", HIRC_GPIO, irq); |
34 | |
35 | //set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
|
36 | |
37 | result = request_irq(irq, irq_handler, |
38 | //0,
|
39 | IRQF_DISABLED | IRQF_TRIGGER_RISING , |
40 | // IRQF_DISABLED | IRQF_TRIGGER_RISING ,
|
41 | HIRC_DRIVER_NAME, irq_id); |
42 | |
43 | switch (result) { |
44 | case -EBUSY: |
45 | printk(KERN_ERR PFX "irq %d busy\n", irq); |
46 | gpio_free (HIRC_GPIO); |
47 | return -EBUSY; |
48 | case -EINVAL: |
49 | printk(KERN_ERR PFX |
50 | "bad irq number or handler\n"); |
51 | gpio_free (HIRC_GPIO); |
52 | return -EINVAL; |
53 | default:
|
54 | printk(KERN_INFO PFX "irq %d, gpio %d obtained\n", irq, HIRC_GPIO); |
55 | break; |
56 | }
|
(Beispiel stammt aus einem Treiber fuer einen Infrarot-Empfaenger, der an einem GPIO haengt - allerdings handelt es sich um einen kleinen Router, nicht um ein Pandaboard). der Interrupt-Handler kann dann mit gpio_get_value den Pin lesen:
1 | static irqreturn_t irq_handler(int i, void *blah) |
2 | {
|
3 | struct timeval tv; |
4 | int dcd; |
5 | long deltv; |
6 | int data; |
7 | static int last_dcd = -1; |
8 | |
9 | while (1) { |
10 | dcd = gpio_get_value(HIRC_GPIO); |
11 | |
12 | if (dcd == last_dcd) { |
13 | return IRQ_HANDLED; |
14 | }
|
15 | |
16 | /* get current time */
|
17 | do_gettimeofday(&tv); |
18 | |
19 | deltv = tv.tv_sec-lasttv.tv_sec; |
20 | if (tv.tv_sec < lasttv.tv_sec || |
21 | (tv.tv_sec == lasttv.tv_sec && |
22 | tv.tv_usec < lasttv.tv_usec)) { |
23 | printk(KERN_WARNING PFX "AIEEEE: your clock just jumped backwards\n"); |
24 | printk(KERN_WARNING PFX |
25 | "%d %d %lx %lx %lx %lx\n", |
26 | dcd, sense, |
27 | tv.tv_sec, lasttv.tv_sec, |
28 | tv.tv_usec, lasttv.tv_usec); |
29 | data = PULSE_MASK; |
30 | } else if (deltv > 15) { |
31 | data = PULSE_MASK; /* really long time */ |
32 | #if 0
|
33 | printk (KERN_WARNING PFX "really long time: %ld\n", deltv);
|
34 | #endif
|
35 | } else |
36 | data = (int) (deltv*1000000 + |
37 | tv.tv_usec - |
38 | lasttv.tv_usec); |
39 | rbwrite(dcd^sense ? data : (data|PULSE_BIT)); |
40 | lasttv = tv; |
41 | last_dcd = dcd; |
42 | wake_up_interruptible(&rbuf.wait_poll); |
43 | }
|
44 | |
45 | return IRQ_HANDLED; |
46 | }
|
Hallo, ich habe den Vorschlag von Günter umgesetzt und das geht auch grundsätzlich. Allerdings tritt der Interrupt nur einmal auf. Meinem Verständnis nach muss ich im Interrupt-Handler den Interrupt wieder frei schalten. Hat da jemand einen Tipp für mich? Vielen Dank im voraus. Ruben
IRQF_DISABLED | IRQF_TRIGGER_RISING Flag könnte Falsch sein setze mal statt desse eine 0 rein.
Hallo, sowas habe ich versucht mit einem Linux FOX Board. Sollte dann ja auch möglich sein damit. Ein Tip zum DRDY Signal. Bei richtiger Behandlung, also wenn man die Daten ausliest, müsste das DRDY Signal mit der ersten Clk-Flanke wieder auf High gehen, also muss man den ISR auf negative Flanke stellen, dann kann man im Wandlertakt( z.B. 1000Hz ADS1281) die 3 bzw 4 Bytes auslesen. Klappt prima bei mir, leider nicht mit Linux. Bernd
Hallo, sorry das ich den alten Thread nochmal ausgrabe aber ich habe ein ähnliches Problem: ich möchte einen GPIO als Interrupt nutzen und beim eintreten des Interrupts eine Aktion auslösen. Das Programmieren das Kernelmoduls ist kein Problem, ABER: Weiß jemand ob es möglich ist aus dem Interrupt-Handler heraus ein Aktion im Userspace aufzurufen, z.B. ein Programm starten?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.