LINUX.ORG.RU

GPIO epoll на Allwinner A20 (cubieboard 2) с mainline kernel

 , , , ,


0

2

Пытаюсь работать с GPIO на Cubieboard 2. С чтением и записью никаких проблем нет. Но кроме просто чтения хочется ещё и получать уведомления об изменении состояния на вводе без цикла со слипом и чтением. Судя по Documentation/gpio/sysfs.txt, для этого можно использовать poll()/epoll. Попробовал написать на go - не работает. После первого вызова epoll_wait() я сразу же получаю ивент EPOLLPRI и на этом всё. То есть при подаче сигнала на GPIO я внучную (cat /sys/class/gpio/gpioN/value) вижу, что значение меняется, но epoll_wait() висит.

Сначала я решил, что накосячил где-то в коде на go (всё-таки это вообще первая программа, которую я на нём пишу), загуглил примеры работы с GPIO при помощи epoll и нашёл вот этот пример:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/types.h>

int main(int argc, char** argv) {
  int n;
  int epfd = epoll_create(1);
  int fd = open("/sys/class/gpio/gpio99/value", O_RDWR | O_NONBLOCK);
  printf("open returned %d: %s\n", fd, strerror(errno));
  if(fd > 0) {
    char buf = 0;

    struct epoll_event ev;
    struct epoll_event events;
    ev.events = EPOLLPRI;
    ev.data.fd = fd;

    n = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
    printf("epoll_ctl returned %d: %s\n", n, strerror(errno));

    while(1) {
      n = epoll_wait(epfd, &events, 1, -1);
      printf("epoll returned %d: %s\n", n, strerror(errno));

      if(n > 0) {
        n = lseek(fd, 0, SEEK_SET);
        printf("seek %d bytes: %s\n", n, strerror(errno));
        n = read(fd, &buf, 1);
        printf("read %d bytes: %s\n", n, strerror(errno));
        printf("buf = 0x%x\n", buf);
      }
    }
  }

  return(0);
}
Но результат оказался тем же: одна «сработка» сразу после запуска и дальше тишина.

Вопрос: в чём проблема? У меня только две версии: 1) нужный код для работы poll/epoll на GPIO ещё не портировали в мейнлайновое ядро; 2) A20 это не умеет аппаратно.

Дополнительный вопрос: как настроить встроенные pull-up/pull-down резисторы на GPIO? Судя по содержимому исходников файлов device tree, делать это нужно там. Но там все GPIO привязаны к каким-то конкретным устройствам, я не понял как сделать устройство «просто GPIO».

Версии ядра, на которых я пробовал: 4.1.6 и 4.3.0rc1 из состава fedora 22.

Deleted

В тему призывается всезнающий ncrmnt.

Deleted ()

возможно фигню скажу, но не зависит ли это от того может ли gpio алвиннера в прерывания?

anonymous ()
Ответ на: комментарий от anonymous

То, что A20 не может в это аппаратно - это одна из возможных версий, которая пришла мне в голову. Нагуглить внятный ответ на тему «может или нет» у меня не вышло.

Deleted ()
Ответ на: комментарий от anonymous

плюсую анона - гпио на котором ты пытаешься это сделать может не уметь в прерывания, а поллить эта хрень может и не уметь. epoll и sysfs gpio я не пробовал вместе стыковать, потому сказать чего-то вменяемого не могу.

ncrmnt ★★★★★ ()
Ответ на: комментарий от Deleted

Надо тупо открыть исходники драйвера gpio и глянуть. самое быстрое, учитывая качество аллвиннеровских доков.

ncrmnt ★★★★★ ()
Ответ на: комментарий от ncrmnt

ключевое слово gpio_irqchip (или в таком духе)

anonymous ()

A20

Я уже взялся ностальгировать, а тут...

buddhist ★★★★★ ()
Ответ на: комментарий от ncrmnt

Кажется разобрался. В A20 не все GPIO могут генерировать прерывания, а только те, которые в этой таблице отмечены как EINT*. Из 22 пинов на cubieboard 2 «наружу» выведено только три: PH7, PH14 и PH15. Остальные видимо уже используются на устройств на плате.

Потестил на PH15 свой код - работает. Но уже с новой проблемой: после подачи сигнала на пин и до сработки epoll_wait() проходит где-то пол секунды.

Deleted ()

Дополнительный вопрос: как настроить встроенные pull-up/pull-down резисторы на GPIO? Судя по содержимому исходников файлов device tree, делать это нужно там. Но там все GPIO привязаны к каким-то конкретным устройствам, я не понял как сделать устройство «просто GPIO».

да

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/arm...

anonymous ()
Ответ на: комментарий от ossa

У тех, что я тестил изначально - не было. У PH7, PH14 и PH15 - есть. Но работает только с both. С rising или falling - никакого эффекта. То-ли это баг, то-ли тоже что-то аппаратное...

Deleted ()
Ответ на: комментарий от Deleted

Когда-то делал модуль ядра, в котором измерял время реакции на прерывание, вроде работало с rising/falling, хотя точно не помню.

Rupricht ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.