GPIO access with interrupts and /sys/class/gpio



  • For some time I have been working on GPIO access from C/C++ (see https://community.onion.io/topic/143/alternative-c-code-for-gpio-access) - this all works as required. For reference, my C/C++ code works by manipulating the relevant bits in the following GPIO registers:

    • 0x18040000 GPIO_OE General Purpose I/O Output Enable
    • 0x18040004 GPIO_IN General Purpose I/O Input Value
    • 0x18040008 GPIO_OUT General Purpose I/O Output Value
    • 0x1804000C GPIO_SET General Purpose I/O Bit Set
    • 0x18040010 GPIO_CLEAR General Purpose I/O Per Bit Clear

    See https://www.openhacks.com/uploadsproductos/ar9331_datasheet.pdf - page 65 and onwards for definition of GPIO registers.

    However, I am still having trouble trying to come up with a method of getting interrupts for change of value for GPIO input pins.

    In my research for this, I came across this reference (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt) for GPIO access via sysfs.
    Experimenting with this sysfs access on the Omega shows that in general it matches the documentation and in particular operations via sysfs are reflected in the results from my C/C++ code and vice versa.

    However, I have noted that when using the sysfs access, there is no file /sys/class/gpio/gpioN/edge as listed in the documentation.
    The documentation indicates that this is because the GPIO pin is not configured to generate interrupts. To quote:
    This file exists only if the pin can be configured as an
    interrupt generating input pin.

    So, I made some changes to my C/C++ code to set the various relevant bits in the following GPIO registers:

    • 0x18040014 GPIO_INT General Purpose I/O Interrupt Enable
    • 0x18040018 GPIO_INT_TYPE General Purpose I/O Interrupt Type
    • 0x1804001C GPIO_INT_POLARITY General Purpose I/O Interrupt Polarity
    • 0x18040020 GPIO_INT_PENDING General Purpose I/O Interrupt Pending
    • 0x18040024 GPIO_INT_MASK General Purpose I/O Interrupt Mask

    And I have also implemented changes to my code to perform poll() access to the /sys/class/gpio/gpioN/value file using POLLPRI event. But with no luck event though separately monitoring /sys/class/gpio/gpioN/value indicates that its value is changing correctly with change of pin level.
    Using POLLIN event on poll() doesn't work either - it always returns irrespective of whether the **/sys/class/gpio/gpioN/value has changed or not. (See https://developer.ridgerun.com/wiki/index.php?title=Gpio-int-test.c and https://github.com/larsks/gpio-watch/blob/master/main.c for reference example of using sysfs GPIO access and poll())

    But irrespective of how I set the GPIO interrupt register bits nothing makes any difference to the existence of /sys/class/gpio/gpioN/edge nor to the effectiveness of the use of poll()

    My suspicions is that either:

    • There is something I haven't done that I need to do
    • Or that there is something in the way that sysfs works /sys/class/gpio that stops the usage of the interrupts and /sys/class/gpio/gpioN/edge

    Does any one have any thoughts or ideas that might assist me?



  • Hi @Kit-Bishop, This is a problem that I have been looking at for some time as well. My understanding is that in order for the edge file to show up we will need to implement a kernel driver for GPIOs that can poll on the GPIO value. What we have done with fast-gpio and your alternative GPIO access library are just libraries that gets and sets the registers, but we still need to figure out a way to hook that into the kernel so the kernel can say, "oh look, this drive will tell me when the GPIO values have changed, so I'll create the edge file for them".

    This is just my understanding of it. Let me know what you think.

    PS. This is an very good article for anyone who's interested in understanding a bit more about how the kernel interacts with GPIOs on a machine: https://lwn.net/Articles/532714/.



  • @Boken-Lin Thanks for your response.

    I have been struggling to get a kernel module that could deal with GPIO interrupts and when I saw the reference I gave above () I hoped that this could be a way to go.

    I have seen similar documentation to what you referenced and while I basically understand it, it (like most else I have found) is pretty sketchy on details.
    I would also note that the reference you gave makes reference to https://lwn.net/Articles/532717/ where it also says:

    • Sysfs Interface for Userspace (OPTIONAL)
      ========================================
      Platforms which use the "gpiolib" implementors framework may choose to
      configure a sysfs user interface to GPIOs.

    Which also makes reference to /sys/class/gpio/gpioN/edge and to use of poll() for handling GPIO interrupts in user space.

    Consequently, since /sys/class/gpio/gpioN/edge is not available on the Omega it would imply that the sysfs for GPIO on the Omega does not implement this functionality.

    So, it seems to me that there are 2 possible options:

    1. Write a kernel mode driver/module that gives access to some form of interrupt handling facility
    2. Modify the implementation of sysfs for GPIO so that it implements the /sys/class/gpio/gpioN/edge functionality.

    My problems are:
    a. I am not all that experienced in the ins and outs of writing, building and installing kernel mode code
    b. I don't know where to find the sources for sysfs for GPIO for the Omega otherwise I would plunge in and see if I could figure out what changes it needed to provide /sys/class/gpio/gpioN/edge



  • @Kit-Bishop Found this after some googling. I tried applying the patch and recompiled, but I still don't see the edge file. I will play around with it some more when i have time. Let me know if it's helpful.



  • @Boken-Lin Thanks. But I assume there was supposed to be a link in your latest post - I don't see it šŸ˜ž



  • Hi @Kit-Bishop, i meant to show you this link: https://github.com/GBert/openwrt-misc/tree/master/gpio-test/src. My apologies.



  • @Boken-Lin Thanks - had already found this. I think some of my issues to date have been to do with my mistakes in building kernel code using the OenWRT cross compilation - I think I had some settings wrong. Am in the process of trying again with git://git.openwrt.org/15.05/openwrt.git - will let you know how things go.



Looks like your connection to Community was lost, please wait while we try to reconnect.