Search code examples
c++armembedded-linuxgpiosysfs

nirq: Flags mismatch irq 80. 00002083 (ledtrig-gpio) vs. 00000083 (USER)


I am doing some experiments on SAMA5D27-SOM1-EK1 board. I am using Linux operating system. I am exploiting GPIOS of my board. There is RED LED defined at GPIO 10 and USER button defined at GPIO 29. I wrote C++ program to control LED of the board and here is the code :

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

#define LED0_PATH "/sys/class/leds/red"

void removeTrigger(){
   // remove the trigger from the LED
   std::fstream fs;
   fs.open( LED0_PATH "/trigger", std::fstream::out);
   fs << "none";
   fs.close();
}

int main(int argc, char* argv[]){
   if(argc!=2){
 cout << "Usage is makeLED and one of: on, off, flash or status"
<< endl;
 cout << "e.g. makeLED flash" << endl;
   }

   string cmd(argv[1]);
   std::fstream fs;
   cout << "Starting the LED flash program" << endl;
   cout << "The LED Path is: " << LED0_PATH << endl;


 // select whether it is on, off or flash
   if(cmd=="on"){
 removeTrigger();
 fs.open (LED0_PATH "/brightness", std::fstream::out);
 fs << "1";
 fs.close();
   }

   else if (cmd=="off"){
 removeTrigger();
 fs.open (LED0_PATH "/brightness", std::fstream::out);
 fs << "0";
 fs.close();
   }

   else if (cmd=="flash"){
 fs.open (LED0_PATH "/trigger", std::fstream::out);
 fs << "timer";
 fs.close();
 fs.open (LED0_PATH "/delay_on", std::fstream::out);
 fs << "50";
 fs.close();
 fs.open (LED0_PATH "/delay_off", std::fstream::out);
 fs << "50";
 fs.close();
   }

   else if (cmd=="status"){
 // display the current trigger details
 fs.open( LED0_PATH "/trigger", std::fstream::in);
 string line;
 while(getline(fs,line)) cout << line;
 fs.close();
 }

   else{
 cout << "Invalid command" << endl;
 }

cout << "Finished the LED flash program" << endl;
       return 0;

This seems to work fine : When I tape ./target_bin off the Red Led turn off and the same for on and flash commands.

But when I tried to control LED ( RED / GPIO 10 ) with BUTTON ( USER / GPIO 29 ) I added this part of code :

else if (cmd=="button"){
        removeTrigger();
        fs.open (LED0_PATH "/trigger", std::fstream::out);
        fs << "gpio";
        fs.close();
        fs.open (LED0_PATH "/gpio", std::fstream::out);
        fs << "29";
        fs.close();
   }

And now when I tape ./target_bin button It shows me an error :

nirq: Flags mismatch irq 80. 00002083 (ledtrig-gpio) vs. 00000083 (USER) leds red: request_irq failed with error -16

Can Anyone help me out please ?


Solution

  • And now when I tape [sic] ./target_bin button It shows me an error :

    nirq: Flags mismatch irq 80. 00002083 (ledtrig-gpio) vs. 00000083 (USER) leds red: request_irq failed with error -16

    Error 16 is "Device or resource busy".
    The device or resource in question is the gpio_key for the push button.
    Note that the error message mentions "USER", which happens to be the label assigned to the gpio_key for the push button in the Device Tree file at91-sama5d27_som1_ek.dts.

    gpio_keys {
        ...
        pb4 {
            label = "USER";
            gpios = <&pioA PIN_PA29 GPIO_ACTIVE_LOW>;
            ...
        };
    };
    

    In order for GPIO 29 to be used as a LED trigger, it must be an available, i.e. unused, GPIO.
    However the default dts file configures that GPIO 29 to be a gpio_key, and therefore that GPIO is owned by the gpio_key driver.
    GPIO 29 is not an unused pin, and is not available for use as a LED trigger (i.e. ownership cannot be transferred to the ledtrig-gpio driver).

    You can either use the push-button gpio_key as an input-event device as currently configured, or reconfigure the GPIO 29 so that it is not a gpio_key and available for use as a LED trigger.


    ADDENDUM
    [responses to comments]

    But when i search for the devices which are " USED " on my board with gpioinfo | grep "[used]" command I find that RED led is used before I run my program : line 10: "PA10" "red" output active-high [used] but my code does not show an error for it.

    Are you complaining that you did not get a LED error?
    I fail to understand what point you are trying to make.

    Why would it show an error for BUTTON ...

    As I already explained the dts file configures GPIO 29 (i.e. the push button) to be a gpio_key, and assigning GPIO 29 to be a LED trigger causes a conflict.

    To be more specific, the LED trigger driver (ledtrig-gpio) requires that the interrupt be configured for "one-shot" mode.

     * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
     *                Used by threaded interrupts which need to keep the
     *                irq line disabled until the threaded handler has been run.
     ...
    #define IRQF_ONESHOT        0x00002000
    

    This (new) interrupt mode (i.e. 0x00002083) conflicts with the existing mode/flags (i.e. 0x00000083) established by the gpio_keys driver.
    This conflict means that this GPIO cannot be used simultaneously for both a gpio_key (input event) and a LED trigger.
    Therefore you have to choose in which mode this GPIO will operate.

    ... and not for LED ?

    You mean you want the error to occur on the LED?
    You don't get to choose which device causes an error when you perform a specific operation.

    The operation you requested, i.e. assign a specific GPIO (which is already installed as a gpio_key) to be the LED trigger, failed during the assignment of the (new) interrupt handler for the gpio_key.
    So the error is reported for the gpio_key, and not the LED.


    For further confirmation to quell your doubts:
    Since the error message mentions "irq 80", you should look up this "irq 80" in the /proc/interrupts file on your board.
    That file should indicate that "irq 80" is associated with "GPIO 29" (which per the DT is a gpio_key).

    For yet another procedure to quell your doubts:
    Locate an unused PIO pin that is accessible and unused (by any peripheral or any driver/process as a gpio).
    Assign that pin as the LED trigger.
    No error should occur (assuming you selected an unused pin).
    Short the pin to ground or VDD_3V3 to change the (default) state of the LED.


    How can I reconfigure the button USER so that it is not a gpio_key and be available for use as a LED trigger ?

    As I already wrote, the Device Tree file at91-sama5d27_som1_ek.dts is where the GPIO with the push button is declared to be a gpio_key, and I also posted a snippet of the salient lines of that node.
    If you do not want that GPIO to be configured as a gpio_key, then the Device Tree file needs to be modified by removing that node (and of course recompiled into a dtb).