嵌入式内核及驱动开发之学习笔记(六) 驱动层中断实现

举报
王建峰 发表于 2021/11/19 03:45:18 2021/11/19
【摘要】 由于中断信号的突发性,CPU要捕获中断信号,有两种方式。一是不断轮询是否有中断发生,这样有点傻;二是通过中断机制,过程如下: 中断源 ---> 中断信号  --->  中断控制器 --->  CPU  中断源有很多,CPU拿到中断信号,如何区分是哪一个中断源产生?那...

由于中断信号的突发性,CPU要捕获中断信号,有两种方式。一是不断轮询是否有中断发生,这样有点傻;二是通过中断机制,过程如下:

中断源 ---> 中断信号  --->  中断控制器 --->  CPU

 中断源有很多,CPU拿到中断信号,如何区分是哪一个中断源产生?那么一定有一个序列,标识不同的中断源发出的信号,这就是中断号了。

 

ARM裸机开发中,使用中断前需要进行不少配置,比较繁琐。而从内核的角度,我们只要明确两个目标

  • 中断号
  • 中断的处理方法

 

实验:在驱动中添加中断机制,按键触发外部中断,中断产生后,驱动打印中断信息。

 

步骤

定义中断号

在通过原理图,芯片手册查询,从硬件连接最终定位到中断号

 

通过源码,系统设备树描述中

每一个设备的节点都要有一个compatible属性 ,用来查找节点(也可以通过节点名或节点路径查找指定节点);interrupt-parent表示结点继承至gic。


  
  1. root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
  2. gpx1: gpx1 {
  3. gpio-controller;
  4. #gpio-cells = <2>;
  5. interrupt-controller;
  6. interrupt-parent = <&gic>;
  7. interrupts = <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
  8. <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
  9. #interrupt-cells = <2>;
  10. };

 

手动定义设备树节点,参考上面的系统描述和硬件设备号。定义如下


  
  1. root@linux:~/linux-3.14-fs4412# vim arch/arm/boot/dts/exynos4412-fs4412.dts
  2. key_int_node{
  3. compatible = "test_key";
  4. interrupt-parent = <&gpx1>;
  5. interrupts = <2 4>;
  6. };

 

重新编译设备树,并更新tftp根目录下的设备树文件


  
  1. make dtbs
  2. cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/

 

编写驱动代码

get_irqno_from_node函数通过设备树的路径到设备结点的中断号;然后request_irq申请中断,并设置触发方式是双边沿触发,key_irq_handler指定为中断处理函数;在key_irq_handler中只有一条打印信息,当中断产生,触发这条函数,打印信息;模块卸载时,通过free_irq释放掉之前申请的中断资源。


  
  1. //key_drv.c
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/of.h>
  5. #include <linux/of_irq.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/slab.h>
  8. #include <linux/fs.h>
  9. #include <linux/device.h>
  10. #include <asm/io.h>
  11. #include <asm/uaccess.h>
  12. irqreturn_t key_irq_handler(int irqno, void *devid);
  13. static int irqno;
  14. int get_irqno_from_node(void)
  15. {
  16. //从设备树路径,查找节点
  17. struct device_node *np = of_find_node_by_path("/key_int_node");
  18. if(np){
  19. printk("find node ok\n");
  20. }else{
  21. printk("find node failed\n");
  22. }
  23. int irqno = irq_of_parse_and_map(np, 0);
  24. printk("irqno = %d\n", irqno);
  25. return irqno;
  26. }
  27. static int __init key_drv_init(void)
  28. {
  29. int ret;
  30. //拿到中断号
  31. irqno = get_irqno_from_node();
  32. //申请中断资源
  33. ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
  34. "key3_eint10", NULL);
  35. if(ret != 0)
  36. {
  37. printk("request_irq error\n");
  38. return ret;
  39. }
  40. return 0;
  41. }
  42. static void __exit key_drv_exit(void)
  43. {
  44. //释放中断资源
  45. free_irq(irqno, NULL);
  46. }
  47. irqreturn_t key_irq_handler(int irqno, void *devid)
  48. {
  49. printk("-------%s-------------\n", __FUNCTION__);
  50. return IRQ_HANDLED;
  51. }
  52. module_init(key_drv_init);
  53. module_exit(key_drv_exit);
  54. MODULE_LICENSE("GPL");

 

Makefile文件


  
  1. ROOTFS_DIR = /nfs/rootfs
  2. ifeq ($(KERNELRELEASE), )
  3. KERNEL_DIR = /mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412
  4. CUR_DIR = $(shell pwd)
  5. all :
  6. make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
  7. clean :
  8. make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
  9. install:
  10. cp -raf *.ko $(ROOTFS_DIR)/drv_module
  11. else
  12. obj-m += key_drv.o
  13. endif

 

编译

Ubuntu环境编译,目标文件输出到nfs目录,nfs共享给开发板执行。


  
  1. root@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make
  2. 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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。