9

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.

Angs
  • 1,605
  • 2
  • 23
  • 47
  • what about the inotify API? – Ryan Sep 21 '14 at 18:43
  • 1
    When you say that the pin is only active for a "very short time", what kind of timing are you talking about? Because having even active polling like you do, doing it from userspace might introduce latencies that can cause you to miss it anyway. – Some programmer dude Sep 21 '14 at 18:43
  • I want to use a GPIO as a chipselect to read SPI data. on the idle state it is logic high. It goes to logic low when the transmission starts. Therefore, the faster reaction the better. When I find an appropriate method, I will test it with slower speed – Angs Sep 21 '14 at 18:47
  • 2
    Does this particular pin have an alternative capture-compare function? What you need is the hardware to generate an interrupt – SzG Sep 21 '14 at 18:52
  • Right, HW interrupt would be the best. But, I could not find the support for my board (olimex imx233nano) yet. It would be good to know a Linux/posix function that would work fine. As true suggests, I am trying inotify now. – Angs Sep 21 '14 at 18:56
  • You could abstract the input as a GPIO key: http://www.armadeus.com/wiki/index.php?title=GPIO_keys. You can be notified of rise and fall with timestamps. Pinctrl may also allow application of HW debounce or deglitch. – sawdust Sep 22 '14 at 01:07
  • @angs, considering that this is based on imx CPU, were you able to check what kind of irqs are registered and importantly gpio_to_irq() ? – Karthik Balaguru Sep 22 '14 at 17:44
  • @angs take a look at [libsoc](https://github.com/jackmitch/libsoc). It provides a routine to wait for a GPIO interrupt. – yegorich Sep 25 '14 at 07:19

1 Answers1

2

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:

and a rest in your application:

  • a function that can coosomeoneperate with interrupt.

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 ??

wiesniak
  • 558
  • 2
  • 11