beaglebone black gpio opts not to work
I’m trying to detect when the gpio pin changes from low to high and there’s a problem. From what I’ve read, I should be able to configure the pin as input this way:
# echo in > /sys/class/gpio/gpio51/direction
# echo rising > /sys/class/gpio/gpio51/edge
Next, I tried running a C program that uses select to wait for a rising edge. The code looks like this (note I commented out the attempt to just read the file, because reading should be blocked if you don’t set O_NONBLOCK):
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
int main(void) {
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY & ~O_NONBLOCK);
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY | O_NONBLOCK);
unsigned char buf[2];
int x = read(fd, &buf, 2);
printf("%d %d: %s\n", fd, x, buf);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
printf("waiting for %d: %s\n", exceptfds);
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}
Regardless of the state of the pin (high or low), the program exits immediately. Can anyone see that there is something wrong with the way I do this?
Postscript. I have a python library that uses poll() to do this, and python works as expected. I pull the pin low, call python, it blocks, pull the pin high, and the code continues. So I don’t think it’s a problem with the Linux GPIO driver.
Solution
I figured it out. You must read from the file descriptor before the select call returns. Here is a valid example:
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
#define MAX_BUF 64
int main(void) {
int len;
char *buf[MAX_BUF];
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
len = read(fd, buf, MAX_BUF); won't work without this read.
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}