RT-Thread 中断管理(学习二)

news2024/11/24 20:08:50

中断的底半处理

RT-Thread不对中断服务程序所需要的处理时间做任何假设、限制,但如同其它实时操作系统或非实时操作系统一样,用户需要保证所有的中断服务程序在尽可能短的时间内完成。这样在发生中断嵌套,或屏蔽了相应中断源的过程中,不会耽误嵌套的其它中断处理过程,或自身中断源的下一次中断信号。

当一个中断发生时,中断服务程序需要取得相应的硬件状态或者数据。
如果中断服务程序接下来需要对状态或者数据进行简单处理,比如CPU时钟中断,中断服务程序只需对一个系统时钟变量进行加一操作,然后就结束中断服务程序。这类中断所需要的运行时间往往都比较短。

但对于另外一些中断,中断服务程序在取得硬件状态或数据以后,还需要进行一系列更耗时的处理过程,通常需要将该中断分割为两部分,即上半部分(Top Half)和底半部分(Bottom Half)。
在上半部分中,取得硬件状态和数据后,打开被屏蔽的中断,给相关线程发送一条通知,然后结束中断服务程序;而接下来,相关的线程在接收到通知后,接着对状态或数据进行进一步的处理,这一过程称之为底半处理。

为了详细描述底半处理在RT-Thread中的实现,以一个虚拟的网络设备接收网络数据包作为范例,假设接收到数据报文后,系统对报文的分析、处理是一个相对耗时的,比外部中断源信号重要性小许多的,而且在不屏蔽中断源信号情况下也能处理的过程。

这个例子的程序创建了一个nwt线程,这个线程在启动运行后,将阻塞在nw_bh_sem信号上,一旦这个信号量被释放,将执行接下来nw_packet_parser过程,开始Bottom Half的事件处理。

/* 用于唤醒线程的信号量 */
rt_sem_t nw_bh_sem;

/* 数据读取、分析的线程 */
void demo_nw_thread(void *param)
{
	//首先对设备进行必要的初始化工作
	device_init_setting();

	/* 创建一个semaphore 来响应 Bottom Half的事件*/
	nw_bh_sem = rt_sem_create("bh_sem", 0, RT_IPC_FLAG_PRIO);

	while(1)
	{
		rt_sem_take(nw_bh_sem,RT_WAITING_FOREVER);
		nw_packet_parser(packet_buffer);
		nw_packet_process(packet_buffer);
	}
}

int main(void)
{
    rt_thread_t thread;

    /* 创建处理线程 */
    thread = rt_thread_create("nwt",demo_nw_thread, RT_NULL, 1024, 20, 5);

    if (thread != RT_NULL)
        rt_thread_startup(thread);
}

void demo_nw_isr(int vector, void *param)
{
	nw_device_status_read();
	rt_sem_release(nw_bh_sem);
}

中断服务程序通过对一个信号量对象的等待和释放,来完成中断Bottom Half的起始和终结。
由于将中断处理划分为Top和Bottom两个部分后,使得中断处理过程变为异步过程。
必须认真考虑中断服务的处理时间是否大于给Bottom Half发送通知并处理的时间。

RT-Thread中断管理接口

为了把操作系统和系统底层的异常、中断硬件隔离开来,RT-Thread把中断和异常封装为一组抽象接口,如下图所示:
在这里插入图片描述

中断服务程序挂接

系统把用户的中断服务程序(handler)和指定的中断号关联起来,可调用如下的接口挂载一个新的中断服务程序:

rt_isr_handler_t rt_hw_interrupt_install(int vector,rt_isr_handler_t handler, void *param,char *name);

调用rt_hw_interrupt_install()后,当这个中断源产生中断时,系统将自动调用装载的中断服务程序。

  • vector:是挂载的中断号。
  • handler:新挂载的中断服务程序
  • param:作为参数传递给中断服务程序
  • name:中断的名称
  • 返回:挂载这个中断服务程序之前挂载的中断服务程序的句柄

注:这个 API 并不会出现在每一个移植分支中,例如通常 Cortex-M0/M3/M4 的移植分支中就没有这个 API。

中断服务程序是一种需要特别注意的运行环境,它运行在非线程的执行环境下(一般为芯片的一种特殊运行模式(特权模式)),在这个运行环境中不能使用挂起当前线程的操作,因为当前线程并不存在。

中断源管理

通常在ISR准备处理某个中断信号之前,我们需要先屏蔽改中断源,在ISR处理完状态或数据以后,及时的打开之前屏蔽的中断源。

屏蔽中断源可以保证在接下来的处理过程中硬件状态或者数据不会收到干扰。

void rt_hw_interrupt_mask(int vector);

调用rt_hw_interrupt_mask函数接口后,相应的中断将会被屏蔽(这个中断触发时,中断状态寄存器会有相应的变化,但并不送达到处理器进行处理)。

打开屏蔽的中断源:

void rt_hw_interrupt_umask(int vector);

全局中断开关

