Linux 驱动 中断(二)

news2024/9/24 3:24:39

中断下半部

在 Linux 内核中,中断下半部(也称为中断下半场)是指在中断服务程序(Top Half)执行完毕后,在上下文之外延迟执行的一些操作。中断下半部通常用于处理那些不适合在中断上下文中立即执行的任务,以保持中断服务程序的快速响应。

中断下半部可以通过以下几种机制来实现:

1、Tasklet,一种内核机制,用于在延迟上下文中执行轻量级的任务。Tasklet 通常在中断服务程序的上下文中调度,并在延迟上下文中执行。是在禁止所有中断的情况下进行的,因此它们可以安全地访问共享的数据结构和资源。

2、工作队列(Workqueue),工作队列是一种内核机制,用于在延迟上下文中异步执行较为耗时的任务。工作队列可以在系统的后台执行,并且可以并发执行多个任务。是由内核线程来完成的,因此可以执行任意复杂度的操作,并且不会阻塞其他内核活动。

3、软中断(SoftIRQ),软中断是一种内核机制,用于在延迟上下文中执行一些较为复杂或耗时的任务。软中断是在内核中断上下文之外的一种执行机制。

代码实现:

1、Tasklet

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

tasklet_init 是 Linux 内核中用于初始化 Tasklet 结构体的函数。

  • t 是要初始化的 Tasklet 结构体指针。
  • func 是 Tasklet 的处理函数,即中断下半部的处理逻辑。
  • data 是传递给处理函数的参数。

static inline void tasklet_schedule(struct tasklet_struct *t)

tasklet_schedule 是 Linux 内核中用于调度 Tasklet 来执行任务的函数,在中断处理触发后合适的位置执行;

  • t 是要调度执行的 Tasklet 结构体指针。
void tasklet_kill(struct tasklet_struct *t);

tasklet_kill 是 Linux 内核中用于终止 Tasklet 的函数。

举个例子:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>

#include <linux/interrupt.h>


#define GPIO_BUTTON_PIN 40

static unsigned int irq_num;

struct tasklet_struct key_drv_tasklet;

static void key_drv_tasklet_handler(unsigned long data) {

	printk("Tasklet executed in delayed context\n");
}


// 中断处理函数
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{
    int value = gpio_get_value(GPIO_BUTTON_PIN);

	if (!value) {
		printk("====> key press\n");
	} else {
		printk("====> key up\n");
	}

	tasklet_schedule(&key_drv_tasklet);

    return IRQ_HANDLED;
}


