驱动开发,基于中断子系统完成按键的中断驱动,引入中断底半部

一.引入linux内核中断目的

        引入linux内核中断之前,内核访问设备要不断轮询访问;

        引入linux内核中断便于内核对设备的访问,当设备事件发生后主动通知内核,内核再去访问设备;

二.linux内核中断实现过程框图      

 根据软中断号回调当前中断的 中断函数 过程:

        中断注册进内核之后,中断信息会保存在一个struct irq_desc对象中,内核中存在一个struct irq_desc类型的数组,软中断号就是数组的下标,数组中每一个成员都是保存了一个注册进内核的设备中断信息,类型为struct irqaction,struct irqaction对象里有中断处理函数的函数指针,指向自定义中断处理函数;

三.添加按键的设备树节点

 在stm32mp157a-fsmp1a.dts文件的根节点内部添加如下内容:

myirq

{

compatible="myirq"; interrupt-parent=<&gpiof>; interrupts=<9 0>,<7 0>,<8 0>;

};

四.中断底半部

1.引入目的(解决问题)

        当一个中断被触发以后,会关闭抢占,一个单核CPU处理当前中断任务时,当前CPU无法处理其他任务,所有的CPU都会关闭当前中断线。在这种情况下,如果一个中断中有延时、耗时甚至休眠操作,最终会导致整个系统功能的延迟。所以一般在中断处理过程中不允许有延时、耗时甚至休眠的操作。但是有的时候又必须在中断的处理程序中进行一些耗时任务。

        这样就会产生一个冲突:中断不允许有耗时但是有时候需要耗时的冲突;

2.解决上面冲突,引入中断底半部

       将一个中断处理得分过程分为了中断顶半部和中断底半部,中断顶半部就是通过 request_irq注册的中断处理函数,在顶半部中主要进行一些重要的、不耗时的任务;中断底半部则是区进行一些耗时,不紧急的任务。在执行中断底半部时,会将执行中断顶半部时关闭的中断线启用以及抢占开启,这样进程以及其他的中断就可以正常的工作了。

3.中断底半部的实现机制

        实现机制有softirq(软中断)、tasklet以及工作队列;

1)软中断机制

        当顶半部即将执行结束时开启软中断,在软中断处理函数中取处理当前中断里的耗时任务。软中断存在数量限制(32个),一般留给内核开发者使用。

2)tasklet机制

  •         基于软中断工作原理进行的;
  •         tasklet没有使用数量的限制;
  •         中断底半部可以进行耗时任务,但不可以进行休眠操作;
  •         工作于中断上下文,不用于进程上下文;

3)工作队列机制

        内核中存在工作队列对应的内核线程,这个线程从内核启动就存在,处于休眠态。当有任务需要执行时,只需要将任务提交到工作队列中,然后唤醒休眠的内核线程,由内核线程去处理对应的任务即可。工作队列既可以用于中断,也可以用于进程。

