2017-08-14 2 views
1

Je suis en train d'apprendre de l'exemple de Derek Molloy dans son livre "Explorer Raspberry Pi - Interfaçage avec le monde réel avec Embedded Linux". J'ai pris l'exemple au Listing 16-3, que malheureusement je n'ai pas pu trouver en ligne.Comment inclure trois gestionnaires d'IRQ dans un module de noyau?

L'exemple contient un code de module noyau pour une seule interruption. Il lit un signal depuis un bouton sur GPIO 17 et envoie une interruption pour allumer une LED sur GPIO 27. Le livre utilise la numérotation par défaut de la broche GPIO, donc je fais la même chose.

Ce que je veux faire est de modifier le code pour inclure 2 autres paires de boutons-LED. Je veux le faire comme ceci:

  • GPIO 17 se met en marche/arrêt GPIO 23
  • GPIO 27 se met en marche/arrêt GPIO 24
  • GPIO 22 se met en marche/arrêt GPIO 25

C'est le code modifié que j'utilise.

static unsigned int gpioDevice1 = 17; 
static unsigned int gpioDevice2 = 27; 
static unsigned int gpioDevice3 = 22; 
static unsigned int gpioButton1 = 24; 
static unsigned int gpioButton2 = 23; 
static unsigned int gpioButton3 = 25; 
static unsigned int irqNumber1On; 
static unsigned int irqNumber2On; 
static unsigned int irqNumber3On; 
static unsigned int buttonCounter1 = 0; 
static unsigned int buttonCounter2 = 0; 
static unsigned int buttonCounter3 = 0; 
static unsigned int totalCounter = 0; 
static bool devOn1 = 0; // Initial state of devices 
static bool devOn2 = 0; 
static bool devOn3 = 0; 

// prototype for the custom IRQ handler function, function below. Should I use IRQF_SHARED here? 

static irq_handler_t rpi3_gpio_irq_handler_1(unsigned int irq, void *dev_id, struct pt_regs *regs); 
static irq_handler_t rpi3_gpio_irq_handler_2(unsigned int irq, void *dev_id, struct pt_regs *regs); 
static irq_handler_t rpi3_gpio_irq_handler_3(unsigned int irq, void *dev_id, struct pt_regs *regs); 

/** LKM initialization function */ 

