嵌入式内核及驱动开发之学习笔记(六) 驱动层中断实现
由于中断信号的突发性,CPU要捕获中断信号,有两种方式。一是不断轮询是否有中断发生,这样有点傻;二是通过中断机制,过程如下:
中断源 ---> 中断信号 ---> 中断控制器 ---> CPU
中断源有很多,CPU拿到中断信号,如何区分是哪一个中断源产生?那么一定有一个序列,标识不同的中断源发出的信号,这就是中断号了。
在ARM裸机开发中,使用中断前需要进行不少配置,比较繁琐。而从内核的角度,我们只要明确两个目标
- 中断号
- 中断的处理方法
实验:在驱动中添加中断机制,按键触发外部中断,中断产生后,驱动打印中断信息。
步骤
定义中断号
在通过原理图,芯片手册查询,从硬件连接最终定位到中断号
通过源码,系统设备树描述中
每一个设备的节点都要有一个compatible属性 ,用来查找节点(也可以通过节点名或节点路径查找指定节点);interrupt-parent表示结点继承至gic。
-
root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
-
-
gpx1: gpx1 {
-
gpio-controller;
-
#gpio-cells = <2>;
-
-
interrupt-controller;
-
interrupt-parent = <&gic>;
-
interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
-
<0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
-
#interrupt-cells = <2>;
-
};
手动定义设备树节点,参考上面的系统描述和硬件设备号。定义如下
-
root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4412-fs4412.dts
-
-
key_int_node{
-
compatible = "test_key";
-
interrupt-parent = <&gpx1>;
-
interrupts = <2 4>;
-
};
重新编译设备树,并更新tftp根目录下的设备树文件
-
make dtbs
-
cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/
编写驱动代码
get_irqno_from_node函数通过设备树的路径到设备结点的中断号;然后request_irq申请中断,并设置触发方式是双边沿触发,key_irq_handler指定为中断处理函数;在key_irq_handler中只有一条打印信息,当中断产生,触发这条函数,打印信息;模块卸载时,通过free_irq释放掉之前申请的中断资源。
-
//key_drv.c
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/of.h>
-
#include <linux/of_irq.h>
-
#include <linux/interrupt.h>
-
#include <linux/slab.h>
-
#include <linux/fs.h>
-
#include <linux/device.h>
-
-
#include <asm/io.h>
-
#include <asm/uaccess.h>
-
-
irqreturn_t key_irq_handler(int irqno, void *devid);
-
-
-
-
static int irqno;
-
-
-
int get_irqno_from_node(void)
-
{
-
//从设备树路径,查找节点
-
struct device_node *np = of_find_node_by_path("/key_int_node");
-
if(np){
-
printk("find node ok\n");
-
}else{
-
printk("find node failed\n");
-
}
-
-
int irqno = irq_of_parse_and_map(np, 0);
-
printk("irqno = %d\n", irqno);
-
-
return irqno;
-
}
-
-
-
static int __init key_drv_init(void)
-
{
-
int ret;
-
-
//拿到中断号
-
irqno = get_irqno_from_node();
-
-
//申请中断资源
-
ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
-
"key3_eint10", NULL);
-
if(ret != 0)
-
{
-
printk("request_irq error\n");
-
return ret;
-
}
-
-
return 0;
-
}
-
-
static void __exit key_drv_exit(void)
-
{
-
//释放中断资源
-
free_irq(irqno, NULL);
-
-
}
-
-
-
irqreturn_t key_irq_handler(int irqno, void *devid)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
-
return IRQ_HANDLED;
-
}
-
-
-
-
module_init(key_drv_init);
-
module_exit(key_drv_exit);
-
-
MODULE_LICENSE("GPL");
-
Makefile文件
-
ROOTFS_DIR = /nfs/rootfs
-
-
ifeq ($(KERNELRELEASE), )
-
-
KERNEL_DIR = /mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412
-
CUR_DIR = $(shell pwd)
-
-
all :
-
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
-
-
clean :
-
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
-
-
install:
-
cp -raf *.ko $(ROOTFS_DIR)/drv_module
-
-
-
else
-
-
obj-m += key_drv.o
-
-
-
-
endif
-
编译
Ubuntu环境编译,目标文件输出到nfs目录,nfs共享给开发板执行。
-
root@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make
-
root@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make install
实验结果
按下按键(1->0),触发一次中断。松下按键(0->1),又触发一次中断。
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/84106949
- 点赞
- 收藏
- 关注作者
评论(0)