gpio中断

https://sns.widora.io/topic/63/widora-neo-gpio中断试验

1. 内核模块模板
继续采用"编制第一个widora-neo驱动" 中的模板。

2. mt7688 GPIO中断相关寄存器
用GPIO 17 脚上的上升沿来触发中断,主要用到如下的寄存器。
volatile unsigned long *GPIO_CTRL_0; //--- GPIO0 to GPIO31 direction control register 0-input 1-output
volatile unsigned long *GINT_REDGE_0; //--GPIO0 to GPIO31 rising edge interrupt enable register
volatile unsigned long *GINT_FEDGE_0; //--GPIO0 to GPIO31 falling edge interrupt enable register
volatile unsigned long *GINT_STAT_0; //---GPIO0 to GPIO31 interrupt status register 1-int 0 -no int
volatile unsigned long *GINT_EDGE_0; //---GPIO0 to GPIO31 interrupt edge status register 1-rising 0-falling
volatile unsigned long *GPIO1_MODE; // GPIO1 purpose selection register,for SPIS or GPIO14-17 mode selection
volatile unsigned long *AGPIO_CFG; // analog GPIO configuartion,GPIO14-17 purpose

3. 申请和注册GPIO中断
3.1 用gpio_to_irq()函数取得GPIO中断号
调用函数 gpio_to_irq(GPIO_PIN_NUM) 来获得中断号,需要包含相关头文件#include <linux/gpio.h>

3.2 申请注册中断
调用函数request_irq(GPIO_INT_NUM,gpio_int_handler,IRQF_DISABLED,"GPIO_INT_midas",NULL) 申请注册中断,相关要素可查阅网上资料。 IRQF_TRIGGER_RISING 标志应该也可以用,没有试过。 申请注册成功后,可以用 cat /proc/interrupts 命令看到对应的中断号。

4. 模块程序
4.1 主要自定函数功能
static void Init_GPIO(void) /* 映射并设定相关寄存器功能 /
static void GPIO_unmap(void) /
 释放内存映射 /
static void get_gpio_INT_num(void) /
 获得GPIO映射的中断号 */
static irqreturn_t gpio_int_handler(int irq,void *dev_id,struct pt_regs regs) / 中断处理函数 /
static int register_gpio_IRQ(void) /
 向内核申请注册中断 */
4.2 在设备打开时进行中断的初始化和注册(黑体部分)。
//---OPEN

4.2 在设备打开时进行中断的初始化和注册(黑体部分)。
//---OPEN
static int gpio_int_open(struct inode *inode, struct file *file)
{
int ret_v=0;
printk("gpio_int driver open........ \n");

    //------------    init GPIO interrupt   ----------
    Init_GPIO();
    get_gpio_INT_num();
    ret_v=register_gpio_IRQ();  //---register GPIO interrup     

return ret_v;
}

4.3 在读取设备时返回中断状态,并重使能中断(黑体部分)。
//---READ
static ssize_t gpio_int_read(struct file *file, char __user *buffer,
size_t len, loff_t *pos)
{
int ret_v = 0;
printk("gpio_int drive read...\n");

 copy_to_user(buffer,&INT_STATUS,4);
 INT_STATUS=0; //----reset interrupt token
 msleep(100);  //------------ deter re-enabling irq to avoid key-jitter
  if(DISABLE_IRQ_TOKEN)
     {
           enable_irq(GPIO_INT_NUM);   
          DISABLE_IRQ_TOKEN=0;
     } 

ret_v=4;
return ret_v;
}
4.4 在设备关闭的时候注销和清理中断资源(黑体部分)。
//---CLOSE
static int gpio_int_close(struct inode *inode , struct file *file)
{
printk("gpio_int drive close...\n");

    //------------free irq resource----------------------------
    GPIO_unmap();  //-----free GPIO map
    free_irq(GPIO_INT_NUM,NULL); //----free irq NON-SHARED**

return 0;
}

5. 用户程序
写一个用户程序来测试,当中断被触发时会在串口终端输出"GPIO Interrupt Triggered! "信息。

 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>

 char str_dev[]="/dev/gpio_int_dev";

 int main(int argc, char **argv)
 {
     int fd;
     unsigned int INT_STATUS = 0;
     //------- open driver--------
     fd = open(str_dev, O_RDWR | O_NONBLOCK);
     if (fd < 0)
      {
     printf("can't open %s\n",str_dev);
     return -1;
         }
       //------------- read INT_STATUS -------
     while(1)
     {
     read(fd, &INT_STATUS, sizeof(INT_STATUS));
         if(INT_STATUS==1)
               printf("GPIO Interrupt Triggered!\n");
         usleep(200000);  
      }
     close(fd);

     return 0;
 }

6. 接线试验
由于这里用的是上升沿触发,需要将GPIO17脚通过一个几k的电阻(3.9k etc.)拉低。

可以在这里获得完整的源码: https://github.com/midaszhou/openwrt_widora/tree/midas/package/kernel/gpio-int

posted @ 2018-01-09 17:04  XZHDJH  阅读(489)  评论(0)    收藏  举报