static int __init rpi3_gpio_init(void) { 
    int result1On = 0; 
    int result2On = 0; 
    int result3On = 0; 
    printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n"); 

    /* GPIO validation on the three devices */ 
    if (!gpio_is_valid(gpioDevice1) || !gpio_is_valid(gpioDevice2) || !gpio_is_valid(gpioDevice3)) { 
     printk(KERN_INFO "GPIO_TEST: invalid GPIO for Devices\n"); 
     return -ENODEV; //wouldn't using ENXIO is more appropriate than ENODEV? 
    } 

    /* Configuring GPIO pins for the pairs */ 
    gpio_request(gpioDevice1, "sysfs"); // request LED GPIO 
    gpio_direction_output(gpioDevice1, devOn1); // set in output mode 
    gpio_export(gpioDevice1, false); // appears in /sys/class/gpio 
    // false prevents in/out change 

    gpio_request(gpioDevice2, "sysfs"); 
    gpio_direction_output(gpioDevice2, devOn2); 
    gpio_export(gpioDevice2, false); 

    gpio_request(gpioDevice3, "sysfs"); 
    gpio_direction_output(gpioDevice3, devOn3); 
    gpio_export(gpioDevice3, false); 

    gpio_request(gpioButton1, "sysfs"); // set up gpioButton1 
    gpio_direction_input(gpioButton1); // set up as input 
    gpio_set_debounce(gpioButton1, 200); // debounce delay of 200ms to avoid erratic and uncontrolled interrupt 
    gpio_export(gpioButton1, false); // appears in /sys/class/gpio 

    gpio_request(gpioButton2, "sysfs"); 
    gpio_direction_input(gpioButton2); 
    gpio_set_debounce(gpioButton2, 200); 
    gpio_export(gpioButton2, false); 

    gpio_request(gpioButton3, "sysfs"); 
    gpio_direction_input(gpioButton3); 
    gpio_set_debounce(gpioButton3, 200); 
    gpio_export(gpioButton3, false); 

    printk(KERN_INFO "GPIO_TEST: button1 value is currently: %d\n", gpio_get_value(gpioButton1)); 
    irqNumber1On = gpio_to_irq(gpioButton1); // map GPIO to IRQ number 189? 
    printk(KERN_INFO "GPIO_TEST: button1 mapped to IRQ: %d\n", irqNumber1On); 

    printk(KERN_INFO "GPIO_TEST: button2 value is currently: %d\n", gpio_get_value(gpioButton2)); 
    irqNumber2On = gpio_to_irq(gpioButton2); // map GPIO to IRQ number 190? 
    printk(KERN_INFO "GPIO_TEST: button2 mapped to IRQ: %d\n", irqNumber2On); 

    printk(KERN_INFO "GPIO_TEST: button3 value is currently: %d\n", gpio_get_value(gpioButton3)); 
    irqNumber3On = gpio_to_irq(gpioButton3); // map GPIO to IRQ number 191? 
    printk(KERN_INFO "GPIO_TEST: button3 mapped to IRQ: %d\n", irqNumber3On); 

    /* Interrupt lines when tactile button is pressed */ 
    result1On = request_irq(irqNumber1On, // interrupt number requested 
      (irq_handler_t) rpi3_gpio_irq_handler_1, // handler function 
      // TO DO: Insert IRQF_SHARED here? 
      IRQF_TRIGGER_RISING, // on rising edge (press, not release) 
      "rpi3_gpio_handler", // used in /proc/interrupts 
      NULL); // *dev_id for shared interrupt lines shouldn't be NULL 
    printk(KERN_INFO "GPIO_TEST: IRQ request result for device 1 is: %d\n", result1On); 
    return result1On; 

    result2On = request_irq(irqNumber2On, 
      (irq_handler_t) rpi3_gpio_irq_handler_2, 
      IRQF_TRIGGER_RISING, 
      "rpi3_gpio_handler", 
      NULL); 
    printk(KERN_INFO "GPIO_TEST: IRQ request result for device 2 is: %d\n", result2On); 
    return result2On; 

    result3On = request_irq(irqNumber3On, 
      (irq_handler_t) rpi3_gpio_irq_handler_3, 
      IRQF_TRIGGER_RISING, 
      "rpi3_gpio_handler", 
      NULL); 
    printk(KERN_INFO "GPIO_TEST: IRQ request result for device 3 is: %d\n", result3On); 
    return result3On; 
} 

static void __exit rpi3_gpio_exit(void) { 

    printk(KERN_INFO "GPIO_TEST: button 1 value is currently: %d\n", gpio_get_value(gpioButton1)); 
    printk(KERN_INFO "GPIO_TEST: button 1 was pressed %d times\n", buttonCounter1); 
    printk(KERN_INFO "GPIO_TEST: button 2 value is currently: %d\n", gpio_get_value(gpioButton2)); 
    printk(KERN_INFO "GPIO_TEST: button 2 was pressed %d times\n", buttonCounter2); 
    printk(KERN_INFO "GPIO_TEST: button 3 value is currently: %d\n", gpio_get_value(gpioButton3)); 
    printk(KERN_INFO "GPIO_TEST: button 3 was pressed %d times\n", buttonCounter3); 
    printk(KERN_INFO "GPIO_TEST: in total the buttons was pressed %d times\n", totalCounter); 

    gpio_set_value(gpioDevice1, 0); // turn the LED off 
    gpio_unexport(gpioDevice1); // unexport the LED GPIO 
    free_irq(irqNumber1On, NULL); // free the IRQ number, no *dev_id? 
    gpio_unexport(gpioButton1); // unexport the Button GPIO 
    gpio_free(gpioDevice1); // free the LED GPIO 
    gpio_free(gpioButton1); // free the Button GPIO 

    gpio_set_value(gpioDevice2, 0); 
    gpio_unexport(gpioDevice2); 
    free_irq(irqNumber2On, NULL); 
    gpio_unexport(gpioButton2); 
    gpio_free(gpioDevice2); 
    gpio_free(gpioButton2); 

    gpio_set_value(gpioDevice3, 0); 
    gpio_unexport(gpioDevice3); 
    free_irq(irqNumber3On, NULL); 
    gpio_unexport(gpioButton3); 
    gpio_free(gpioDevice3); 
    gpio_free(gpioButton3); 

    printk(KERN_INFO "GPIO_TEST: Goodbye from the LKM!\n"); 
} 

