как обнаружить изменение контакта GPIO на плате Linux

Я использую ядро ​​​​3.12 на плате Linux на базе ARM (процессор imx233). Моя цель - обнаружить изменение контакта 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;
}

Но это вызывает слишком большую нагрузку на процессор. Я не использую usleep или nanosleep, потому что смена контакта происходит в течение очень короткого промежутка времени, из-за которого я могу пропустить это событие.

Насколько я знаю, использовать 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);

EDIT2: код на https://developer.ridgerun.com/wiki/index.php/Gpio-int-test.c отлично работает с poll() Мне нужно было определить нарастающий/спадающий фронт для прерывания и немного исправить определение. Это решает мою проблему, однако мне и некоторым другим людям было бы полезно услышать/знать альтернативные методы.


person Angs    schedule 21.09.2014    source источник
comment
как насчет inotify API?   -  person Ryan    schedule 21.09.2014
comment
Когда вы говорите, что контакт активен только в течение очень короткого времени, о каком времени вы говорите? Потому что даже при активном опросе, как у вас, выполнение его из пользовательского пространства может привести к задержкам, из-за которых вы все равно его пропустите.   -  person Some programmer dude    schedule 21.09.2014
comment
Я хочу использовать GPIO в качестве чипа для чтения данных SPI. в состоянии простоя это высокий логический уровень. Он переходит в низкий логический уровень, когда начинается передача. Поэтому чем быстрее реакция, тем лучше. Когда я найду подходящий метод, я протестирую его на более низкой скорости.   -  person Angs    schedule 21.09.2014
comment
Есть ли у этого конкретного контакта альтернативная функция захвата-сравнения? Что вам нужно, так это аппаратное обеспечение для генерации прерывания   -  person SzG    schedule 21.09.2014
comment
Правильно, прерывание HW было бы лучшим. Но я пока не смог найти поддержку своей платы (olimex imx233nano). Было бы хорошо знать функцию Linux/posix, которая будет работать нормально. Как и предполагает правда, я сейчас пытаюсь inotify.   -  person Angs    schedule 21.09.2014
comment
Вы можете абстрагировать ввод как ключ GPIO: armadeus.com/wiki/index. php?title=GPIO_keys. Вы можете получать уведомления о росте и падении с отметками времени. Pinctrl также может разрешать применение HW debounce или deglitch.   -  person sawdust    schedule 22.09.2014
comment
@angs, учитывая, что это основано на процессоре imx, смогли ли вы проверить, какие типы прерываний зарегистрированы и, что важно, gpio_to_irq()?   -  person Karthik Balaguru    schedule 22.09.2014
comment
@angs взгляните на libsoc. Он предоставляет процедуру ожидания прерывания GPIO.   -  person yegorich    schedule 25.09.2014


Ответы (1)


Я никогда не видел эту плату раньше, однако я думаю, что PIC полностью реализован для этой платы (обычно это так), но вы должны настроить прерывание дополнительно в GPIO-контроллере (обычно это так). Некоторая часть должна быть выполнена в виде модуля ядра, затем вы должны передать информацию о прерывании вашему приложению.

Примерный способ сделать это - реализовать следующую вещь в качестве модуля ядра:

  • настроить контроллер GPIO, чтобы включить прерывание на определенном порту и уровне (как это сделать, вы можете найти здесь: http://cache.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf 37.2.3.3 Операция прерывания ввода)

  • включить прерывание GPIO в PIC (как это сделать: http://lwn.net/images/pdf/LDD3/ch10.pdf Глава 10)

  • реализовать процедуру обработки прерываний (я опишу немного ниже)
  • реализовать интерфейсы ioctl для вашего модуля.

и отдых в вашем приложении:

  • функция, которая может выполняться с прерыванием.

Самый простой способ передачи информации о прерывании от ядра к приложению — семафор на стороне ядра. в модуле вы можете реализовать ioctl, который будет спать, пока не произойдет прерывание. Таким образом, приложение вызовет этот ioctl, и его поток будет заблокирован до тех пор, пока не произойдет прерывание.

Внутри модуля процедура прерывания должна проверять, заблокирован ли поток приложения, и если да, то семафор up().

РЕДАКТИРОВАТЬ*****

Этот ЦП имеет SSP, который имеет рабочий режим для SPI. Почему не пользуетесь??

person wiesniak    schedule 17.12.2014