From: Paul B. <pb...@si...> - 2011-11-18 15:58:49
|
I've been testing the sysfs interface to use GPIOs on a Gumstix Overo and it seems to work properly except for interrupts. It would be handy to be able to user GPIO interrupts in user space. As described in http://www.kernel.org/doc/Documentation/gpio.txt, under "Sysfs Interface for Userspace (OPTIONAL)": Once a particular GPIO has been exported, a string of "rising", "falling", etc. can be written to /sys/class/gpio/gpioN/edge to configure it as an interrupt. To block on the interrupt, a poll(2) is done on /sys/class/gpio/gpioN/value (where N is the GPIO number). When I try this using GPIO14 it doesn't block on the interrupt, although I can read the correct value of the pin. Here's the code: #include <stdio.h> /* For printf() */ #include <string.h> /* For strerror() */ #include <unistd.h> /* For read(), close() */ #include <fcntl.h> /* For open() */ #include <errno.h> /* For errno */ #include <sys/poll.h> /* For poll() */ #define ERREXIT(str) {printf("err %s, %s\n", str, strerror(errno)); return -1;} int main(int argc, char** argv) { struct pollfd xfds[1]; const char *fn; char buf[4]; int rc; int fd; int i; /* export */ fn = "/sys/class/gpio/export"; fd = open(fn, O_WRONLY); if(fd < 0) ERREXIT("open export") rc = write(fd, "14", 3); if(rc != 3) ERREXIT("write export") close(fd); /* direction */ fn = "/sys/class/gpio/gpio14/direction"; fd = open(fn, O_RDWR); if(fd < 0) ERREXIT("open direction") rc = write(fd, "in", 3);if(rc != 3) ERREXIT("write direction") close(fd); /* edge */ fn = "/sys/class/gpio/gpio14/edge"; fd = open(fn, O_RDWR); if(fd < 0) ERREXIT("open edge") rc = write(fd, "falling", 8); if(rc != 8) ERREXIT("write edge") rc = lseek(fd, 0, SEEK_SET); if(rc < 0) ERREXIT("lseek edge") rc = read(fd, buf, 10); if(rc <= 0) ERREXIT("read edge") buf[10] = '\0'; printf("read gpio14/edge:%s\n", buf); close(fd); /* wait for interrupt - try it a few times */ fn = "/sys/class/gpio/gpio14/value"; fd = open(fn, O_RDWR); if(fd < 0) ERREXIT("open value") xfds[0].fd = fd; xfds[0].events = POLLPRI | POLLERR; xfds[0].revents = 0; for (i=0; i<3; i++) { printf("Waiting for interrupt..\n"); rc = poll(xfds, 1, 10000); if(rc == -1) ERREXIT("poll value") printf("poll rc=%d, revents=0x%x\n", rc, xfds[0].revents); } /* get value */ rc = lseek(fd, 0, SEEK_SET); if (rc < 0) ERREXIT("lseek value") rc = read(fd, buf, 2); if (rc != 2) ERREXIT("read value") close(fd); buf[1] = '\0'; /* Overwrite the newline character with terminator */ printf("read rc=%d, val=%s\n", rc, buf); /* unexport */ fn = "/sys/class/gpio/unexport"; fd = open(fn, O_WRONLY); if(fd < 0) ERREXIT("open unexport") rc = write(fd, "14", 3); if(rc != 3) ERREXIT("write unexport") close(fd); return 0; } Here's the result: root@overo:~# ./irquser read gpio14/edge:falling Waiting for interrupt.. poll rc=1, revents=0xa Waiting for interrupt.. poll rc=1, revents=0xa Waiting for interrupt.. poll rc=1, revents=0xa read rc=2, val=1 root@overo:~# The poll() call returns immediately. If I hold down the GPIO14 button while running it, the "val=1" becomes "val=0." The returned bits in 'revents' (0xa) are: POLLPRI: There is urgent data to read (e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in slave). POLLERR: Error condition (output only). I have tested on both these Linux versions: Linux overo 2.6.34 #1 Wed Oct 20 10:22:48 PDT 2010 armv7l GNU/Linux Linux overo 2.6.39 #1 Mon Aug 15 19:04:09 PDT 2011 armv7l GNU/Linux It appears as though this hasn't been implemented, but any ideas are welcome. -- Paul Brown www.signalcraft.com |