您尚未登录。

楼主 # 2024-12-31 18:56:42

微凉VeiLiang
会员
所在地: 深圳
注册时间: 2018-10-28
已发帖子: 631
积分: 526
个人网站

全志A133芯片Linux下GPIO外部中断使用和第二次运行无法触发Poll运行的问题解决

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

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn