RK3568外部IO中断示例
1. 外部IO中断介绍本篇文章以万象奥科HD-RK3568-IOT评估板中GPIO30为例,介绍Linux内核中断的注册方法,使用中断的方式检测GPIO30是否出现上升沿信号。中断在linux、设备驱动开发里使用的都非常多,可以更加实时的检测GPIO30的状态。Linux内核提供了中断的注册接口:1) 注册中断头文件 include\linux\interrupt.h定义文件 include\linux\interrupt.h函数原型 int request_irq(unsigned int irq,/* 做实参传递给中断服务函数第1个参数 */ Irq_handler_thandler,/* 中断服务函数指针 */ unsignedlong flags, constchar *name,void*dev_id); /* 做实参传递给中断服务函数第2个参数 */函数功能: 向内核注册一个中断服务函数;当发生中断号为irq的中断时,会执行handler指针函数。函数参数: irq: 中断编号(每个中断有唯一的编号)。handler: 中断服务函数指针。 原型typedef irqreturn_t(*irq_handler_t)(int,void *)。flag: 中断的标志,用来描述本中断的基本特征的。 有固定的值,由中断源的特征决定; 比如外中断有: 上升沿,下降沿触发中断这类标志。name: 中断名字,注册后会出现cat /proc/interruptsdev_id: 这个参数是传递给中断服务函数。 对共享中断来说,这个参数一定有要; 当注销共享中断中的其中一个时,用这个标识要注销哪一个。 对于有唯一入口的中断,可以传递NULL; 但是一般来说都会传递一个有意义指针,在中断程序中使用,以方便编程。 返回值 0 标识成功 -EINVAL (无效参数22) 表示中断号无效。 -EBUSY (设备或者资源忙16) 表示中断已经被占用。2) 注销中断voidfree_irq(unsigned int irq, void *dev_id)irq: 要注销的中断号dev_id: 其实就是注册时需要使用的dev参数,在共享中断必不可少,不能传递NULL。注意:为防止在注销时同时发生中断,调用时候,先禁掉中断。3)中断开启与关闭 禁止中断:voiddisable_irq_nosync(unsigned int irq);voiddisable_irq(unsigned int irq);参数: irq,要禁止的中断对应的编号。注意:在中断服务程序中不能使用disable_irq这个函数,否则内核崩溃,可以使用disable_irq_nosync,disable_irq: 函数调用后,函数不会马上返回,而等待中断程序执行完成才返回,在中断调用会导致死锁。使能中断: void enable_irq(unsigned int irq); 参数: irq, 要使能的中断对应的编号。4) 获取irq中断号 Int gpio_to_irq(unsigned int irq); 参数: irq,要使能的中断对应的编号2. 外部IO中断驱动编写2.1 IO原理图https://18821080.s21i.faiusr.com/4/ABUIABAEGAAg6KGSqgYohIj97AEwoAc4oAQ.png图2.1 GPIO0_D6 GPIO0_D6=0*32+(4-1)-8+6=302.2 驱动示例代码#include<linux/init.h>#include<linux/module.h>#include<linux/gpio.h>#include<linux/interrupt.h>#include<linux/timer.h>
#defineGPIO_PIN 30// 替换为你的GPIO引脚
staticunsigned int irq_number;
//GPIO中断处理函数staticirqreturn_t gpio_irq_handler(int irq, void *dev_id) { printk("GPIO中断触发!\n"); return IRQ_HANDLED;}staticint __init mymodule_init(void) { int ret; // 请求GPIO ret = gpio_request(GPIO_PIN,"my_gpio"); if (ret) { printk("无法请求GPIO %d\n",GPIO_PIN); return ret; }
// 配置GPIO引脚为输入 ret = gpio_direction_input(GPIO_PIN); if (ret) { printk("无法配置GPIO %d 为输入\n", GPIO_PIN); gpio_free(GPIO_PIN); return ret; }
// 请求GPIO中断 irq_number = gpio_to_irq(GPIO_PIN); ret = request_irq(irq_number, gpio_irq_handler,IRQF_TRIGGER_RISING, "my_gpio_irq", NULL);/* IRQF_TRIGGER_RISING上升沿有效 */ if (ret) { printk("无法请求GPIO中断 %d\n",irq_number); gpio_free(GPIO_PIN); return ret; } printk("模块加载成功\n"); return 0;}staticvoid __exit mymodule_exit(void) { // 释放GPIO中断 free_irq(irq_number, NULL);
// 释放GPIO gpio_free(GPIO_PIN);
printk("模块卸载成功\n");}
module_init(mymodule_init);module_exit(mymodule_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("zou");MODULE_DESCRIPTION("SampleGPIO and Timer Interrupt Kernel Module");3. 外部IO中断验证将驱动编译成模块,insmod加载模块后。由于驱动检测GPIO0_D6上升沿有效,当给该引脚提供高电平时,会触发中断执行中断处理函数。
https://18821080.s21i.faiusr.com/4/ABUIABAEGAAggKKSqgYo5Onu1AYw6AU4fw.png图3.1触发IO中断
页:
[1]