在Linux里面需要用到中断功能,是通过修改/sys/class/gpioxx/edge改成对应的非none选项,然后把/sys/class/gpioxx/direction 改成in就好。
然后使用的时候通常是开启一个线程,然后用poll的形式来处理中断。
在A133上面,也是使用这个方式,但是发现编译好的app运行一次后,kill掉,再运行,就无法触发poll 了,初始化io的时候也没有报错。
查看代码,发现也没有啥问题。open和close都有。
最后经过实验,发现是在已经存在/sys/class/gpioxx文件夹的时候,xx按键初始化成外部中断就会无法触发poll。需要unexport,收回对应引脚的文件夹后,再次初始化才行。其他家的芯片好像没有这个要求
因此发上来方便后面的人遇到同样的问题的时候可以参考,下面是对应的测试代码
//带unexport的代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define GPIO_PATH "/sys/class/gpio"
#define GPIO_EXPORT_FILE GPIO_PATH "/export"
#define GPIO_UNEXPORT_FILE GPIO_PATH "/unexport"
#define GPIO_EDGE_FILE "edge"
#define GPIO_VALUE_FILE "value"
int export_gpio(int gpio_num) {
char buffer[4];
int fd = open(GPIO_EXPORT_FILE, O_WRONLY);
if (fd < 0) {
perror("Failed to open export for write");
return -1;
}
snprintf(buffer, sizeof(buffer), "%d", gpio_num);
write(fd, buffer, strlen(buffer));
close(fd);
return 0;
}
int set_gpio_direction(int gpio_num, const char *direction) {
char path[64];
snprintf(path, sizeof(path), GPIO_PATH "/gpio%d/direction", gpio_num);
int fd = open(path, O_WRONLY);
if (fd < 0) {
perror("Failed to open direction for write");
return -1;
}
write(fd, direction, strlen(direction));
close(fd);
return 0;
}
int set_gpio_edge(int gpio_num, const char *edge) {
char path[64];
snprintf(path, sizeof(path), GPIO_PATH "/gpio%d/%s", gpio_num, GPIO_EDGE_FILE);
int fd = open(path, O_WRONLY);
if (fd < 0) {
perror("Failed to open edge for write");
return -1;
}
write(fd, edge, strlen(edge));
close(fd);
return 0;
}
int is_gpio_exported(int gpio_num)
{
char path[64];
snprintf(path, sizeof(path), GPIO_PATH "/gpio%d", gpio_num);
return !access(path, F_OK);
}
int main() {
int gpio_fd, ret;
struct pollfd fds[1];
int gpio_num = 23; // Replace with your GPIO number
if ()
{
//这里要unexport下
int unexport_fd = open(GPIO_UNEXPORT_FILE, O_WRONLY);
if (unexport_fd >= 0) {
char buffer[4];
snprintf(buffer, sizeof(buffer), "%d", gpio_num);
write(unexport_fd, buffer, strlen(buffer));
close(unexport_fd);
}
}
// Export GPIO and set direction and edge
if (export_gpio(gpio_num) < 0)
return 1;
if (set_gpio_direction(gpio_num, "in") < 0)
return 1;
if (set_gpio_edge(gpio_num, "rising") < 0)
return 1;
// Open value file for reading
char value_path[64];
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/%s", gpio_num, GPIO_VALUE_FILE);
gpio_fd = open(value_path, O_RDONLY | O_NONBLOCK);
if (gpio_fd < 0) {
perror("Failed to open value for read");
return 1;
}
// Setup poll structure
fds[0].fd = gpio_fd;
fds[0].events = POLLPRI;
while (1) {
ret = poll(fds, 1, -1); // Wait indefinitely for event
if (ret == -1) {
if (errno == EINTR)
continue;
perror("poll");
break;
} else if (ret == 0) {
printf("Timeout occurred!?\n");
continue;
}
if (fds[0].revents & POLLPRI) {
// Read the value to clear the interrupt
lseek(gpio_fd, 0, SEEK_SET);
char value_str[32];
read(gpio_fd, value_str, sizeof(value_str));
printf("Interrupt detected on GPIO %d\n", gpio_num);
// Process the interrupt here...
// Break after processing one interrupt for demonstration purposes
break;
}
}
// Cleanup
close(gpio_fd);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/value", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/edge", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/direction", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d", gpio_num);
rmdir(value_path);
//这里要unexport下
int unexport_fd = open(GPIO_UNEXPORT_FILE, O_WRONLY);
if (unexport_fd >= 0) {
char buffer[4];
snprintf(buffer, sizeof(buffer), "%d", gpio_num);
write(unexport_fd, buffer, strlen(buffer));
close(unexport_fd);
}
return 0;
}
//没有执行unexport的代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define GPIO_PATH "/sys/class/gpio"
#define GPIO_EXPORT_FILE GPIO_PATH "/export"
#define GPIO_EDGE_FILE "edge"
#define GPIO_VALUE_FILE "value"
int export_gpio(int gpio_num) {
char buffer[4];
int fd = open(GPIO_EXPORT_FILE, O_WRONLY);
if (fd < 0) {
perror("Failed to open export for write");
return -1;
}
snprintf(buffer, sizeof(buffer), "%d", gpio_num);
write(fd, buffer, strlen(buffer));
close(fd);
return 0;
}
int set_gpio_direction(int gpio_num, const char *direction) {
char path[64];
snprintf(path, sizeof(path), GPIO_PATH "/gpio%d/direction", gpio_num);
int fd = open(path, O_WRONLY);
if (fd < 0) {
perror("Failed to open direction for write");
return -1;
}
write(fd, direction, strlen(direction));
close(fd);
return 0;
}
int set_gpio_edge(int gpio_num, const char *edge) {
char path[64];
snprintf(path, sizeof(path), GPIO_PATH "/gpio%d/%s", gpio_num, GPIO_EDGE_FILE);
int fd = open(path, O_WRONLY);
if (fd < 0) {
perror("Failed to open edge for write");
return -1;
}
write(fd, edge, strlen(edge));
close(fd);
return 0;
}
int main() {
int gpio_fd, ret;
struct pollfd fds[1];
int gpio_num = 23; // Replace with your GPIO number
// Export GPIO and set direction and edge
if (export_gpio(gpio_num) < 0)
return 1;
if (set_gpio_direction(gpio_num, "in") < 0)
return 1;
if (set_gpio_edge(gpio_num, "rising") < 0)
return 1;
// Open value file for reading
char value_path[64];
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/%s", gpio_num, GPIO_VALUE_FILE);
gpio_fd = open(value_path, O_RDONLY | O_NONBLOCK);
if (gpio_fd < 0) {
perror("Failed to open value for read");
return 1;
}
// Setup poll structure
fds[0].fd = gpio_fd;
fds[0].events = POLLPRI;
while (1) {
ret = poll(fds, 1, -1); // Wait indefinitely for event
if (ret == -1) {
if (errno == EINTR)
continue;
perror("poll");
break;
} else if (ret == 0) {
printf("Timeout occurred!?\n");
continue;
}
if (fds[0].revents & POLLPRI) {
// Read the value to clear the interrupt
lseek(gpio_fd, 0, SEEK_SET);
char value_str[32];
read(gpio_fd, value_str, sizeof(value_str));
printf("Interrupt detected on GPIO %d\n", gpio_num);
// Process the interrupt here...
// Break after processing one interrupt for demonstration purposes
break;
}
}
// Cleanup
close(gpio_fd);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/value", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/edge", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d/direction", gpio_num);
unlink(value_path);
snprintf(value_path, sizeof(value_path), GPIO_PATH "/gpio%d", gpio_num);
rmdir(value_path);
return 0;
}
离线