MT7688+ OPENWRT使用GPIO外部中断触发

本文介绍了一种在MT7688平台上利用OPENWRT系统通过配置GPIO实现外部中断的方法。作者最初尝试使用线程轮询的方式检测信号但效果不佳,最终通过直接配置GPIO文件的方式实现了双边沿触发的中断功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        最近在搞MT7688 + OPENWRT,过程中需要使用一个捕获一个高脉冲已确保消息到达对方子设备,开始直接使用了一个线程一直读,读到电平变化就表示捕获到高脉冲了,但是我发现偶尔会漏掉,本着严谨的态度,我希望使用类似STM32那种外部中断事件触发.

       首先我参考了这个博主的方法:

https://blog.csdn.net/qq_37596943/article/details/103750860

        但是编译报错:/mnt/Windows_Share/Soft/GatewayApp_V3_2_2/src/dev_model/examples/gpio.c:42:24: fatal error: linux/init.h: No such file or directory
 #include <linux/init.h>

       随后我尝试解决这个问题搞了两天都没成功,只能想别的方法了,因为我刚搞linux,对Makefile不是很懂,我这又是交叉编译,哭唧唧...

       我看着我的gpio.c文件深深的叹了口气, 忽然间我看到我的gpio配置都是直接对GPIO文件进行的操作,所以我想到是否有直接对gpio文件的外部中断文件进行配置呢?

       说干就干,我百度谷歌一顿操作,找到了介个博主的方法:

https://blog.csdn.net/qq_31094099/article/details/88714440?spm=1001.2014.3001.5506

       茅塞顿开,撸起袖子一顿复制粘贴................搞定! 不过了介个博主的代码不是很全,所以在此贴上我的完全代码:

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

#include <poll.h>



#define FILENAME_SIZE  128

#define GPIO_PATH "/sys/class/gpio"



//导出io
int gpio_export(int pin_number) 
{
	char buf[FILENAME_SIZE];
	int  fp;
	int  length;

	if ( gpio_is_exported(pin_number) ) { return GPIO_SUCCESS; }

	//write to export file
	fp = open(GPIO_PATH "/export", O_WRONLY);
	if ( fp == -1) 
        {
		return GPIO_INVALID_RESOURCE;
	}

	length = snprintf(buf, sizeof(buf), "%d", pin_number);
	if (write(fp, buf, length * sizeof(char)) == -1) 
        {
		close(fp);
		return GPIO_INVALID_RESOURCE;
	}

	close(fp);
	return gpio_is_exported(pin_number);
}

//开始捕获测试
int ACK_test( void )
{
	int fd = -1;

//导出io
	if(1 != gpio_export(25))
	{
		perror("Z_ACK  gpio_export failed!\n");  
	}

//配置成输入
	fd = open( "/sys/class/gpio/gpio25/direction", O_RDWR);
	if ( fd == -1)
	{
		perror("open Z_ACK  direction failed!\n");  
		return GPIO_INVALID_RESOURCE;
	}
	if ( lseek(fd, 0, SEEK_SET) < 0 ) 
	{
		close(fd);
		perror("lseek Z_ACK  direction failed!\n");  
		return GPIO_INVALID_RESOURCE;
	}
	if (write( fd, "in", 2 * sizeof(char)) == -1) 
	{
		close(fd);
		perror("write Z_ACK  direction failed!\n");  
		return GPIO_ERROR_WRITE;
	}
	printf("Z_ACK  direction ok!\n"); 

//边沿触发
	fd = open( "/sys/class/gpio/gpio25/edge", O_RDWR);
	if ( fd == -1)
	{
		perror("open Z_ACK  edge failed!\n");  
		return GPIO_INVALID_RESOURCE;
	}
	if ( lseek(fd, 0, SEEK_SET) < 0 ) 
	{
		close(fd);
		perror("lseek Z_ACK  edge failed!\n"); 
		return GPIO_INVALID_RESOURCE;
	}
	if (write( fd, "both", 4 * sizeof(char)) == -1) 
	{
		close(fd);
		perror("write Z_ACK  edge failed!\n"); 
		return GPIO_ERROR_WRITE;
	}
	printf("Z_ACK  edge ok!\n"); 


//开始捕获
    fd = open("/sys/class/gpio/gpio25/value",O_RDONLY);
    if(fd<0)
    {
        perror("open Z_ACK failed!\n");  
        return -1;
    }
    else { perror("open Z_ACK Ok!\n");   }


    struct pollfd fds[1];
    fds[0].fd=fd;
    fds[0].events = POLLPRI;

    while(1)
    {
        if(poll(fds,1,0)==-1)
        {
            perror("poll failed!\n");
            return -1;
        }

        if( fds[0].revents & POLLPRI )
        {
	    //set_ACK();  //能进这里就代表触发事件发生了,我这里是置了一个标志
            if(lseek(fd,0,SEEK_SET)==-1)
            {
                perror("lseek  Z_ACK value failed!\n");
                return -1;
            }
            char buffer[16];
            int len;
            //一定要读取,不然会一直检测到紧急事件
            if(( len = read(fd,buffer,sizeof(buffer))) == -1)  
            {
                perror("read Z_ACK value failed!\n");
                return -1;
            }
            buffer[len]=0;
            printf("%s",buffer);
        }
    }

	return 0;
}

       我这里设置/sys/class/gpio/gpio25/edge是both,因为我需要双边沿触发,这里小伙伴可以选择自己合适的:

