Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to detect a pin change of a GPIO on Linux board

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.

like image 269
Angs Avatar asked Sep 21 '14 18:09

Angs


People also ask

How to check GPIO status in Linux?

If your kernel has sysfs support you can access and control the gpio pins through the interface in /sys/class/gpio . See the sysfs section of the kernel document in Documentation/gpio. txt .

How to find GPIO pins?

The Linux GPIO number for a certain GPIO pin can be determined by adding the GPIO pin index to the port base index. For instance: i. MX6 GPIO2_4 (port 2, pin 4) is: 32 + 4 = 36.

Which Linux command is used to find GPIO pin name?

You can use 'lsof' command to list the open files. according to fact that gpio files are regular files. (e.g /sys/class/gpio/gpio242/value). Also you should be sure of loading the right kernel modules (with insmod or modprobe) into memory.


1 Answers

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)

  • implement interrupt handling routine (I will describe a little bit below)
  • implement ioctl interfaces for your 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 ??

like image 150
wiesniak Avatar answered Oct 04 '22 16:10

wiesniak