全局中断开关也称为中断锁,是禁止多线程访问临界区的最简单的一种方式,即通过关闭中断的方式,来保证当前线程不会被其它事件打断(整个系统已经不再响应那些可以触发重新调度的外部事件),当前线程不会被抢占,除非这个线程主动放弃了CPU控制权。

rt_base_t rt_hw_interrupt_disable(void);
  • 返回:中断状态,函数运行前的中断状态。

恢复中断也称为开中断。
rt_hw_interrupt_enable()这个函数用于“使能”中断,它恢复了调用中断使能函数前的中断状态。

如果调用rt_hw_disable()函数前是关中断状态,调用此函数后仍然是关中断状态。

使用中断锁来操作临界区的方法可以应用于任何场合,且其他几类同步方式都是依赖于中断锁而实现的,可以说中断锁是最强大的和最高效的同步方法。

只是使用中断锁最主要的问题在于,在中断关闭期间系统将不再响应任何中断,也就不能响应外部的事件。所以中断锁对系统的实时性影响巨大,当使用不当的时候会导致系统完全无实时性可言。

为了保证一行代码的互斥运行,最快速的方法是使用中断锁而不是信号量或互斥量

    /* 关闭中断 */
    level = rt_hw_interrupt_disable();
    a = a + value;
    /* 恢复中断 */
    rt_hw_interrupt_enable(level);
    /* 获得信号量锁 */
    rt_sem_take(sem_lock, RT_WAITING_FOREVER);
    a = a + value;
    /* 释放信号量锁 */
    rt_sem_release(sem_lock);

函数 rt_base_t rt_hw_interrupt_disable(void) 和函数 void rt_hw_interrupt_enable(rt_base_t level) 一般需要配对使用,从而保证正确的中断状态。

在RTT中,开关全局中断的API支持多级嵌套使用。

中断通知

当整个系统被中断打断,进入中断处理函数时,需要通知内核当前已经进入到中断状态。
针对这种情况,可通过以下接口:

void rt_interrupt_enter(void);
void rt_interrupt_leave(void);

这两个接口分别用在中断前导程序和中断后续程序中,均会对rt_interrupt_nest(中断嵌套深度)的值进行修改。

每当进入中断时,可以调用rt_interrupt_enter()函数,用于通知内核,当前已经进入了中断状态,并增加中断嵌套深度(执行rt_interrupt_nest++);

每当退出中断时,可以调用rt_interrupt_leave()函数,用于通知内核,当前已经离开了中断状态,并减少中断嵌套深度。

注意不要在应用程序中调用这两个接口函数。

使用rt_interrupt_enter/leave()的作用是,在中断服务程序中,如果调用了内核相关的函数(如释放信号量等操作),则可以通过判断当前中断状态,让内核及时调整相应的行为。

例如,在中断中释放了一个信号量,唤醒了某线程,但通过判断发现当前系统处于中断上下文环境中,那么在进行线程切换时应该采取中断中线程切换的策略,而不是立即进行切换。

在上层应用中,在内核需要指定当前已经进入到中断状态或当前嵌套的中断深度时,可调用rt_interrupt_get_nest()接口,它会返回rt_interrupt_nest。

  • 0:当前系统不处于中断上下文环境中。
  • 1:当前系统处于中断上下文环境中。
  • 大于1:当前中断嵌套层次。

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

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

相关文章

小黑开始了拉歌训练,第一次进入部室馆,被通知要去当主持人心里有些紧张的leetcode之旅:337. 打家劫舍 III

小黑代码(小黑卡在了bug中,上午一步步探索做出,非常NB!!!) # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left lef…

Hive窗口函数回顾

1.语法 1.1 基于行的窗口函数 Hive的窗口函数分为两种类型,一种是基于行的窗口函数,即将某个字段的多行限定为一个范围,对范围内的字段值进行计算,最后将形成的字段拼接在该表上。 注意:在进行窗口函数计算之前&#…

X86指令基本格式

X86指令基本格式 1 什么是机器码2 X86指令基本格式3 指令前缀3.1 第一组:封锁和重复执行前缀3.2 第二组:段前缀3.3 第三组:修改操作数默认长度3.4 第四组:修改默认地址长度 4 操作码5 ModR/M与SIB5.1 ModR/M字节5.2 SIB字节 6 地址…

uCharts常用图表组件demo

