linux驱动学习(九)之中断

news2025/2/26 1:24:58

一、中断的实现

对于中断的请求,在linux内核中,有一套标准的接口函数,可以实现中断的响应和处理。

#include <linux/interrupt.h>

//1 申请中断
static inline int __must_check request_irq(unsigned int irq, 
										irq_handler_t handler, 
										unsigned long flags, 
										const char *name, 
										void *dev)

1)unsigned int irq  ---->中断号,每个中断源有一个唯一中断号
2)irq_handler_t handler  --->中断请求发生后,被调用的中断服务函数 typedef irqreturn_t (*irq_handler_t)(int, void *); 

/**
 * enum irqreturn
 * @IRQ_NONE		interrupt was not from this device  中断发生异常时
 * @IRQ_HANDLED		interrupt was handled by this device 正常返回
 * @IRQ_WAKE_THREAD	handler requests to wake the handler thread
 */
enum irqreturn {
	IRQ_NONE		= (0 << 0),
	IRQ_HANDLED		= (1 << 0),
	IRQ_WAKE_THREAD		= (1 << 1),
};

typedef enum irqreturn irqreturn_t;

3)unsigned long flags ---->中断的标志----->中断触发方式
4) const char *name --->中断的名称,是由用户自定义
5)void *dev ---->向中断服务程序传递的参数 

返回值:
   成功:0
   失败:返回负数的错误码

查看开发板linux系统中的中断:

[root@GEC6818 /proc]#cat interrupts 

	   CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       
 33:          0          0          0          0          0          0          0          0       GIC  pl08xdmac
 34:          0          0          0          0          0          0          0          0       GIC  pl08xdmac
 37:          0          0          0          0          0          0          0          0       GIC  rtc 1hz
 39:         18         14         13         10         22         14         14         29       GIC  nxp-uart
 48:          0          0          0          1          0          0          0          0       GIC  s3c2440-i2c.1
 49:       3197        153       3935       3803       3735       3151       3387       3896       GIC  s3c2440-i2c.2
 56:      22946      15098      13068      14422      15060      15512      15454      18817       GIC  Event Timer IRQ
 63:          0          0          0          0          0          0          0          0       GIC  nxp-wdt
 65:       1402        876        712        851        786        901        919        982       GIC  nxp-disp
 66:          0          0          0          0          0          0          0          0       GIC  nxp-disp
 68:          0          0          1          0          0          0          0          0       GIC  hdmi-int
 中断号       中断被处理的次数                                                                    中断控制器   中断名称

在linux内核中,如果中断号被使用或者被其他申请了,再申请就会出错:

[root@GEC6818 /6818_driver]#insmod led_drv.ko 
[ 1022.779000] gec6818_interrupt_init
[ 1022.779000] ------------[ cut here ]------------
[ 1022.782000] WARNING: at kernel/irq/manage.c:1370 request_threaded_irq+0x114/0x13c()
[ 1022.789000] Modules linked in: led_drv(O+)
[ 1022.793000] [<c001517c>] (unwind_backtrace+0x0/0x134) from [<c0044880>] (warn_slowpath_common+0x54/0x64)
[ 1022.803000] [<c0044880>] (warn_slowpath_common+0x54/0x64) from [<c004492c>] (warn_slowpath_null+0x1c/0x24)
[ 1022.813000] [<c004492c>] (warn_slowpath_null+0x1c/0x24) from [<c00b8fd8>] (request_threaded_irq+0x114/0x13c)
[ 1022.822000] [<c00b8fd8>] (request_threaded_irq+0x114/0x13c) from [<bf00203c>] (gec6818_interrupt_init+0x3c/0x50 [led_drv])
[ 1022.833000] [<bf00203c>] (gec6818_interrupt_init+0x3c/0x50 [led_drv]) from [<c0008710>] (do_one_initcall+0x11c/0x174)
[ 1022.844000] [<c0008710>] (do_one_initcall+0x11c/0x174) from [<c0097dc0>] (sys_init_module+0xaa4/0x1e14)
[ 1022.853000] [<c0097dc0>] (sys_init_module+0xaa4/0x1e14) from [<c000ec40>] (ret_fast_syscall+0x0/0x30)
[ 1022.863000] ---[ end trace d4f7d5ddfdae4527 ]---
insmod: can't insert 'led_drv.ko': invalid parameter  ---->不合法参数,request_irq的参数不对

成功输出:

[root@GEC6818 /6818_driver]#insmod led_drv.ko 
[ 2711.551000] gec6818_interrupt_init
[root@GEC6818 /6818_driver]#lsmod
led_drv 977 0 - Live 0xbf008000 (O)
[root@GEC6818 /6818_driver]#cat /proc/interrupts 
134:          0          0          0          0          0          0          0          0      GPIO  my_interrupt
134 --->中断号 IRQ_GPIO_A_START + 28 --->106 + 28 --->134
//2 释放中断
void free_irq(unsigned int, void *)
参数说明:
	unsigned int ---->要释放的中断的中断号
	void * ----> 中断服务程序的参数

二、中断号

unsigned int irq

中断号是跟中断源有关,每一个中断源有一个唯一中断号,中断源由外部与内部,中断源是跟硬件有关,每一个处理器平台,中断源不一样的。

1、硬件平台的中断源的定义

kernel\arch\arm\mach-s5p6818\include\mach\s5p6818_irq.h
/*
* Physical Interrupt Number 64 (0~63)
*/
#define IRQ_PHY_UART1					(6	+ 32) // pl01115_Uart_modem
#define IRQ_PHY_UART0					(7	+ 32) // UART0_MODULE
#define IRQ_PHY_UART2					(8	+ 32) // UART1_MODULE
#define IRQ_PHY_UART3					(9	+ 32) // pl01115_Uart_nodma0
#define IRQ_PHY_UART4					(10 + 32)	// pl01115_Uart_nodma1
#define IRQ_PHY_UART5					(11 + 32)	// pl01115_Uart_nodma2

/*
 * GPIO Interrupt Number 160 (106~265)
 */
#define IRQ_GPIO_START			IRQ_PHY_MAX_COUNT
#define IRQ_GPIO_END			(IRQ_GPIO_START + 32 * 5)	// Group: A,B,C,D,E

#define IRQ_GPIO_A_START		(IRQ_GPIO_START + PAD_GPIO_A)
#define IRQ_GPIO_B_START		(IRQ_GPIO_START + PAD_GPIO_B)
#define IRQ_GPIO_C_START		(IRQ_GPIO_START + PAD_GPIO_C)
#define IRQ_GPIO_D_START		(IRQ_GPIO_START + PAD_GPIO_D)
#define IRQ_GPIO_E_START		(IRQ_GPIO_START + PAD_GPIO_E)	

关于中断号与GPIO:   KEY2->GPIOA28 
 按键       中断号                     GPIO口号        GPIO口
KEY2    IRQ_GPIO_A_START+28         PAD_GPIO_A+28   GPIOA28

头文件:#include <cfg_type.h>

三、中断标志

unsigned long flags

注意:中断一旦安装成功(request_irq),默认是打开的

中断标志分为:外部中断和内部中断


1、外部中断标志

#define IRQF_TRIGGER_NONE        0x00000000
#define IRQF_TRIGGER_RISING      0x00000001
#define IRQF_TRIGGER_FALLING     0x00000002
#define IRQF_TRIGGER_HIGH        0x00000004
#define IRQF_TRIGGER_LOW         0x00000008

双边沿触发:IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING    

2、内核内部中断

#define IRQF_DISABLED	0x00000020   //当响应当前中断的时候,关闭其他的中断
#define IRQF_SHARED		0x00000080  	 //当一个中断源,注册多次时,可以对应多个中断服务程序
#define IRQF_TIMER		(__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)  //当注册定时器中断时,使用该标志

四、中断服务程序

irq_handler_t handler
typedef irqreturn_t (*irq_handler_t)(int, void *);

通常情况下,一个中断源对应一个中断服务程序(中断处理函数),也可以多个中断源对应一个中断服务程序。

irqreturn_t key_irq_handler(int irq,void* dev)
{
  
}

1 根据中断号来区分中断处理
2 通过中断请求传递的参数来区分中断处理
头文件:#include <linux/interrupt.h>

注意:对于嵌入式系统中,中断服务程序是一个原子操作,所谓的原子操作就是该过程被执行时,不能被打断。 在中断服务服务程序中,不能有阻塞的操作,如睡眠,copy_to_user,copy_from_user,锁等。

在linux内核中,使用睡眠函数要包含头文件:

#include <linux/delay.h>
static inline void ssleep(unsigned int seconds)  ---->秒级睡眠
void msleep(unsigned int msecs); ----->毫秒

五、中断与等待队列(wait_queue)

 1、等待队列

设置一个等待条件,如果条件满足,则进程继续往下执行;如果条件不满足,则进程就进入等待队列中。当条件满足时,中断会唤醒等待队列中的进程,进程再继续往下执行。等待队列也是一种同步方法。

2、等待队列的相关API接口函数

#include <linux/wait.h>
#include <linux/sched.h>

//等待队列结构体:
typedef struct __wait_queue wait_queue_t;
struct __wait_queue 
{
	unsigned int flags;  //条件变量的标志
	#define WQ_FLAG_EXCLUSIVE	0x01
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};

