linux驱动学习3-外部中断

news2024/10/6 8:33:27

在做中断试验时,发现中断驱动总是insmod失败,之后定位到 gpio_request 失败,之后是想到使用的野火做好的系统,在uEnv.txt中会加载大量设备树插件,将key相关的设备树插件屏蔽即可。

linux中断API函数

中断号

每个中断都有一个中断号,通过中断号即可区分不同的中断,在 Linux 内核中使用一个 int 变量表示中断号

request_irq函数

在 Linux 内核中要想使用某个中断是需要申请的, request_irq 函数用于申请中断, request_irq函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。 request_irq 函数会激活(使能)中断,所以不需要我们手动去使能中断, request_irq 函数原型如下:

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

irq:要申请中断的中断号。
handler:中断处理函数,当中断发生以后就会执行此中断处理函数。
flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志,这些标志可以通过“|”来实现多种组合。
在这里插入图片描述
name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。
dev: 如果将 flags 设置为 IRQF_SHARED 的话, dev 用来区分不同的中断,一般情况下将dev 设置为设备结构体, dev 会传递给中断处理函数 irq_handler_t 的第二个参数。

free_irq函数

使用中断的时候需要通过 request_irq 函数申请,使用完成以后就要通过 free_irq 函数释放掉相应的中断。

void free_irq(unsigned int irq,void *dev)

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

中断处理函数

使用 request_irq 函数申请中断的时候需要设置中断处理函数,中断处理函数格式如下所示:

irqreturn_t (*irq_handler_t) (int, void *)

第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向 void 的指针,也就是个通用指针,需要与 request_irq 函数的 dev 参数保持一致。用于区分共享中断的不同设备,dev 也可以指向设备数据结构。中断处理函数的返回值为 irqreturn_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 是个枚举类型,一共有三种返回值。一般中断服务函数返回值使用如下形式:

return IRQ_RETVAL(IRQ_HANDLED)

中断使能和禁止函数

void enable_irq(unsigned int irq)
void disable_irq(unsigned int irq)

disable_irq函数要等到当前正在执行的中断处理函数执行完才返回,因此使用者需要保证不会产生新的中断,并且确保所有已经开始执行的中断处理程序已经全部退出。在这种情况下,可以使用另外一个中断禁止函数:

void disable_irq_nosync(unsigned int irq)

关闭全局中断可以使用如下函数:

local_irq_save(flags)   //禁止中断
local_irq_restore(flags)  //恢复中断

上半部与下半部

上半部:上半部就是中断处理函数,那些处理过程比较快,不会占用很长时间的处理就可以放在上半部完成
下半部:如果中断处理过程比较耗时,那么就将这些比较耗时的代码提出来,交给下半部去执行,这样中断处理函数就会快进快出。

tasklet

tasklet 是利用软中断来实现的另外一种下半部机制,在软中断和 tasklet 之间,建议大家使用 tasklet。 Linux 内核使用 tasklet_struct 结构体来表示 tasklet:

struct tasklet_struct
{
struct tasklet_struct *next; /* 下一个 tasklet */
unsigned long state; /* tasklet 状态 */
atomic_t count; /* 计数器,记录对 tasklet 的引用数 */
void (*func)(unsigned long); /* tasklet 执行的函数 */
unsigned long data; /* 函数 func 的参数 */
};
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long),unsigned long data);

t:要初始化的 tasklet
func: tasklet 的处理函数。
data: 要传递给 func 函数的参数
也 可 以 使 用 宏 DECLARE_TASKLET 来 一 次 性 完 成 tasklet 的 定 义 和 初 始 化 ,DECLARE_TASKLET 定义在 include/linux/interrupt.h 文件中,定义如下:

DECLARE_TASKLET(name, func, data)

其中 name 为要定义的 tasklet 名字,这个名字就是一个 tasklet_struct 类型的时候变量, func就是 tasklet 的处理函数, data 是传递给 func 函数的参数。
在上半部,也就是中断处理函数中调用 tasklet_schedule 函数就能使 tasklet 在合适的时间运行, tasklet_schedule 函数原型如下:

void tasklet_schedule(struct tasklet_struct *t)

t:要调度的 tasklet,也就是 DECLARE_TASKLET 宏里面的 name。
关于 tasklet 的参考使用示例如下所示:

/* 定义 taselet */
struct tasklet_struct testtasklet;
/* tasklet 处理函数 */
void testtasklet_func(unsigned long data)
{
/* tasklet 具体处理内容 */
}
/* 中断处理函数 */
irqreturn_t test_handler(int irq, void *dev_id)
{
......
/* 调度 tasklet */
tasklet_schedule(&testtasklet);
......
}
/* 驱动入口函数 */
static int __init xxxx_init(void)
{
......
/* 初始化 tasklet */
tasklet_init(&testtasklet, testtasklet_func, data);
/* 注册中断处理函数 */
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev);
......
}

工作队列