/** GPIO IRQ Handler functions */ 

static irq_handler_t rpi3_gpio_irq_handler_1(unsigned int irq, void *dev_id, struct pt_regs *regs) { 
    devOn1 = !devOn1; // invert the LED state 
    gpio_set_value(gpioDevice1, devOn1); // set LED accordingly 
    printk(KERN_INFO "GPIO_TEST: Interrupt! (button 1 is %d)\n", 
    gpio_get_value(gpioButton1)); 
    buttonCounter1++; 
    totalCounter++; // global counter 
    return (irq_handler_t) IRQ_HANDLED; // announce IRQ handled 
} 

static irq_handler_t rpi3_gpio_irq_handler_2(unsigned int irq, void *dev_id, struct pt_regs *regs) { 
    devOn2 = !devOn2; 
    gpio_set_value(gpioDevice2, devOn2); 
    printk(KERN_INFO "GPIO_TEST: Interrupt! (button 2 is %d)\n", 
    gpio_get_value(gpioButton2)); 
    buttonCounter2++; 
    totalCounter++; 
    return (irq_handler_t) IRQ_HANDLED; 
} 

static irq_handler_t rpi3_gpio_irq_handler_3(unsigned int irq, void *dev_id, struct pt_regs *regs) { 
    devOn3 = !devOn3; 
    gpio_set_value(gpioDevice3, devOn3); 
    printk(KERN_INFO "GPIO_TEST: Interrupt! (button 3 is %d)\n", 
    gpio_get_value(gpioButton3)); 
    buttonCounter3++; 
    totalCounter++; 
    return (irq_handler_t) IRQ_HANDLED; 
} 

module_init(rpi3_gpio_init); 
module_exit(rpi3_gpio_exit); 

Pour obtenir les numéros IRQ que j'utilise gpio_to_irq() comme dans l'exemple, parce que je ne sais pas quelles valeurs seraient un nombre valide.

La première paire a bien fonctionné, mais les autres paires ne fonctionneront pas, peu importe combien de fois j'ai appuyé sur les boutons. Lorsque j'ai vérifié les numéros IRQ avec cat /proc/interruptsI got this display in the terminal. I've inverted the colors to make it easier to skim through

Il semble que seul le premier obtenir un numéro d'IRQ, qui est . Hypothétiquement, les deux autres devraient probablement obtenir et , mais ils ne sont pas là.

Les fonctions printk() également affichées uniquement les lignes pour irqnumber1On, tandis que les lignes de irqnumber2On et irqnumber3On ne sont pas apparus.

J'ai donné les interruptions NULL dev_id parce que je ne sais pas comment donner/lire ID pour les boutons. J'ai essayé des combinaisons de nombres aléatoires, comme , , et mais terminal dit warning: passing argument 5 of 'request_irq' makes pointer from integer without a cast. Alors, qu'est-ce que j'ai fait terriblement mal ici? Je suis coincé dessus pendant un bon moment. Dois-je essayer d'utiliser IRQF_SHARED? Mais il faut dev_id particulier pour chaque interruption (ou boutons dans ce cas). Mon esprit novice pense qu'il est tout à fait impossible de le faire.

PS: Je sais que le code a l'air désordonné et horrible, mais s'il vous plaît gardez avec moi.

PPS: Je pourrais effacer une partie du code si nécessaire.

Répondre

1

tout code après cette déclaration:

return result1On; 

ne sera jamais exécutée.

Cela signifie que les deux autres interruptions de bouton ne seront jamais traitées.

+0

Oups, j'ai raté ce point. Je vais essayer d'utiliser une structure alors. Je serai de retour après l'avoir essayé. –