Linux – beaglebone black gpio opts not to work

beaglebone black gpio opts not to work… here is a solution to the problem.

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.

https://bitbucket.org/cswank/gadgets/src/590504d4a30b8a83143e06c44b1c32207339c097/gadgets/io/poller.py?at=master

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;                                                                                                                                                                                                                        
}                                                                                                                                                                                                                                  

Related Problems and Solutions