1)定义一个等待队列 和等待的条件
static wait_queue_t gec6818_wait;
static in key_press_flag = 0;

2)初始化等待队列
#define init_wait(wait)							\
	do {								\
	(wait)->private = current;				\
	(wait)->func = autoremove_wake_function;		\
	INIT_LIST_HEAD(&(wait)->task_list);			\
	(wait)->flags = 0;					\
} while (0)
static inline void INIT_LIST_HEAD(struct list_head *list)

由此可得:
void init_wait(wait_queue_t* wait);
如 init_wait(&gec6818_wait);

#define init_waitqueue_head(q)				\
	do {						\
	static struct lock_class_key __key;	\
	\
	__init_waitqueue_head((q), #q, &__key);	\
} while (0)

得到原型:void init_waitqueue_head(wait_queue_head_t*);

struct __wait_queue_head 
{
    spinlock_t lock;
    struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
比如:wait_queue_head_t gec6818_wq_head;

3)进入等待队列
#define wait_event_interruptible(wq, condition)				\
	({									\
	int __ret = 0;							\
	if (!(condition))						\
	__wait_event_interruptible(wq, condition, __ret);	\
	__ret;								\
})
struct __wait_queue_head {
	spinlock_t lock;
	struct list_head task_list;
};

typedef struct __wait_queue_head wait_queue_head_t;
void wait_event_interruptible(wait_queue_head_t wait,int condition)

4)唤醒队列
#define wake_up(x)			__wake_up(x, TASK_NORMAL, 1, NULL)

void wake_up(wait_queue_head_t* head)

觉得有帮助的话,打赏一下呗。。

           

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

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

相关文章

vue自定义一个回到顶部组件

1.首先创建一个backTop.vue页面&#xff1a; 页面有两个按钮&#xff0c;一个回到顶部按钮&#xff0c;一个刷新按钮(showRefresh:false将刷新按钮隐藏)&#xff0c;实现效果如下&#xff1a; 代码解析&#xff1a; domName:需要监听滚动的dom类名&#xff0c;不传默认监听bod…

windows下open webui+ollama+sd webui

原文&#xff1a;https://wangguo.site/Blog/2024/Q2/2024-06-14/ 说明&#xff1a;安装使用环境是在Windows下 1、给ollama一个好看的交互界面&#xff08;open webui&#xff09; 1.1、ollama安装 安装&#xff1a;在ollama官网下载windows版本进行安装 模型列表&#xff1…

ChatGPT等大模型可以代替搜索引擎吗?

在知乎看到一个问题&#xff0c;回答了一下&#xff0c;分享到这里。 把ChatGPT当作搜索引擎可靠性差点&#xff0c;但是可行。 代替搜索引擎 1、写代码 我们可以让GPT写一段算法代码或者使用某个语言API的示例&#xff0c;然后只需要把这段代码粘贴到IDE中&#xff0c;简单…

Linux编辑器 vim使用 (解决普通用户无法进行sudo提权问题)

文章目录 一.vim是什么命令模式底行模式 二.关于vim暂停问题三.注释批量化注释批量化去注释 四.解决普通用户无法进行sudo提权问题五.vim的配置 一.vim是什么 用过VS的都知道&#xff0c;拥有着编辑器编译器调试.编写C&#xff0c;C&#xff0c;python等的功能。就是集成 Linu…

Git 基础操作(一)

Git 基础操作 配置Git 安装完Git后&#xff0c;首先要做的事情是设置你的 用户名 和 e-mail 地址。这样在你向仓库提交代码的时候&#xff0c;就知道是谁提交的&#xff0c;以及提交人的联系方式。 配置用户名和邮箱 使用git config [--global] user.name "你的名字&qu…

网络爬虫概述

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 网络爬虫&#xff08;又被称为网络蜘蛛、网络机器人&#xff0c;在某社区中经常被称为网页追逐者&#xff09;&#xff0c;可以按照指定的规则&#…

神经网络-万能近似定理的探索

神经网络-万能近似定理的探索 对于这个实验博主想说&#xff0c;其实真的很有必要去好好做一下&#xff0c;很重要的一个实验。 1.理论介绍 万能近似定理: ⼀个前馈神经⽹络如果具有线性层和⾄少⼀层具有 “挤压” 性质的激活函数&#xff08;如 sigmoid 等&#xff09;&…

基于Matlab的细胞计数图像处理系统(GUI界面有报告) 【含Matlab源码 MX_003期】

简介&#xff1a; 本文旨在解决生物血细胞数目统计的挑战&#xff0c;提出了基于图像处理的综合方案。通过MATLAB平台&#xff0c;我们设计并实现了一套完整的细胞图像处理与分析流程。在预处理阶段&#xff0c;采用图像增强和阈值分割等方法&#xff0c;有效地提高了细胞图像的…

