迅为嵌入式linux驱动开发笔记(六)— 中断与中断下文_linux中断 迅为

	key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /\* KEY0 \*/ 
	interrupt-parent = <&gpio1>; 
	interrupts = <18 IRQ_TYPE_EDGE_BOTH>; /\* FALLING RISING \*/
	 status = "okay"

}


在这个例子中, 我们先使用 pinctrl 和 gpio 子系统把这个引脚设置为了 gpio 功能, 因为在使用中断的时候需要把引脚设置成输入。然后使用 interrupt-parent 和 interrupts 属性来描述中断。 interrupt-parent 的属性值是 gpio1,也就是要使用 gpio1这个中断控制器, 为什么是 gpio1 呢,因为引脚使用的是 gpio1 里面的io18,所以使用的是gpio1这个中断控制器。interrupts 属性设置的是中断源,为什么里面是俩个cells 呢, 因为在 gpio1 这个中断控制器里面#interrupt-cells 的值为 2, 如下图所示:


![在这里插入图片描述](https://img-blog.csdnimg.cn/93fb9df620a24178a4b2a8688ca0bbcd.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5qKF5bGx5YmR5a6i,size_20,color_FFFFFF,t_70,g_se,x_16)


例子中的第一个 cells 的 18 表示 GPIO1 组的 18 号 IO。 IRQ\_TYPE\_EDGE\_BOTH 表示 上升沿和下降沿同时有效。 IRQ\_TYPE\_EDGE\_BOTH 定义在文件 include/linux/irq.h 中, 定义如下:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/3891dd053349418c8b4e6366d7e38103.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5qKF5bGx5YmR5a6i,size_20,color_FFFFFF,t_70,g_se,x_16)  
 所以在设备树里面配置中断的时候只需要俩个步骤即可, 第一个步骤是把管脚设置为 gpio 功能。 第二个步骤是使用 interrupt-parent 和 interrupts 属性来描述中断。


#### 二. 中断相关函数


<1>获取中断号相关函数  
 编写驱动的时候需要用到中断号,每一个中断都有中断号, 用到中断号,中断信息已经写到了设备树里面, 因此可以通过 irq\_of\_parse\_and\_map 函数从 interupts 属性中提取到对应的设备号,函数原型如下:



unsigned int irq_of_parse_and_map(struct device_node *dev,int index)


参数: dev 设备节点。  
 index: 索引号,interrupts 属性可能包含多条中断信息,通过 index 指定要获取的信息。  
 返回值: 中断号。  
 如果使用 GPIO 的话,可以使用 gpio\_to\_irq 函数来获取 gpio 对应的中断号,函数原型如下:



int gpio_to_irq(unsigned int gpio)


参数: gpio: 要获取的 GPIO 编号。  
 返回值: GPIO 对应的中断号。


<2>申请中断函数 同 GPIO 一样,在 Linux 内核里面,如果要使用某个中断也是需要申请的,申请中断使用的函数是 request\_irq函数原型:



int request_irq( unsigned int irq, i rq_handler_t handler, unsigned long flags, const char *name, void *dev)


参数:  
 irq:要申请中断的中断号。  
 handler:中断处理函数,当中断发生以后就会执行此中断处理函数。  
 flags:中断标志。  
 中断标识可以在文件 include/linux/interrupt.h 里面查看所有的中断标志, 介绍几个常用的中断标志,如下图所示:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9d97c973ee1e4cb5a65cbf4db68d3358.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5qKF5bGx5YmR5a6i,size_20,color_FFFFFF,t_70,g_se,x_16)name: 中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。  
 dev: 如果将 flags 设置为 IRQF\_SHARED 的话, dev 用来区分不同的中断, 一 般 情 况 下将 dev 设置为设备 结构体,dev会传递给中断处理函数 irq\_handler\_t 的第二个参数。  
 返回值:0 中断申请成功, 其他负值中断申请失败,如果返回-EBUSY的话表示中断已经被申请了。


< 3 > 中断处理函数  
 使用 request\_irq 函数申请中断的时候需要设置中断处理函数, 中断处理函数 格式 如下所示:第一个参数是要中断处理函数要相应的中断号。 第二个参数是一个指 向 void 的指 针 ,也就是个通用 指 针 , 需要 与 request\_irq 函数的 dev 参数 保持 一 致 。 用于区分 共享 中断的不同设备, dev 也可以指 向 设备数 据结构 。 中断处理函数的返回值为 i rqreturn\_t 类 型, irqreturn\_t 类 型定义如下所示:



enum irqreturn {
IRQ_NONE = (0 << 0),
IRQ_HANDLED = (1 << 0),
IRQ_WAKE_THREAD = (1 << 1),
};
typedef enum irqreturn irqreturn_t;


可以看 出 irqreturn \_t 是个枚举类 型, 一共 有三种返回值。一般中断服务函数返回值使用如下 形式 :


