程序技术好文:驱动开发——中断号与中断编程

简介: 程序技术好文:驱动开发——中断号与中断编程

目录:


  1、中断号


  2、获取中断号


  3、实现中断处理


  4、中断编程—实现字符设备驱动框架


  5、驱动实现将硬件数据传递给数据


  6、示例


1、中断号


  中断号是系统分配给每个中断源的代号,以便识别和处理。在采用向量中断方式的中断系统中,CPU必须通过它才可以找到中断服务程序的入口地址,实现程序的转移。


  在ARM裸机中实现中断需要配置:


1 I/O口为中断模式,触发方式,I/O口中断使能


2 设置GIC中断使能,分发配置,分发总使能,CPU外部中断接口使能,中断优先级


  在linux内核中实现中断,只需要知道:


1 中断号是什么,怎么得到中断号


2 中断处理方法


 2、获取中断号的方法:


  1)宏定义


    在没有设备树的内核中,中断号定义为宏,IRQ_EINT


  2)设备树文件中


    arch/arm/boot/dts/exynos4412-fs4412.dts


  1)看原理图,芯片手册找到中断源对应的中断号SPI Port No


  2)进入设备树,在arch/arm/boot/dts/exynos4x12-pinctrl.dtsi中


1 gpx1: gpx1 {


2 gpio-controller;


3 #gpio-cells = [span style="color: rgba(128, 0, 128, 1)">2

4


5 interrupt-controller; //中断控制器


6 interrupt-parent = ; //继承于gic


7 interrupts = [span style="color: rgba(128, 0, 128, 1)">0 24 00 25 00 26 00 27 0

8 [span style="color: rgba(128, 0, 128, 1)">0 28 00 29 00 30 00 31 0

9 #interrupt-cells = [span style="color: rgba(128, 0, 128, 1)">2

10 };


  括号中的24、 25等对应于SPI Port No,以上是系统中已经定义好的节点


在编程中,需要定义自己的节点,用来描述按键,打开可编辑的设备树文件:


arch/arm/boot/dts/exynos4412-fs4412.dts,进入文件。


  3)定义节点,描述当前设备用的中断号


1 key_int_node{


2 compatible = "test_key";


3 interrupt-parent = ; //继承于gpx1


4 interrupts = [span style="color: rgba(128, 0, 128, 1)">2 4

5 }; //interrupts里长度由父母的-cell决定


  再举个栗子,设置k4 --- GPX3_2(XEINT26) 的节点,中断号


1 key_int_node{


2 compatible = "test_key";


3 interrupt-parent = ; //继承于gpx3


4 interrupts = [span style="color: rgba(128, 0, 128, 1)">2 4

5 };


    中断号的定位方法:


    看I/O引脚,GPX1_2,中断号就是GPX1里面的第2个


  4)编译设备树:make dtbs


    更新设备树文件: cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/


    查看定义的节点:在根目录的 proc/device-tree/目录下  


3、实现中断处理方法


  在驱动中通过代码获取到中断号,并且申请中断


  先看一下中断相关的函数:


1 a,获取到中断号码:


2 int get_irqno_from_node(void)


3 {


4 // 获取到设备树中的节点


5 struct device_node np = of_find_node_by_path("/key_int_node");


6 if(np){


7 printk("find node ok\n");


8 }else{


9 printk("find node failed\n");


10 }


11


12 // 通过节点去获取到中断号码


13 int irqno = irq_of_parse_and_map(np, 0);


14 printk("irqno = %d\n", irqno);


15


16 return irqno;


17 }


18 b,申请中断


19 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char name, void dev)


20 参数1: irq 设备对应的中断号


21 参数2: handler 中断的处理函数


22 typedef irqreturn_t (irq_handler_t)(int, void );


23 参数3:flags 触发方式


24 #define IRQF_TRIGGER_NONE 0x00000000 //内部控制器触发中断的时候的标志


25 #define IRQF_TRIGGER_RISING 0x00000001 //上升沿


26 #define IRQF_TRIGGER_FALLING 0x00000002 //下降沿


27 #define IRQF_TRIGGER_HIGH 0x00000004 // 高点平


28 #define IRQF_TRIGGER_LOW 0x00000008 //低电平触发


29 参数4:name 中断的描述,自定义,主要是给用户查看的


30 /proc/interrupts


31 参数5:dev 传递给参数2中函数指针的值


32 返回值: 正确为0,错误非0


33


34


35 参数2的赋值:即中断处理函数


36 irqreturn_t key_irq_handler(int irqno, void devid)


37 {


38 return IRQ_HANDLED;


39 }


43


44 c, 释放中断:


45 void free_irq(unsigned int irq, void dev_id)


46 参数1: 设备对应的中断号


47 参数2:与request_irq中第5个参数保持一致


代码实现获取中断号,并注册中断,按下按键引发中断,打印信息


1 #include


2 #include


3 #include


4 #include


5 #include


6 #include


7 #include


8 #include


9 #include


10 #include


11


12 int irqno; //中断号


13


14


15 irqreturn_t key_irq_handler(int irqno, void devid)


16 {


17 printk("----------%s---------",FUNCTION);


18 return IRQ_HANDLED;


19 }


20


21


22 //获取中断号


23 int get_irqno_from_node(void)


24 {


25 //获取设备树中的节点


26 struct device_node *np = of_find_node_by_path("/key_int_node");


27 if(np){


28 printk("find node success\n");


29 }else{


30 printk("find node failed\n");


31 }


32


33 //通过节点去获取中断号


34 int irqno = irq_of_parse_and_map(np, 0);


35 printk("iqrno = %d",irqno);


36


37 return irqno;


38 }


39


40


41


42 static int init key_drv_init(void)


43 {


44 //演示如何获取到中断号


45 int ret;


46


47 irqno = get_irqno_from_node();


48


49 ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,


50 "key3_eint10", NULL);


51 if(ret != 0)


52 {


53 printk("request_irq error\n");


54 return ret;


55 }


56


57 return 0;


58 }