4)tasklet机制驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>struct device_node *dnode;
unsigned int irqno[3];
int i;
struct tasklet_struct tasklet;  //分配tasklet对象//定义底半部处理函数
void key_callback(struct tasklet_struct *t)
{int i;//耗时事件for(i=0; i<100; i++){printk("i=%d\n",i);}}// 定义中断处理函数
irqreturn_t key_handler(int irq, void *dev)
{int witch = (int)dev;switch (witch){case 0:printk("KEY1_INTERRUPT\n");break;case 1:printk("KEY2_INTERRUPT\n");break;case 2:printk("KEY3_INTERRUPT\n");break;}//开启底半部tasklet_schedule(&tasklet);return IRQ_HANDLED;
}static int __init mycdev_init(void)
{// 1解析按键的设备树节点dnode = of_find_compatible_node(NULL, NULL, "myirq");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");// 2解析按键的软中断号for (i = 0; i < 3; i++){irqno[i] = irq_of_parse_and_map(dnode, i);if (!irqno[i]){printk("解析按键%d软中断号失败\n", i);return -ENXIO;}printk("解析按键%d软中断号成功%d\n", i, irqno[i]);// 3注册按键1中断int ret = request_irq(irqno[i], key_handler, IRQF_TRIGGER_FALLING, "key_int", (void *)i);if (ret < 0){printk("注册按键%d中断失败\n", i);return ret;}}printk("注册按键中断成功\n");//初始化底半部tasklet_setup(&tasklet,key_callback);return 0;
}
static void __exit mycdev_exit(void)
{// 注销中断int i;for (i = 0; i < 3; i++){free_irq(irqno[i], (void *)i);}
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

现象:

5)工作队列机制驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>struct device_node *dnode;
unsigned int irqno[3];
int i;
struct work_struct work;  //分配工作队列对象//定义底半部处理函数
void key_work(struct work_struct *t)
{int i;//耗时事件for(i=0; i<100; i++){printk("i=%d\n",i);}}// 定义中断处理函数
irqreturn_t key_handler(int irq, void *dev)
{int witch = (int)dev;switch (witch){case 0:printk("KEY1_INTERRUPT\n");break;case 1:printk("KEY2_INTERRUPT\n");break;case 2:printk("KEY3_INTERRUPT\n");break;}//开启底半部schedule_work(&work);return IRQ_HANDLED;
}static int __init mycdev_init(void)
{// 1解析按键的设备树节点dnode = of_find_compatible_node(NULL, NULL, "myirq");if (dnode == NULL){printk("解析设备树节点失败\n");return -ENXIO;}printk("解析设备树节点成功\n");// 2解析按键的软中断号for (i = 0; i < 3; i++){irqno[i] = irq_of_parse_and_map(dnode, i);if (!irqno[i]){printk("解析按键%d软中断号失败\n", i);return -ENXIO;}printk("解析按键%d软中断号成功%d\n", i, irqno[i]);// 3注册按键1中断int ret = request_irq(irqno[i], key_handler, IRQF_TRIGGER_FALLING, "key_int", (void *)i);if (ret < 0){printk("注册按键%d中断失败\n", i);return ret;}}printk("注册按键中断成功\n");//初始化队列项INIT_WORK(&work,key_work);return 0;
}
static void __exit mycdev_exit(void)
{// 注销中断int i;for (i = 0; i < 3; i++){free_irq(irqno[i], (void *)i);}
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

现象:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/116120.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mall电商项目(学习记录1)

1.简介 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现,采用Docker容器化部署。前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。后台管理系统包含商品管理、订单管…

OpenGL之相机

OpenGL本身没有摄像机(Camera)的概念&#xff0c;但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机&#xff0c;产生一种我们在移动的感觉&#xff0c;而不是场景在移动。 本节我们将会讨论如何在OpenGL中配置一个摄像机&#xff0c;并且将会讨论FPS风格的…

laravel框架 - 消息队列如何使用

业务场景&#xff1a;项目里边有很多视频资源需要上传到抖音资源库&#xff0c;通过队列一条一条上传。 参考实例&#xff1a;发送邮件&#xff0c;仅供参考 (1)创建任务【生成任务类】 在你的应用程序中&#xff0c;队列的任务类都默认放在 app/Jobs 目录下。如果这个目录不存…

如何自动获取短信验证码?

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 这篇文章通过解决实际项目开发中遇到的如何自动获取短信验证码的问题&#xff0c;进一步讲述在Java中如何使用正则。 Java中如何使用正则 Java中正则相关类位于java.util.r…

精心制作的小游戏,没有人玩,失落......

引言 昨天有粉丝问我&#xff1a;大佬你好,前阵子我做了一款微信小游戏并且成功的上线了,但是发现并没有人玩,每天零零散散的几个人,有点失落,我觉得自己做的游戏还是挺好玩的,有没有什么办法可以让更多的人能够玩我的小游戏呢? 在粉丝的问题中&#xff0c;笔者仿佛看到了曾…

10路LED驱动器和GPIO控制器禾润HTR3310

供电范围&#xff1a;2.5V~5.5V 10个多功能IO&#xff0c;支持LED驱动或GPIO&#xff08;电流源调光&#xff09; LED模式下具有256阶线性调光 任意IO可配置为独立的输入或输出 中断功能&#xff0c;8μs防抖&#xff0c;低电平有效 标准I2C接口&#xff0c;4个I2C器件地址…

栈和队列1——栈的实现及其oj(括号匹配问题)

一&#xff0c;栈的概念 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#xf…

Otter改造 增加springboot模块和HTTP调用功能

环境搭建 & 打包 环境搭建&#xff1a; 进入 $otter_home/lib 目录执行&#xff1a;bash install.sh 打包&#xff1a; 进入$otter_home目录执行&#xff1a;mvn clean install -Dmaven.test.skip -Denvrelease发布包位置&#xff1a;$otter_home/target 项目背景 阿里…

C# OpenCvSharp 图片模糊检测(拉普拉斯算子)

效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyl…

Python —— pytest框架

1、认识pytest框架 1、搭建自动化框架的思路与流程 1、搭建自动化测试框架的思路和流程&#xff0c;任意测试手段流程都是一致的&#xff1a;手工测试、自动化测试、工具测试 手工测试&#xff1a;熟悉业务 —— 写用例 —— 执行用例并记录结果 —— 生成测试报告自动化测试…

stack与queue的简单封装

前言&#xff1a; stack与queue即栈和队列&#xff0c;先进后出/先进先出的特性我们早已了然于心&#xff0c; 在学习数据结构时&#xff0c;我们利用c语言实现栈与队列&#xff0c;从结构体写起&#xff0c;利用数组或指针表示他们的数据成员&#xff0c;之后再一个个实现他们…

Mycat与ShardingSphere如何选择(未完待续)

区别 MycatSharding-JDBCSharding-ProxySharding-Sidecar官方网站官方网站官方网站官方网站官方网站源码地址GitHubGitHubGitHubGitHub官方文档Mycat 权威指南官方文档官方文档官方文档开发语言JavaJavaJavaJava开源协议GPL-2.0/GPL-3.0Apache-2.0Apache-2.0Apache-2.0数据库M…