static int __init key_drv_init(void) {

	int ret;

	// 获取中断号
	// 请求 GPIO 引脚
	ret = gpio_request(GPIO_BUTTON_PIN, "button_gpio");
	if (ret) {
		printk(KERN_ERR "Failed to request GPIO pin\n");
		return ret;
	}

	// 设置 GPIO 引脚方向为输入
	ret = gpio_direction_input(GPIO_BUTTON_PIN);
	if (ret) {
		printk(KERN_ERR "Failed to set GPIO pin direction\n");
		gpio_free(GPIO_BUTTON_PIN);
		return ret;
	}

	// 将 GPIO 映射到 IRQ
	irq_num = gpio_to_irq(GPIO_BUTTON_PIN);
	if (irq_num < 0) {
		printk(KERN_ERR "Failed to map GPIO to IRQ\n");
		gpio_free(GPIO_BUTTON_PIN);
		return irq_num;
	}

	tasklet_init(&key_drv_tasklet, key_drv_tasklet_handler, 0);

	// 请求中断
	ret = request_irq(irq_num, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq", NULL);
	if (ret) {
        printk(KERN_ERR "Failed to register IRQ handler\n");
        gpio_free(GPIO_BUTTON_PIN);
        return ret;
    }
	
	return 0;
}

static void __exit key_drv_exit(void) {

	free_irq(irq_num, NULL);

	tasklet_kill(&key_drv_tasklet);

	gpio_free(GPIO_BUTTON_PIN);
}

module_init(key_drv_init);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("dengcaixiang");
MODULE_DESCRIPTION("Simple key driver");

执行结果:

2、工作队列

INIT_WORK(work, func)

INIT_WORK 是 Linux 内核中用于初始化工作队列中的工作项的宏

  • work 是要初始化的 struct work_struct 结构体指针。
  • func 是要与工作项关联的处理函数的函数指针。
static inline bool schedule_work(struct work_struct *work)

schedule_work 用于将一个工作项(struct work_struct)添加到工作队列中以延迟执行。

  • work:指向要添加到工作队列中的工作项的指针,类型为 struct work_struct *。该工作项必须是预先初始化的,并且在调用 schedule_work() 函数之后,内核将负责安排该工作项的执行。

举个例子:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>

#include <linux/workqueue.h>
#include <linux/interrupt.h>


#define GPIO_BUTTON_PIN 40

static unsigned int irq_num;

static struct work_struct key_drv_workqueue;


static void key_drv_work_handler(struct work_struct *work) {

	printk("Workqueue executed in process context\n");
}


// 中断处理函数
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{
    int value = gpio_get_value(GPIO_BUTTON_PIN);

	if (!value) {
		printk("====> key press\n");
	} else {
		printk("====> key up\n");
	}

	schedule_work(&key_drv_workqueue);

    return IRQ_HANDLED;
}


static int __init key_drv_init(void) {

	int ret;

	// 获取中断号
	// 请求 GPIO 引脚
	ret = gpio_request(GPIO_BUTTON_PIN, "button_gpio");
	if (ret) {
		printk(KERN_ERR "Failed to request GPIO pin\n");
		return ret;
	}

	// 设置 GPIO 引脚方向为输入
	ret = gpio_direction_input(GPIO_BUTTON_PIN);
	if (ret) {
		printk(KERN_ERR "Failed to set GPIO pin direction\n");
		gpio_free(GPIO_BUTTON_PIN);
		return ret;
	}

	// 将 GPIO 映射到 IRQ
	irq_num = gpio_to_irq(GPIO_BUTTON_PIN);
	if (irq_num < 0) {
		printk(KERN_ERR "Failed to map GPIO to IRQ\n");
		gpio_free(GPIO_BUTTON_PIN);
		return irq_num;
	}

	INIT_WORK(&key_drv_workqueue, key_drv_work_handler);

	// 请求中断
	ret = request_irq(irq_num, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq", NULL);
	if (ret) {
        printk(KERN_ERR "Failed to register IRQ handler\n");
        gpio_free(GPIO_BUTTON_PIN);
        return ret;
    }
	
	return 0;
}

static void __exit key_drv_exit(void) {

	free_irq(irq_num, NULL);

	gpio_free(GPIO_BUTTON_PIN);
}

module_init(key_drv_init);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("dengcaixiang");
MODULE_DESCRIPTION("Simple key driver");

执行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv5创新改进:SPPF创新涨点篇 | SPPELAN:SPP创新结合ELAN ,效果优于SPP、SPPF| YOLOv9

💡💡💡本文独家改进:新颖SPPF创新涨点改进,SPP创新结合ELAN,来自于YOLOv9,助力YOLOv5,将SPPELAN代替原始的SPPF 💡💡💡在多个私有数据集和公开数据集VisDrone2019、PASCAL VOC实现涨点 收录 YOLOv5原创自研 https://blog.csdn.net/m0_63774211/category_12…

Java多线程导入Excel示例

在导入Excel的时候&#xff0c;如果文件比较大&#xff0c;行数很多&#xff0c;一行行读往往速度比较慢&#xff0c;为了加快导入速度&#xff0c;我们可以采用多线程的方式 话不多说直接上代码 首先是Controller import com.sakura.base.service.ExcelService; import com.s…

URI is not registered (Settings | Languages Frameworks | Schemas and DTDs)

在我们实际编码&#xff0c;配置xml文件时&#xff0c;会出现如下的问题 因此应该从File->Settings-> 这样在xml中就显示正常了

SpringMVC--03--前端传数组给后台

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 案例1乘客个人信息方法1&#xff1a;表单提交&#xff0c;以字段数组接收方法2&#xff1a;表单提交&#xff0c;以BeanListModel接收方法3&#xff1a;将Json对象序…

S2---FPGA-A7板级原理图硬件实战

视频链接 FPGA-A7板级系统硬件实战01_哔哩哔哩_bilibili FPGA-A7板级原理图硬件实战 基于XC7A100TFGG484的FPGA硬件设计流程图 A7核心板&#xff0c;是基于XILINX公司的ARTIX-7系列100T的XC7A100T,2FGG484I这款芯片开发的高性能核心板&#xff0c;具有高速&#xff0c;高带宽&a…

B084-SpringCloud-Zuul Config

目录 zuul系统架构和zuul的作用zuul网关实现配置映射路径过滤器 Config概述云端管理本地配置 zuul zuul是分布式和集群后前端统一访问入口 系统架构和zuul的作用 zuul把自己注册进eureka&#xff0c;然后可通过前端传来的服务名发现和访问对应的服务集群 为了预防zuul单点故…

Raid5阵列数据恢复+Openmediavault配置内网与外网远程访问+服务器到服务器的大量文件转移备份

一、适用场景&#xff1a; 1、OpenMediaVault&#xff0c;是一个开源的&#xff08;免费&#xff09;基于Debian Linux的下一代网络附加存储(NAS)解决方案。 2、易于使用的 WEB 管理界面&#xff1a;OpenMediaVault 的用户界面设计直观&#xff0c;即使是没有 Linux 经验的用户…

FPGA-AXI4接口协议概述

假设我们要传一帧1080P的图片到显示屏显示&#xff0c;那么需要多大的储存空间呢&#xff1f; 一帧1080P的RGB565图像数据需要1920*1080*1633.1776Mb 存储空间 下图是ZYNQ-7000系列中Block RAM的大小&#xff1a; 可以看到最大存储空间的BRAM都不能存储一帧图片&#xff0c;那…

#QT(智能家居界面-布局)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 水平布局&#xff0c;垂直布局&#xff0c;栅格布局&#xff08;弹簧&#xff09; 界面自动调整 3.记录 注意弹簧不是拖拽拉长&#xff0c;而是使用栅格布局 运行发现窗口放大缩小可以自动调整 如果想要重新布局&#xff0c;需…

【短时交通流量预测】基于双层BP神经网络

课题名称&#xff1a;基于双层BP神经网络的短时交通流量预测 版本时间&#xff1a;2023-04-27 代码获取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主获取 模型简介&#xff1a; 城市交通路网中交通路段上某时刻的交通流量与本路段前几个时段的交通流量有关&…

为什么各品牌主食冻干差价那么大?真正性价比高的主食冻干分享

随着科学养猫知识的普及&#xff0c;主食冻干喂养逐渐受到了许多铲屎官的青睐。然而&#xff0c;也有不少的铲屎官看到主食冻干的价格望而却步。实际上&#xff0c;像我这样的资深铲屎官早已开始主食冻干喂养。虽然主食冻干的价格相对于烘焙粮和膨化粮要高一些&#xff0c;但它…

es6 相关面试题

1 var, let ,const 区别&#xff1f; 2 手写将对象进行合并 手写合并对象 3 普通函数和箭头函数区别&#xff1f; 4 find 和 filter的区别&#xff1f; 5 some和every区别&#xff1f;

OCR 文字识别在未来会有哪些发展趋势?

随着技术的不断进步&#xff0c;OCR&#xff08;光学字符识别&#xff09;文字识别技术也在不断发展。未来&#xff0c;OCR 文字识别技术将会呈现以下几个发展趋势&#xff1a; 一、更高的识别准确率 OCR 技术的核心是识别准确率。随着深度学习等人工智能技术的发展&#xff0c…

测温线夹装置

测温线夹是一种用于测量温度的装置&#xff0c;通常用于电力系统中监测电气设备的温度。它可以安装在电气设备的导线上&#xff0c;通过感应导线的温度来测量电气设备的运行状态。测温线夹通常由金属材料制成&#xff0c;具有耐高温、耐腐蚀等特点&#xff0c;适用于各种恶劣的…

一文读懂Persistence One- 如何将Restaking带入Cosmos

Persistence One正在将Restaking引入Cosmos。用户将能够通过pSTAKE、Stride、Quicksilver和Milkyway将Liquid Staked Tokens&#xff08;如ATOM、TIA、DYDX等&#xff09;存入Persistence One&#xff0c;对其进行Restaking&#xff0c;从而安全地连接更多区块链&#xff0c;首…

苹果电脑专业的Mac垃圾清理工具CleanMyMac X4.14.7

CleanMyMac X是一款专业的Mac清理工具&#xff0c;它具有强大的功能和易用的界面&#xff0c;可以帮助用户快速清理Mac上的无用文件和垃圾&#xff0c;优化系统性能&#xff0c;提升电脑运行速度。 该软件的核心功能包括智能扫描与清理、应用程序管理、隐私保护和系统维护等。…

Python的http模块requests

模块简介&#xff1a; requests 库是一个 python中比较有名的 http请求的库&#xff0c;能处理 get,post,put,delete 等 restful请求&#xff0c;能设置 header&#xff0c;cookie,session 等操作&#xff0c;也是作为爬虫的基础库&#xff0c;它目前还不能异步请求,如果要支持…

Spring循环依赖:原因与解决方法

在Spring框架中&#xff0c;处理循环依赖一直备受关注。这是因为Spring团队在源代码中为了解决这个问题做了大量的处理和优化。同时&#xff0c;循环依赖也是Spring高级面试中的必考问题&#xff0c;对其深入了解可以成为面试中的制胜法宝。本文将详细介绍Spring循环依赖的产生…

【Datawhale组队学习:Sora原理与技术实战】Attention和LLM

Attention Attention 注意力&#xff0c;从两个不同的主体开始。 论文&#xff1a;https://arxiv.org/pdf/1703.03906.pdf seq2seq代码仓&#xff1a;https://github.com/google/seq2seq 计算方法&#xff1a; 加性Attention&#xff0c;如&#xff08;Bahdanau attention&…

备战蓝桥杯---图论应用1

目录 1.增加虚点建图&#xff1a; 2.抽象图的迪杰斯特拉&#xff1a; 3.用bitset优化弗洛伊德&#xff1a; 4.有向图的Prim/kruskal&#xff1a; 1.增加虚点建图&#xff1a; 我们当然可以每一层与上一层的点再连上一条边&#xff0c;但这样子边太多了超内存&#xff0c;我们…