edge:    控制中断触发模式,引脚被配置为中断后可以使用poll() 函数监听引脚 
          非中断引脚: echo “none” > edge
          上升沿触发: echo “rising” > edge
          下降沿触发: echo “falling” > edge
          边沿触发    : echo “both”  > edge

<think>好的,我现在需要帮助用户解决在OpenWRT系统中配置中断管脚的问题。首先,我得仔细阅读用户提供的引用内容,看看是否有相关的信息。用户提到了引用3和引用4,里面涉及到了GPIO中断的配置和问题。 引用3提到在MT7628的OpenWRT中,GPIO中断的驱动是gpio-mt7621.c,里面有一个函数mediatek_gpio_irq_type,用于设置中断类型。这可能涉及到设备树(DTS)的配置,因为用户提到了mt7628an.dtsi文件中的gpio驱动设置。所以,配置中断可能需要修改设备树文件,指定GPIO引脚和中断触发方式。 引用4中用户提到在MT7688使用GPIO外部中断触发时遇到问题,原本用轮询方式偶尔漏掉信号,想改用中断方式。这说明用户需要具体的配置步骤,包括如何在内核或设备树中启用中断,以及如何编写用户空间的程序来响应中断。 接下来,我需要将这两个引用中的信息整合起来,形成一个步骤指南。首先,配置设备树(DTS)来指定GPIO中断属性,比如将某个GPIO引脚设置中断源,并定义触发方式(上升沿、下降沿等)。然后,可能需要编译和更新设备树,确保驱动正确加载。 然后,用户空间的应用程序如何监听中断事件。通常,在Linux系统中,可以通过sysfs或者使用库函数来注册中断处理函数。例如,在sysfs中导出GPIO,然后设置中断边缘,再通过poll或epoll来监听value文件的变化。或者,使用内核模块来处理中断,但用户可能更倾向于用户空间的解决方案,特别是在OpenWRT环境下。 另外,需要注意不同芯片(如MT7628和MT7688)的设备树配置可能有所不同,但整体流程类似。需要检查具体的设备树节点,确保GPIO控制器和中断处理正确配置。同时,驱动中的函数如mediatek_gpio_irq_type可能影响中断的注册和处理,用户可能需要确认驱动是否支持所需的中断类型。 可能还需要考虑内核配置是否启用了GPIO中断的支持,以及相关的子系统如IRQ和GPIO中断处理是否编译进内核。在OpenWRT中,可能需要通过make menuconfig来配置相关选项。 最后,测试和调试步骤也很重要,比如使用工具检查GPIO状态,或者编写简单的测试程序来验证中断是否被正确触发。如果遇到问题,可能需要查看内核日志(dmesg)来排查驱动或配置错误。 总结起来,步骤应该包括设备树配置、编译更新内核、用户空间中断处理设置,以及测试验证。同时,要提醒用户注意不同硬件平台的差异,参考具体的文档和示例代码。</think>在OpenWRT系统中配置GPIO中断管脚需要结合设备树(DTS)配置和用户空间编程实现,以下是具体步骤: ### 一、设备树(DTS)配置 1. **定位GPIO控制器节点** 在设备树文件(如`mt7628an.dtsi`)中找到GPIO控制器节点。根据引用[3],MT7628的GPIO驱动为`mtk,mt7621-gpio-bank`,其节点示例如: ```dts gpio@600 { compatible = "mtk,mt7621-gpio-bank"; reg = <0x600 0x100>; #gpio-cells = <2>; #interrupt-cells = <2>; interrupt-controller; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; }; ``` 2. **定义GPIO中断属性** 在需要使用中断GPIO引脚节点中,添加`interrupt-parent`和`interrupts`属性: ```dts my_device { compatible = "custom-device"; interrupt-parent = <&gpio0>; // 指向GPIO控制器 interrupts = <12 IRQ_TYPE_EDGE_RISING>; // GPIO12,上升沿触发 }; ``` 触发类型可选:`IRQ_TYPE_EDGE_RISING`(上升沿)、`IRQ_TYPE_EDGE_FALLING`(下降沿)等[^3]。 ### 二、用户空间中断处理 1. **通过sysfs操作GPIO** ```bash # 导出GPIO(假设GPIO12) echo 12 > /sys/class/gpio/export # 设置中断触发方式 echo "rising" > /sys/class/gpio/gpio12/edge ``` 支持的触发方式:`none`, `rising`, `falling`, `both`[^4]。 2. **使用poll/epoll监听中断** 编写C程序通过文件描述符监听`/sys/class/gpio/gpio12/value`变化: ```c #include <poll.h> #include <fcntl.h> int fd = open("/sys/class/gpio/gpio12/value", O_RDONLY); struct pollfd pfd = { .fd = fd, .events = POLLPRI }; poll(&pfd, 1, -1); // 阻塞等待中断 ``` ### 三、注意事项 1. **驱动兼容性** MT7628的GPIO中断驱动`gpio-mt7621.c`需要支持`mediatek_gpio_irq_type`函数,该函数负责设置中断触发类型[^3]。 2. **避免中断冲突** 使用前需通过`cat /proc/interrupts`确认GPIO中断未被其他设备占用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值