linux中断号指的是什么
本篇内容主要讲解“linux中断号指的是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux中断号指的是什么”吧!
linux中断号是系统分配给每个中断源的代号,以便识别和处理;在采用向量中断方式的中断系统中,CPU必须通过它才可以找到中断服务程序的入口地址,实现程序的转移。
中断号与中断编程:
1、中断号
中断号是系统分配给每个中断源的代号,以便识别和处理。在采用向量中断方式的中断系统中,CPU必须通过它才可以找到中断服务程序的入口地址,实现程序的转移。
在ARM裸机中实现中断需要配置:
I/O口为中断模式,触发方式,I/O口中断使能<br> 设置GIC中断使能,分发配置,分发总使能,CPU外部中断接口使能,中断优先级<br>
在linux内核中实现中断,只需要知道:
中断号是什么,怎么得到中断号<br>中断处理方法<br>
2、获取中断号的方法:
/arm/boot/dts/exynos4412-fs4412.dts<br>
1)看原理图,芯片手册找到中断源对应的中断号SPI Port No
2)进入设备树,在arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
中
<pre>gpx1: gpx1 {
gpio-controller;
#gpio-cells = ;
interrupt-controller; //中断控制器
interrupt-parent = ; //继承于gic
interrupts = , , , ,
, , , ;
#interrupt-cells = ; //子继承的interrupts的长度
};</pre>
括号中的24、 25等对应于SPI Port No,以上是系统中已经定义好的节点
在编程中,需要定义自己的节点,用来描述按键,打开可编辑的设备树文件:
arch/arm/boot/dts/exynos4412-fs4412.dts,进入文件。
3)定义节点,描述当前设备用的中断号
1 key_int_node{<br>2 compatible = "test_key";<br>3 interrupt-parent = ; //继承于gpx1<br>4 interrupts = ; //2表示第几个中断号,4表示触发方式为下降沿5 }; //interrupts里长度由父母的-cell决定<br>
再举个栗子,设置k4 --- GPX3_2(XEINT26) 的节点,中断号
<pre>1 key_int_node{
2 compatible = "test_key";
3 interrupt-parent = ; //继承于gpx3
4 interrupts = ; //2表示第2个中断号,4表示触发方式为下降沿
5 };</pre>
中断号的定位方法:
看I/O引脚,GPX1_2,中断号就是GPX1里面的第2个
4)编译设备树:make dtbs
更新设备树文件: cp -raf arch/arm/boot/dts/exynos4412-fs4412.dtb /tftpboot/
查看定义的节点:在根目录的 proc/device-tree/目录下
3、实现中断处理方法
在驱动中通过代码获取到中断号,并且申请中断
先看一下中断相关的函数:
<pre>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 okn");
8 }else{
9 printk("find node failedn");
10 }
11
12 // 通过节点去获取到中断号码
13 int irqno = irq_of_parse_and_map(np, 0);
14 printk("irqno = %dn", 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个参数保持一致</pre>
代码实现获取中断号,并注册中断,按下按键引发中断,打印信息
1 #include <br> 2 #include <br> 3 #include <br> 4 #include <br> 5 #include <br> 6 #include <br> 7 #include <br> 8 #include <br> 9 #include <br>10 #include <br>11 <br>12 int irqno; //中断号<br>13 <br>14 <br>15 irqreturn_t key_irq_handler(int irqno, void *devid)<br>16 {<br>17 printk("----------%s---------",__FUNCTION__);<br>18 return IRQ_HANDLED;<br>19 }<br>20 <br>21 <br>22 //获取中断号<br>23 int get_irqno_from_node(void)<br>24 {<br>25 //获取设备树中的节点<br>26 struct device_node *np = of_find_node_by_path("/key_int_node");<br>27 if(np){<br>28 printk("find node successn");<br>29 }else{<br>30 printk("find node failedn");<br>31 }<br>32 <br>33 //通过节点去获取中断号<br>34 int irqno = irq_of_parse_and_map(np, 0);<br>35 printk("iqrno = %d",irqno);<br>36 <br>37 return irqno;<br>38 }<br>39 <br>40 <br>41 <br>42 static int __init key_drv_init(void)<br>43 {<br>44 //演示如何获取到中断号<br>45 int ret;<br>46 <br>47 irqno = get_irqno_from_node();<br>48 <br>49 ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, <br>50 "key3_eint10", NULL);<br>51 if(ret != 0)<br>52 {<br>53 printk("request_irq errorn");<br>54 return ret;<br>55 }<br>56 <br>57 return 0;<br>58 }<br>59 <br>60 static void __exit key_drv_exit(void)<br>61 {<br>62 free_irq(irqno, NULL); //free_irq与request_irq的最后一个参数一致<br>63 }<br>64 <br>65 <br>66 <br>67 module_init(key_drv_init);<br>68 module_exit(key_drv_exit);<br>69 <br>70 MODULE_LICENSE("GPL");<br>key_drv.c<br>
key_drv.c
测试效果:
按键按下,打印信息,但出现了按键抖动
cat /proc/interrupt
4、 中断编程 --- 字符设备驱动框架
<pre>// 1,设定一个全局的设备对象
key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);
// 2,申请主设备号
key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
// 3,创建设备节点文件
key_dev->cls = class_create(THIS_MODULE, "key_cls");
key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major,0), NULL, "key0");
// 4,硬件初始化:
a.地址映射
b.中断申请</pre>
5、驱动实现将硬件所产生的数据传递给用户
1)硬件如何获取数据
<pre>key: 按下和抬起: 1/0读取key对应的gpio的状态,可以判断按下还是抬起
读取key对应gpio的寄存器--数据寄存器
//读取数据寄存器int value = readl(key_dev->reg_base + 4) & (1event.value = 0;<br>在xxx_read中奖数据传递给用户<br> ret = copy_to_user(buf, &key_dev->event, count);<br></pre>