工作队列是另外一种下半部执行方式,工作队列在进程上下文执行,工作队列将要推后的工作交给一个内核线程去执行,因为工作队列工作在进程上下文,因此工作队列允许睡眠或重新调度。因此如果你要推后的工作可以睡眠那么就可以选择工作队列,否则的话就只能选择软中断或 tasklet。
Linux 内核使用 work_struct 结构体表示一个工作,内容如下(省略掉条件编译):

struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func; /* 工作队列处理函数 */
};

简单创建工作很简单,直接定义一个 work_struct 结构体
变量即可,然后使用 INIT_WORK 宏来初始化工作, INIT_WORK 宏定义如下:

#define INIT_WORK(_work, _func)

_work 表示要初始化的工作, _func 是工作对应的处理函数。
也可以使用 DECLARE_WORK 宏一次性完成工作的创建和初始化,宏定义如下:

#define DECLARE_WORK(n, f)

n 表示定义的工作(work_struct), f 表示工作对应的处理函数。
和 tasklet 一样,工作也是需要调度才能运行的,工作的调度函数为 schedule_work,函数原型如下所示:

bool schedule_work(struct work_struct *work)

函数参数和返回值含义如下:
work: 要调度的工作。
返回值: 0 成功,其他值 失败。

/* 定义工作(work) */
struct work_struct testwork;
/* work 处理函数 */
void testwork_func_t(struct work_struct *work);
{
/* work 具体处理内容 */
}
/* 中断处理函数 */
irqreturn_t test_handler(int irq, void *dev_id)
{
......
/* 调度 work */
schedule_work(&testwork);
......
}
/* 驱动入口函数 */
static int __init xxxx_init(void)
{
......
/* 初始化 work */
INIT_WORK(&testwork, testwork_func_t);
/* 注册中断处理函数 */
request_irq(xxx_irq, test_handler, 0, "xxx", &xxx_dev);
......
}

设备树修改

设备树修改如下:

key{
    #address-cells = <1>;
		#size-cells = <1>;
		compatible = "fire,key";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_key>;
		key_gpio = <&gpio5 1 GPIO_ACTIVE_LOW>;
		interrupt-parent = <&gpio5>;
		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;  //1表示使用gpio5_io01
		status = "okay";
	};

IRQ_TYPE_EDGE_FALLING 定义在文件 include/linux/irq.h 中,定义如下:

enum {
IRQ_TYPE_NONE = 0x00000000,
IRQ_TYPE_EDGE_RISING = 0x00000001,
IRQ_TYPE_EDGE_FALLING = 0x00000002,
IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
IRQ_TYPE_LEVEL_HIGH = 0x00000004,
IRQ_TYPE_LEVEL_LOW = 0x00000008,
IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW |
IRQ_TYPE_LEVEL_HIGH),
......
}

获取中断号

编写驱动的时候需要用到中断号,我们用到中断号,中断信息已经写到了设备树里面,因此可以通过 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 对应的中断号。

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

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

相关文章

【管理运筹学】第 5 章 | 整数规划 (3,隐枚举法计算步骤)

文章目录 引言四、0-1 整数规划4.2 0-1 整数规划的解法4.2.1 0-1 规划模型标准型4.2.2 隐枚举法计算步骤 写在最后 引言 经过前文&#xff0c;了解以及体会到 0-1 变量的特性后&#xff0c;我们来研究该如何去求解这类特殊的 0-1 整数规划模型。 四、0-1 整数规划 4.2 0-1 整…

【Maven教程】(二)安装配置篇:手把手教你安装及配置Maven环境~

Maven安装配置篇 1️⃣ 在 Windows 上安装 Maven1.1 下载及安装 Maven1.2 升级 Maven 2️⃣ 在基于UNIX 的系统上安装 Maven2.1 下载和安装2.2 升级 Maven2.3 安装目录分析2.4 设置 HTTP 代理 3️⃣ 在 IDE中安装Maven插件 1️⃣ 在 Windows 上安装 Maven 在安装 Maven 之前&a…

【面试专题】Java核心基础篇②

&#x1f4c3;个人主页&#xff1a;个人主页 &#x1f525;系列专栏&#xff1a;Java面试专题 目录 1.接口和抽象类有什么区别&#xff1f; 2.两个对象的 hashCode() 相同&#xff0c;则 equals()也一定为 true&#xff0c;对吗&#xff1f; 3.说一说hashCode()和equals()的…

一般文章让你了解mybatis,以及如今在Java开发的地位!

一.了解mybatis&#xff01; A.什么是mybatis&#xff1f; MyBatis是一个开源的持久层框架&#xff0c;它简化了在Java应用程序中使用关系型数据库的开发工作。MyBatis提供了将SQL语句和Java代码进行解耦的能力&#xff0c;使得应用程序可以通过简单的配置来访问数据库&#x…

【AI视频教程】只需5步,AI作出鸡你太美视频

1.视频效果 黄昏见证虔诚的信徒 2.准备工作 制作视频效果&#xff0c;需要准备下面3个条件&#xff1a; 准备stable diffusion的环境剪辑一段【鸡你太美】原版视频stable diffusion安装sd-webui-IS-NET-pro插件 2.1部署stable diffusion环境 部署步骤参考制作ikun图片的文章…