< 4 >free\_irq 函数  
 中断使用完成以后就要通过 free\_irq 函数释放掉相应的中断。如果中断不是共享 的,那么 free\_irq 会删除中断处理函数并且禁止中断。free\_irq 函数原型如下所示:



void free_irq(unsigned int irq,void *dev)


参数:  
 irq:要释放的中断。  
 dev: 如果中断设置为 共享( IRQF\_SHARED ) 的话, 此参数用来区分具体的中断。共享中断只有在 释放最 后中断处理函数的时候才会被禁止掉。  
 返回值: 无


#### 按键中断实验


包含头文件



#include <linux/interrupt.h>


修改设备树信息



test_key{
compatible = “keys”;
pinctrl-names = “default”;
pintrl-0=<&pinctrl_gpio_keys>;//通过宏 把管脚设置为gpio功能
gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;

}


修改驱动匹配函数



const struct of_device_id of_match_table[] =
{
{.compatible = “keys”},
{},
};


在beep\_probe添加如下的代码:



int beep_probe(struct platform_device *pdev){

/\*查找我们要查找的节点\*/
test_device_node = of\_find\_node\_by\_path("/test\_key");
if (test_device_node == NULL)
{
    printk("of\_find\_by\_path is erron\n");
    return -1;
}    //获取gpio的节点

gpio_num = of\_get\_named\_gpio(test_device_node,"gpios",0);//获取gpio
if (gpio_num<0)
{    
    printk("of\_get\_named\_gpio is erron\n");
    return -1;
}

gpio\_direction\_input(gpio_num);//设置方向为输入

irq = gpio\_to\_irq(gpio_num);//获取中断号

printk("irq is %d\n", irq);

ret = request\_irq(irq,test_key,IRQF_TRIGGER_RISING,"test\_key",NULL);
if (ret<0)
{
    printk("request\_irq is erron\n");
    return -1;
}
return 0;

}


烧入驱动:cat /proc/interrupts 查看中断是否加载完成。  
 cat /proc/irq/48/spurious 查看中断次数。


#### 方法2:修改设备树代码


驱动设备树代码:



test_key{
compatible = “keys”;
pinctrl-names = “default”;
pintrl-0=<&pinctrl_gpio_keys>;//通过宏 把管脚设置为gpio功能
gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
//方法2 :在设备树上修改代码
interrupt-parent = <&gpio1>;
interrupts =<18 IRQ_TYPE_EDGE_BOTH>;/*FALLING RISING*/
}


包含头文件



#include<linux/of_irq.h>


驱动代码:



int beep_probe(struct platform_device *pdev){

/\*查找我们要查找的节点\*/
test_device_node = of\_find\_node\_by\_path("/test\_key");
if (test_device_node == NULL)
{
    printk("of\_find\_by\_path is erron\n");
    return -1;
}    //获取gpio的节点

 /\*获取GPIO的编号\*/
gpio_num = of\_get\_named\_gpio(test_device_node,"gpios",0);//获取gpio
if (gpio_num<0)
{    
    printk("of\_get\_named\_gpio is erron\n");
    return -1;
} 

/\*设置gpio的方向\*/
gpio\_direction\_input(gpio_num);//设置方向为输入

//irq = gpio\_to\_irq(gpio\_num);//获取中断号

/\*获取irq的编号\*/
irq = irq\_of\_parse\_and\_map(test_device_node,0);//第二种获取中断号的方式,索引号为0

printk("irq is %d\n", irq);
/\*申请中断\*/
ret = request\_irq(irq,test_key,IRQF_TRIGGER_RISING,"test\_key",NULL);
if (ret<0)
{
    printk("request\_irq is erron\n");
    return -1;
}
return 0;

}


#### 中断下文之tasklet


#### 一、tasklet 相关知识点


1、什么是 tasklet ?  
 tasklet 是中断处理中断下文常用的一种方法,tasklet 是一种特殊的软中断。 处理中断下文的机制还有工作队列和软中断。  
 2、怎么使用 tasklet 来设计中断下文?  
 框图:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9e56c0f905214a2b92e4fd9c54d27d5b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5qKF5bGx5YmR5a6i,size_17,color_FFFFFF,t_70,g_se,x_16)  
 Linux 把中断分成俩个部分,一个是上半部分,一个是下半部分,在上半部分我们只 处理紧急的事情,同时可以调用 tasklet 来启动中断下文,比较耗时间的就要放到下文来 处理,调用 tasklet 以后, tasklet 绑定的函数并不会立马执行,而是出中断以后,经过一 个很短的不确定时间在来执行。  
 3、tasklet 定义  
 tasklet 由 tasklet\_struct 结构表示,每个结构体单独代表一个 tasklet , 在<linux/interrupt.h> 中定义为:



struct tasklet_struct {
struct tasklet_struct *next;

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

-1715840826412)]

[外链图片转存中…(img-yf5e6nYq-1715840826413)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值