Ядро Linux предоставляет для доступа к входам/выходам GPIO (general purpose input/output) специальный интерфейс, который позволяет работать с GPIO как с символьными устройствами.
Прежде всего, сошлюсь на полезный пост Linux - Accessing GPIO from User Space и дополню его некоторыми комментариями, а также описанием работы с прерываниями.
Получение значения порта.
Итак, мы экспортировали GPIO
int exportfd;
exportfd = open("/sys/class/gpio/export", O_WRONLY);
write(exportfd, "149", 4);
close(exportfd);
задали направление
int directionfd;
directionfd = open("/sys/class/gpio/gpio149/direction", O_RDWR);
write(directionfd, "in", 4);
close(directionfd);
и открыли файл со значением выхода для чтения (как производить запись, полностью описано в указанной статье)
int valuefd;
valuefd = open("/sys/class/gpio/gpio149/value", O_RDWR);
Файл valuefd является символьным устройством, в котором в строковом виде содержится значение входного порта. Чтобы прочитать текущее значение, необходимо установить смещение в файле, и прочитать строку со значением.
char buffer[2];
lseek(valuefd , 0, SEEK_SET);
r = read(valuefd, buffer, 2);
Строка значения обычно имеет формат "0\n" или "1\n".
Обработка прерываний.
Получение прерываний от GPIO в общем случае асинхронно. В User Space невозможно стандартным образом установить непосредственный обработчик прерывания. Но для GPIO возможно получать информацию о том, произошло ли прерывание или нет, и если произошло, то произвести чтение значения порта и осуществить необходимые вам действия. Для этого используется системный вызов poll(), в этом случае работа ведется, как с обычным символьным устройством (с помощью poll() можно получать и информацию о поступлении символов на консоль, и другие подобные задачи).
Необходимо учесть, что поступление прерывания по фронту не гарантирует, что ко времени чтения значения с порта с помощью read() оно не изменится, т.к. может пройти произвольное время. Linux не является операционной системой реального времени.
Для получения прерываний необходимо настроить фронт, на который сработает прерывание: "none", "rising", "falling", or "both".
int edgefd;
edgefd = open("/sys/class/gpio/gpio149/edge", O_WRONLY);
r = write(edgefd, "rising", 7);
close(edgefd);
Теперь мы открываем файл значения порта и можем ловить сигналы с помощью вызова poll():
#include <poll.h>
...
int valuefd;
struct pollfd poll_fd;
int r;
int timeout_ms = 1000;
valuefd = open("/sys/class/gpio/gpio149/value", O_RDWR);
poll_fd.fd = gpio_fd;
poll_fd.events = POLLPRI;
r = poll(&poll_fd, 1, timeout_ms);
if (r < 0)
{
printf("poll() failed!\n");
}else if (poll_fd.revents & POLLPRI)
{
printf("it was interrupt event on gpio\n");
}
На этом всё. Описание интерфейса gpiolib можно посмотреть на kernel.org.
Комментариев нет:
Отправить комментарий