如何检测Linux板上GPIO的引脚变化 [英] how to detect a pin change of a GPIO on Linux board

查看:1044
本文介绍了如何检测Linux板上GPIO的引脚变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在基于ARM的linux板(imx233 CPU)上使用3.12内核.我的目的是检测GPIO的引脚变化(1到0).

我可以不断调用以下函数(在while(1)循环中)读取引脚值

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

但是这会给CPU带来过多的负载.我不使用usleepnanosleep,因为引脚更改发生的时间很短,这会导致我错过该事件.

据我所知,不可能使用poll().是否可以使用任何类似于poll()的功能来检测GPIO的引脚变化?

以防万一,如果我做错了,这是我的poll()用法,它不能检测到引脚变化

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

https://developer.ridgerun.com/wiki/上的代码index.php/Gpio-int-test.c poll()下工作正常,我需要为中断定义上升沿/下降沿,并对定义进行一些修复.它解决了我的问题,但是,对我和其他一些人来说,听到/知道其他选择方法可能会很有帮助.

解决方案

我以前从未见过此板,但是我猜想PIC已经完全实现了该板的功能(通常就是这样),但是您必须在GPIO中另外配置中断控制器(通常就是这样). 某些部分应作为内核模块完成,然后您必须将有关中断的信息传递给应用程序.

执行此操作的示例方法是将以下内容实现为内核模块:

和其余的应用程序:

  • 可以与中断配合使用的功能.

从内核向应用程序传递有关中断的信息的最简单方法是通过内核端的信号量. 在模块中,您可以实现一个ioctl,它将一直休眠直到发生中断. 因此,应用程序将调用此ioctl,并且其线程将被阻塞,直到发生中断为止.

在内部模块中,中断例程应检查应用程序线程是否现在被阻塞,以及up()信号是否被阻塞.

编辑*****

此CPU的SSP具有SPI的工作模式.为什么不使用它?

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:

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

这篇关于如何检测Linux板上GPIO的引脚变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