I3MPS_Opgave6

I denne opgave skal vi arbejde med interrupts. Vi arbejder her kun med at implementere interrupt på GPIO 130.

Implementer Interrupt
For at opsætte et interrupt, indsætter vi følgende i vores init funktion: code format="c" /* * Request IRQ Line */

request_irq(gpio_to_irq(130), irqHandleFunc, IRQF_TRIGGER_RISING, "GPIO", NULL); // Funktion til erklæring af interrupt printk(KERN_ALERT "IRQ Requestet\n"); // Besked at vi har requested IRQ code Vi har også følgende i vores exit funktion, for frigive interrupt requested igen. code format="c" /* * Release IRQ */ free_irq(gpio_to_irq(130), NULL); printk(KERN_ALERT "IRQ Released\n"); code Vi kompilerede modulet, og indsatte det i kernen. Herefter kunne vi lave "cat /proc/interrupts" og se følgende linje code ... 187:      2737     GPIO ads7846 290:       289     GPIO GPIO // Vores interrupt 368:         0  twl4030 twl4030_gpio ... code

Implementer ISR
For at implementere vores ISR, tilføjede vi følgende kode: code format="c" irqreturn_t irqHandleFunc(int irq, void *dev_id) {   printk(KERN_ALERT "IRQ Event!\n"); // Skriver besked om IRQ return IRQ_HANDLED; // Sender besked tilbage til systemet, om IRQ er behandlet } code Denne funktion behandler vores IRQ, ved at skrive en besked, og derefter gå tilbage til systemet. Efter at have kompileret og indsat modulet, kunne vi ved at skifte vores indgang mellem høj og lav, få følgende output: code 2000 Jan 1 00:30:36 beagleboard  [ 1839.941192] IRQ Event! 2000 Jan 1 00:30:36 beagleboard  [ 1839.959991] IRQ Event! 2000 Jan 1 00:30:36 beagleboard  [ 1839.962493] IRQ Event! code Her kan vi se at der bliver genereret et interrupt, og kernen afvikler denne.

Implementer "Read"
For at kunne bruge interrupts, til at sætte vores read på pause, skal vi først tilføje til vores read, så den venter på signal, om at må starte op igen, derefter skal vi ændre vores ISR, så denne sender signalet til read, om at den må fortsætte. code format="c" // Erklæring af elementer til brug i interrupt int activeIRQ = 0; DECLARE_WAIT_QUEUE_HEAD(irqQueue);

irqreturn_t irqHandleFunc(int irq, void *dev_id) {   printk(KERN_ALERT "IRQ Event!\n"); activeIRQ = 1; wake_up_interruptible(&irqQueue); return IRQ_HANDLED; }

...

ssize_t mygpio_read(struct file *filep, char __user *buf, size_t count, loff_t *f_pos) {   ...    /*     * Wait for read ready signal * Placeret inden aflæsning af GPIO port. */

wait_event_interruptible(irqQueue, activeIRQ != 0); activeIRQ = 0; ... } code Link til fuld source code

Hvor skal request_irq ligge?
Vi har valgt at ligge vores request irq request i init, for at sikre at vi har denne gennem hele driveren. Det er dog også muligt at ligge denne i open, så vi kun holder på denne, når der er behov for den.

Hvor skal aflæsning af GPIO foregå?
GPIO skal aflæses i read funktionen. Når read funktionen bliver kaldt normalt, bliver den blokeret, indtil der kommer noget nyt data. Denne nye data aktiver vores ISR, som så unblocker vores read funktion, så den kan fortsætte med aflæsningen. Derudover, hvis aflæsningen lå i vores ISR funktion, skulle vores data enden behandles der, eller sendes tilbage til read funktionen. Behandlingen af data i ISR vil være uhensigtsmæssigt, da en ISR skal være så kort som mulig.