I am using 3.12 kernel on an ARM based linux board (imx233 CPU). My purpose is to detect pin change of a GPIO (1 to 0).
I can read the pin value constantly calling the below function (in a while(1) loop)
int GPIO_read_value(int pin){
int gpio_value = 0;
char path[35] = {'\0'};
FILE *fp;
sprintf(path, "/sys/class/gpio/gpio%d/value", pin);
if ((fp = fopen(path,"rb+")) == NULL){ //echo in > direction
//error
}
fscanf(fp, "%d", &gpio_value);
fclose(fp);
return gpio_value;
}
But it causes too much load to the CPU. I don't use usleep
or nanosleep
, because the pin change happens for a very short of a time that would cause me to miss the event.
As far as I find out, it is not possible to use poll()
. Is there any poll()
like function that I can use to detect a pin change of a GPIO?
EDIT: Just in case, if I am doing something wrong, here is my poll()
usage that does not detect the pin change
struct pollfd pollfds;
int fd;
int nread, result;
pollfds.fd = open("/sys/class/gpio/gpio51/value", O_RDWR);
int timeout = 20000; /* Timeout in msec. */
char buffer[128];
if( pollfds.fd < 0 ){
printf(" failed to open gpio \n");
exit (1);
}
pollfds.events = POLLIN;
printf("fd opens..\n");
while (1)
{
result = poll (&pollfds, 0, timeout);
switch (result)
{
case 0:
printf ("timeout\n");
break;
case -1:
printf ("poll error \n");
exit (1);
default:
printf("something is happening..\n");
if (pollfds.revents & POLLIN)
{
nread = read (pollfds.fd, buffer, 8);
if (nread == 0) {
printf ("result:%d\n", nread);
exit (0);
} else {
buffer[nread] = 0;
printf ("read %d from gpio: %s", nread, buffer);
}
}
}
}
close(fd);
EDIT2: the code on https://developer.ridgerun.com/wiki/index.php/Gpio-int-test.c works fine with poll()
I needed to define the rising/falling edge for the interrupt and a little bit fix on the definition. It solves my problem, however, it might be good for me and some other people to hear/know the alternative methods.
I have never seen this board before, however I guess PIC is fully implemented for this board (usually is like that) but you have to configure interrupt additionally in GPIO controller (usually is like that). Some part should be done as a kernel module, then you have to pass information about interrupt to you application.
Example way to do this is to implement following thing as a kernel module:
setup GPIO controller to enable interrupt on particular port and level (how to do this you can find here: http://cache.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf 37.2.3.3 Input Interrupt Operation)
enable GPIO interrupt in PIC (how to do this: http://lwn.net/images/pdf/LDD3/ch10.pdf Chapter10)
and a rest in your application:
Simplest way of passing information about interrupt from kernel to app is by semaphore on kernel side. in module you can implement an ioctl that will sleep until interrupt happen. So application will call this ioctl and its thread will be blocked until interrupt happen.
Inside module, interrupt routine should check if application thread is now blocked, and if so up() semaphore.
EDIT*****
This CPU has SSP that has working mode for SPI. Why dont use it ??