带渐变阴影的曲线图 <view class"charts-box"><qiun-data-charts type"area" :opts"opts" :chartData"chartData" :ontouch"true":background"rgba(256,256,256,0)" /> </view>data(){return{…

嵌入式学习(1)HAL库

文章目录 1.HAL库文件介绍2.HAL库编程目录结构3.使用cubemx生成HAL库编程目录结构 1.HAL库文件介绍 2.HAL库编程目录结构 3.使用cubemx生成HAL库编程目录结构

【JavaEE重点知识归纳】第7节:类和对象

目录 一&#xff1a;了解面向对象 1.什么是面向对象 2.面向对象和面向过程区分 二&#xff1a;类定义和使用 1.什么是类 2.练习&#xff1a;定义一个学生类 三&#xff1a;类的实例化 1.什么是实例化 2.类和对象的说明 四&#xff1a;认识this 1.为什么要有this引用…

rails 常量自动加载和重新加载机制

在Rails中&#xff0c;有一个称为"常量自动加载和重新加载机制"的功能&#xff0c;它使得在开发和生产环境中能够自动加载和重新加载类和模块。这个机制允许您不必手动管理类的加载&#xff0c;使得开发更加方便。 快乐学习&#xff1a; 自动加载、重新加载 自动加…

Yii2全拦截路由catchAll的使用

定义&#xff1a;catchAll 路由&#xff08;全拦截路由&#xff09; 应用场景&#xff1a;网站维护的时候需要向用户抛出一个维护的页面&#xff0c;方便提醒用户 使用方法&#xff1a; 1、在应用配置中设置 yii\web\Application::catchAll 属性 2、新增对应的控制器方法 3、…

【Putty】win10 / win 11:SSH 远程连接工具 Putty 下载、安装

目录 一、Jmerter 连接 SSH 隧道的 mysql&#xff08;不可行&#xff09; 二、Putty 介绍 三、Putty 的下载 四、Putty 无需安装直接使用 五、Putty 使用 &#xff08;1&#xff09;我需要连接 ssh 隧道的 MySQL 参数如下 &#xff08;2&#xff09;Putty 使用教程 一、…

MA-SAM:模态不可知的三维医学图像分割SAM自适应

论文&#xff1a;MA-SAM: Modality-agnostic SAM Adaptation for 3D Medical Image Segmentation | Papers With Code 代码&#xff1a;GitHub - cchen-cc/MA-SAM: PyTorch implementation for MA-SAM 机构&#xff1a;a)高级医疗计算和分析中心&#xff0c;麻省总医院和哈佛…

华为云开源低代码引擎 TinyEngine 正式发布

随着企业对于低代码开发平台的需求日益增长,急需一个通用的解决方案来满足各种低代码平台的开发需求。正是在这种情况下,低代码引擎应运而生。它是一种通用的开发框架,通过对低代码平台系统常用的功能进行解构,将其划分为多个功能模块,并为每个模块定义了相应的协议和开发…

Go 语言中 panic 和 recover 搭配使用

本次主要聊聊 Go 语言中关于 panic 和 recover 搭配使用 &#xff0c;以及 panic 的基本原理 最近工作中审查代码的时候发现一段代码&#xff0c;类似于如下这样&#xff0c;将 recover 放到一个子协程里面&#xff0c;期望去捕获主协程的程序异常 看到此处&#xff0c;是否会…

传输层TCP协议

前言 传输层的历史渊源可以追溯到计算机网络的早期阶段。在20世纪60年代和70年代&#xff0c;计算机网络主要是由一些简单的点对点连接组成的。这些连接通常使用专用的硬件和协议&#xff0c;例如串行线路和电话线路。在这种情况下&#xff0c;传输层的功能是由这些协议本身来提…

【SpringCloud】认识微服务

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 认识微服务 一、 服务架构演变1.1 单体架构…

Qt之进程通信-QProcess(含源码+注释)

文章目录 一、QProcess进程通信示例二、QProcess通信个人理解三、源码MainWindowProcessSenderMainWindowProcessSender.hMainWindowProcessSender.cppMainWindowProcessSender.ui MainWindowProcessRecvMainWindowProcessRecv.hMainWindowProcessRecv.cppMainWindowProcessRec…

【算法——双指针】LeetCode 18 四数之和

题目描述&#xff1a; 解题思路&#xff1a;双指针 四数之和与前面三数之和思路一样&#xff0c;排序后&#xff0c;枚举 nums[a]作为第一个数&#xff0c;枚举 nums[b]作为第二个数&#xff0c;那么问题变成找到另外两个数&#xff0c;使得这四个数的和等于 target&#xff0c…

吃鸡玩家必备神器!一站式提升战斗力、分享干货!

大家好&#xff0c;我是吃鸡玩家。在这个视频中&#xff0c;我要分享一个让你瞬间提高战斗力的神器&#xff0c;同时让你享受到顶级游戏作战干货的盛宴&#xff01;让我们一起来了解吧&#xff01; 首先&#xff0c;我们推荐绝地求生作图工具。通过这款工具&#xff0c;你可以轻…

用这些IDEA插件,让你早下班两小时

GenerateAllSetter:一键调用一个对象的所有setter方法 RestfulTool:自动显示所有URL接口&#xff0c;快速检索接口 SequenceDiagram:以图形界面形式显示方法调用链&#xff0c;方便阅读源码、梳理代码 CamelCase:变量下划线转驼峰命名 Rainbow Brackets:帮助程序员识别代码中括…

十五、异常(5)

本章概要 异常限制构造器 异常限制 当覆盖方法的时候&#xff0c;只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用&#xff0c;因为这意味着与基类一起工作的代码&#xff0c;也能和导出类一起正常工作&#xff08;这是面向对象的基本概念&#xff09;&#…

基于SSM的校园资讯推荐系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…