59


60 static void exit key_drv_exit(void)


61 {


62 free_irq(irqno, NULL); //free_irq与request_irq的最后一个参数一致


63 }


64


65


66


67 module_init(key_drv_init);


68 module_exit(key_drv_exit);


69


70 MODULE_LICENSE("GPL");


key_drv.c


测试效果:


按键按下,打印信息,但出现了按键抖动


cat /proc/interrupt


  4、 中断编程 --- 字符设备驱动框架


1 // 1,设定一个全局的设备对象


2 key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);


3


4 // 2,申请主设备号


5 key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);


6


7 // 3,创建设备节点文件


8 //代码效果参考:http://www.jhylw.com.cn/414939743.html

key_dev->cls = class_create(THIS_MODULE, "key_cls");

9 key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,0), NULL, "key0");


10


11 // 4,硬件初始化:


12 a.地址映射


13 b.中断申请


  5、驱动实现将硬件所产生的数据传递给用户


  1)硬件如何获取数据


key: 按下和抬起: 1/0


读取key对应的gpio的状态,可以判断按下还是抬起


读取key对应gpio的寄存器--数据寄存器


//读取数据寄存器


int value = readl(key_dev->reg_base + 4) & (1[2);


  2)驱动传递数据给用户


在中断处理中填充数据:


key_dev->event.code = KEY_ENTER;


key_dev->event.value = 0;


在xxx_read中奖数据传递给用户


ret = copy_to_user(buf, &key_dev->event, count);


  3)用户获取数据


while(1)


{


read(fd, &event, sizeof(struct key_event));


if(event.code == KEY_ENTER)


{


if(event.value)


{


printf("APP key enter pressed\n");


}else{


//代码效果参考:http://www.jhylw.com.cn/062323019.html

printf("APP key enter up\n");

}


}


}


<a href="javascript:void(0);" onclick="co

相关文章
|
27天前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
42 1
|
2月前
|
存储 缓存 Linux
中断系列第三篇:中断实操一下?
中断系列第三篇:中断实操一下?
47 0
|
10月前
|
缓存 NoSQL 安全
Linux设备驱动程序(四)——调试技术3
Linux设备驱动程序(四)——调试技术3
98 0
|
7天前
|
Java C++ Windows
程序技术好文:调试器工作原理
程序技术好文:调试器工作原理
|
7天前
|
C语言
程序技术好文:部分ARM汇编指令解读
程序技术好文:部分ARM汇编指令解读
|
2月前
|
存储
【51单片机】初学者必读的一文【探究定时计数器与中断系统是如何配合起来的?】(9)
【51单片机】初学者必读的一文【探究定时计数器与中断系统是如何配合起来的?】(9)
|
10月前
|
NoSQL 安全 Linux
Linux设备驱动程序(四)——调试技术1
Linux设备驱动程序(四)——调试技术1
111 0
|
10月前
|
安全 Unix Linux
Linux设备驱动程序(四)——调试技术2
Linux设备驱动程序(四)——调试技术2
65 0
|
Linux 调度
Linux驱动开发——中断编程之顶半部与底半部机制(1)
Linux驱动开发——中断编程之顶半部与底半部机制(1)
169 0
Linux驱动开发——中断编程之顶半部与底半部机制(1)
|
C语言
【嵌入式实训】STM32中断处理机制及外部中断使用方法
理论知识 STM32系列处理器外部中断/事件控制器的原理 共19个外部中断线,其中GPIO端口以下图的方式连接到16个外部中断/事件线上: 另外三种其他的外部中断/事件控制器的连接如下:EXTI 线 
560 0

热门文章

最新文章