赞
踩
《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记
CPU 在正常运行期间,由外部或者内部引起的事件,让 CPU 停下当前正在运行的程序,转而去执行触发他中断的对应程序,处理完中断对应程序后再回来继续运行。这就是中断。
虽然中断可以提高 CPU 的运行效率,但中断会打断内核进程的正常调度和运行,所以为了保证系统的实时性,中断服务程序必须足够短。但实际应用中,我们可能需要在中断后执行一些比较耗时的任务,为此,内核提出了中断上下文的概念,即把中断服务程序分为两部分,中断上文和中断下文。
中断上文用来完成比较紧急且耗时短的任务,中断下文用来处理比较耗时的任务。
中断号(IRQ number)也叫软中断号,在 Linux 系统中是唯一的,也是我们在中断编程中需要用到的中断号。
- SGI(Software-generated interrupt):范围0 - 15,软件触发的中断,一般用于核间通讯
- PPI(Private peripheral interrupt ): 范围16 - 31,私有外设中断,只对指定的core有效
- SPI(Shared peripheral interrupt):范围32 - 1019,共享中断,不限定特定的core
操作内核中断,我们需要使用到中断号,gpio_to_irq() 可以将 GPIO 编号转换为中断号,该函数原型如下:
int gpio_to_irq(unsigned gpio);
内核中 request_irq() 函数被用来申请中断,该函数原型如下:
#include <linux/interrupt.h>
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
const char *name, void *dev);
函数功能:向内核注册一个中断服务函数(当 irq 对应的中断发生时,会执行 handler 指向的中断服务函数)。
中断服务函数原型为:typedef irqreturn_t (*irq_handler_t)(int, void *)
函数参数
flags 可取值可以在 linux/interrupt.h 头文件查看,本文将用到标志有 IRQF_TRIGGER_RISING 和 IRQF_TRIGGER_FALLING。
当 flags 指定为共享中断(IRQF_SHARED)时,dev 参数不能为 NULL,并且不同的共享中断 dev 参数不能相同,因为共享中断可以注册多个中断函数,中断号相同,所以需要根据 dev 来区分不同的中断函数。
返回值
返回 0 表示申请成功,失败返回负值。
free_irq() 用来注销中断,函数原型为 :
void free_irq(unsigned int irq, void *dev_id);
参数与 request_irq() 的部分参数意义相同,这里不再赘述。
【注意】在调用 free_irq() 时,为了防止此时中断被触发,需要先禁止中断。
禁止内核中断的函数包括:
void disable_irq_nosync(unsigned int irq);
void disable_irq(unsigned int irq);
disable_irq() 在调用后不会立刻返回,需要等待中断程序执行完才返回,所以在中断服务函数中不能调用该函数。
disable_irq_nosync() 则会在调用后立刻返回。
函数原型:
void enable_irq(unsigned int irq);
迅为教学视频里用触摸屏所用的中断 IO 作为外部中断实验的 IO,在实验之前,需要将触摸屏驱动关闭。具体操作步骤为:进入内核根目录,输入 make ARCH=arm64 menucofig
,关闭 Device Driver -> Input device support -> Touchscreens 下的 FT5x06 触摸屏驱动:
修改完成后,用 .config 替换平台默认的配置文件(参考 rk3568 相关文档),然后编译内核,最后将内核烧录到开发板上。
我们要操作触摸屏中断脚,首先要知道中断脚的 IO,根据原理图得知其 IO 为 GPIO3_A5,
在驱动中,gpio 都是通过编号表示的,那么 GPIO3_A5 的编号是多少呢?这个问题在之前的点灯实验中已经提及:
到网上找资料发现,RK3568 的 GPIO 编号很好计算,以 GPIO0_B7 为例,其 bank 为 0,group 为 1(A 为 0,以此类推),X 为 7,那么它的 pin 编号为 bank * 32 + group * 8 + X = 15,直白点讲,GPIO 的编号就是它在所有 IO 中所属序号
根据上面的公式, GPIO3_A5 的编号为 3 * 32 + 0 * 8 + 5 = 101
实验源码
下面是一个简单的中断驱动代码(参考原文/视频):
#include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/gpio.h> int irq; //中断服务函数 irqreturn_t my_interrupt(int irq, void *args) { printk("my interrupt handler.\n"); return IRQ_RETVAL(IRQ_HANDLED); } static int interrupt_irq_init(void) { int ret = 0; // 获取中断号 irq = gpio_to_irq(101); printk("irq is %d\n", irq); // 申请中断 ret = request_irq(irq, my_interrupt, IRQF_TRIGGER_RISING, "inttrupt_test", NULL); if(ret < 0) { printk("request irq error.\n"); return 0; } return 0; } static void interrupt_irq_exit(void) { printk("interrupt irq exit.\n"); // 注销中断 free_irq(irq, NULL); } module_init(interrupt_irq_init); module_exit(interrupt_irq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("xiaohui");
Makefile 文件:
#目标文件,与驱动源文件同名,编译成模块 obj-m := interrupt.o #架构平台选择 export ARCH=arm64 #编译器选择 export CROSS_COMPILE=aarch64-linux-gnu- #内核目录 KDIR := /home/topeet/Linux/rk356x_linux/kernel/ #编译模块 all: make -C $(KDIR) M=$(shell pwd) modules #清除编译文件 clean: make -C $(KDIR) M=$(shell pwd) clean
实验结果
触碰触摸屏时,中断触发,运行中断服务函数(打印数据到串口终端)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。