Swift开发——输出格式化字符

Swift语言是开发iOS和macOS等Apple计算机和移动设备系统应用程序的官方语言。Swift语言是一种类型安全的语言,语法优美自然,其程序从main.swift文件开始执行,程序代码按先后顺序执行,同一个工程的程序文件中的类和函数直接被main.swift文件调用,除了main.swift文件外,工程…

【数据挖掘-思考】分类和聚类

将芝麻和花生分开&#xff0c;是一个分类问题还是聚类问题? 显而易见的&#xff0c;在日常生活中&#xff0c;这是一个分类问题&#xff0c;在数据挖掘领域中&#xff0c;是否也是这样呢&#xff1f; 通义千问的回答&#xff1a; 在数据挖掘中&#xff0c;将芝麻和花生分开可以…

【C语言】14. qsort 的底层与模拟实现

一、回调函数 回调函数就是⼀个通过函数指针调用的函数。 把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用&#xff0c;而是…

思维+暴力,CF992D - Nastya and a Game

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 992D - Nastya and a Game 二、解题报告 1、思路分析 这个题题目很吓人 因为看起来前缀和根本存不下&#xff0c;似乎没法算 这也提示我们似乎只需在小范围内枚举求解即可 题目的P / K SUM也保证了我们…

SQL中的UPDATE语句:别让你的数据“离家出走”

sql的update操作正式环境用的很少&#xff0c;但是在测试环境还是用的挺多的。 想象一下&#xff0c;你正在管理一个学校的数据库&#xff0c;其中有一个students表&#xff0c;记录着每个学生的信息。有一天&#xff0c;你接到通知说某个学生的年龄或成绩需要更新。这时&…

54.Python-web框架-Django-免费模板django-datta-able

1.Datta Able Django介绍 Detta Able Djiango是什么 Datta Able Django 是一个由AppSeed提供的开源Django管理面板&#xff0c;基于现代设计&#xff0c;为开发者提供了一流的功能和优雅的界面。它源自CodedThemes的高风格化Bootstrap 4模板——Datta Able Bootstrap Lite&…

云电脑有多好用?适合哪些人使用?

云电脑作为一种新型的计算模式&#xff0c;其应用场景广泛且多样&#xff0c;适合各类人群使用。云电脑适合什么人群使用&#xff1f;云电脑有哪些应用场景&#xff1f;有什么好的云电脑推荐&#xff1f;以下本文将详细探讨云电脑的主要应用场景及其适用人群的相关内容&#xf…

【YOLOv5/v7改进系列】改进池化层为RT-DETR的AIFI

一、导言 Real-Time DEtection TRansformer&#xff08;RT-DETR&#xff09;&#xff0c;是一种实时端到端目标检测器&#xff0c;克服了Non-Maximum Suppression&#xff08;NMS&#xff09;对速度和准确性的影响。通过设计高效的混合编码器和不确定性最小化查询选择&#xf…

缩窄route范围来提速本地打包的尝试

目录 为什么要缩窄route范围缩窄route的方式意外触发的重复构建重复构建的原因解决方案 为什么要缩窄route范围 对于一些大单页&#xff0c;单个router-view中可能包含上百个页面。但是开发的时候其实并不需要那么多调试那么多页面。 因此&#xff0c;为了节省不必要的打包和热…

【SpringBoot + Vue 尚庭公寓实战】地区信息管理接口实现(九)

【SpringBoot Vue 尚庭公寓实战】地区信息管理接口实现&#xff08;九&#xff09; 文章目录 【SpringBoot Vue 尚庭公寓实战】地区信息管理接口实现&#xff08;九&#xff09;1、业务说明2、数据逻辑模型3、接口实现3.1、查询省份信息列表3.2、根据省份ID查询城市信息列表3…

Python对象序列化库之dill使用详解

概要 在 Python 编程中,序列化(Serialization)和反序列化(Deserialization)是处理对象持久化和数据传输的常见任务。Python 提供了内置的 pickle 模块用于对象序列化,但它在处理复杂对象(如带有 lambda 函数、生成器和闭包的对象)时存在一定局限性。dill 库是 pickle …

本地运行大语言模型(LLMs)

用例 像PrivateGPT、llama.cpp、Ollama、GPT4All、llamafile 等项目的流行度凸显了本地&#xff08;在您自己的设备上&#xff09;运行大型语言模型&#xff08;LLMs&#xff09;的需求。 这至少有两个重要的好处&#xff1a; 1.隐私&#xff1a;您的数据不会发送给第三方&a…