软件开发中常用数据结构介绍:C语言队列

工作之余来写写C语言相关知识&#xff0c;以免忘记。今天就来聊聊C语言实现循环队列&#xff0c;我是分享人M哥&#xff0c;目前从事车载控制器的软件开发及测试工作。 学习过程中如有任何疑问&#xff0c;可底下评论&#xff01; 如果觉得文章内容在工作学习中有帮助到你&…

基于springboot+vue的考研资讯平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Python中Setup.py的作用是什么

Python中Setup.py的作用是什么 今天就跟大家聊聊有关Python中Setup.py的作用是什么&#xff0c;可能很多人都不太了解&#xff0c;为了让大家更加了解. 1. 为什么需要对项目分发打包? 平常我们习惯了使用 pip 来安装一些第三方模块&#xff0c;这个安装过程之所以简单&#…

高项4.项目管理核心技术.

第一部分 项目管理概论 价值驱动的项目管理知识体系: 十二项原则;生命周期四个阶段;五个过程组;十大PM知识领域;八大绩效域;外加价值交付系统; 自1987 年以来, PMBOK 一直是基于过程的项目管理标准的重要代表,项目管理从业者一 直坚持基于过程的项目管理方法。随着…

用python从零开始做一个最简单的小说爬虫带GUI界面(1/3)

目录 前言 三节博客内容概要 PyQt5的配置 设置软件的快捷启动方式 1. 用于设计界面的程序 2. 将Qt Designer设计出来的ui文件转化为py文件 3. 可以把py文件打包成可执行的exe文件 4. 将ico图片放在qrc文件中&#xff0c;再将qrc文件转换成py…

Axios跨域请求处理

问题背景&#xff1a; vue 项目用 axios 进行请求的时候&#xff0c;总是报“Access to XMLHttpRequest at ‘http://localhost:8889/api/login’ from origin ‘http://localhost:8080……’”的错误 实际上就是前后端分离的情况下&#xff0c;发生了跨域的问题 跨域定义&…

AWS SDK 3.x for .NET Framework 4.0 可行性测试

前言 为了应对日益增长的网络安全挑战, 越来越多的互联网厂商已经陆续开始或者已经彻底停止了对 SSL 3 / TLS 1.0 / TLS1.1 等上古加密算法的支持. 而对于一些同样拥有悠久历史的和 AWS 服务相关联的应用程序, 是否可以通过仅更新 SDK 版本的方式来适应新的环境. 本文将以 Win…

PyTorch模型性能分析与优化

动动发财的小手&#xff0c;点个赞吧&#xff01; 训练深度学习模型&#xff0c;尤其是大型模型&#xff0c;可能是一项昂贵的支出。我们可以使用的管理这些成本的主要方法之一是性能优化。性能优化是一个迭代过程&#xff0c;我们不断寻找提高应用程序性能的机会&#xff0c;然…

基于Java+SpringBoot+vue前后端分离在线动漫信息系统设计实现

基于JavaSpringBootvue前后端分离在线动漫信息系统设计实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于JavaSpringBootvue前后端分离在线动漫信息系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完…

基于单片机串口控制直流电机调速

一、系统方案 (2)本设计采用STC89C5单片机作为主控器&#xff0c;串口控制直流电机调速&#xff0c;串口助手发送1-8&#xff0c;改变电机速度&#xff0c;数码管显示对应速度。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 TMOD0x21;//定…

Linux学习之ssh和scp

ls /etc/ssh可以看到这个目录下有一些文件&#xff0c;而/etc/ssh/ssh_config是客户端配置文件&#xff0c;/etc/ssh/sshd_config是服务端配置文件。 cat -n /etc/ssh/sshd_config | grep "Port "可以看一下sshd监听端口的配置信息&#xff0c;发现这个配置端口是22…

代码随想录算法训练营之JAVA|第三十三天|738. 单调递增的数字

今天是第33天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天&#xff0c;如果做不到&#xff0c;完成一件评论区点赞最高的挑战。 算法挑战链接 738. 单调递增的数字https://leetcode.cn/problems/monotone-increasing-digits/ 第一想法 题目理解&#xff1a;找到一个…

2023国赛数学建模B题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…

C++进阶 类型转换

本文简介&#xff1a;介绍C中类型转换的方式 类型转换 C语言中的类型转换为什么C需要四种类型转换C强制类型转换static_castreinterpret_castconst_castdynamic_cast RTTI&#xff08;了解&#xff09;总结 C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型…

数据同步后数据总条数对不上的问题解决

文章目录 [toc] 1.问题2.解决办法2.1&#xff09;设置合理的线程池参数2.2&#xff09;设置url连接参数2.3) 优化msql的系统参数2.4&#xff09;使用CountDownLatch减法计数器和数据插入的公共方法新开一个事务2.5&#xff09;sql批量注入器执行成功后&#xff0c;当前线程slee…