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

中断的底半处理

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.hqwc.cn/news/127568.html

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

相关文章

JAVA-SpringBoot入门Demo用IDEA建立helloworld

使用编辑器IDEA做SpringBoot项目最近几年比较红红,作为JAVA语言翻身的技术,用户量激增。由于java平台原来的占有率,相比net core在某些方面更有优势。 我把本次我下载完成后Maven项目的过程记录下来了,仅供参考! 安装J…

FFmpeg 命令:从入门到精通 | FFmpeg 基本介绍

FFmpeg 命令:从入门到精通 | FFmpeg 基本介绍 FFmpeg 命令:从入门到精通 | FFmpeg 基本介绍FFmpeg 简介FFmpeg 基础知识复用与解复用编解码器码率和帧率 资料 FFmpeg 命令:从入门到精通 | FFmpeg 基本介绍 本系列文章要解决的问题&#xff1…

1.6 IntelliJ IDEA开发工具

前言: ### 1.6 IntelliJ IDEA开发工具笔记 - **背景**: - 使用基础文本编辑器如记事本编写Java代码虽然可行,但存在效率低下且难以调试的问题。 - 集成开发环境 (IDE) 可以有效地提高Java程序的开发效率。 - **常见Java IDE**&#xf…

【深度学习】UNIT-DDPM核心讲解

文章目录 大致介绍:扩散损失:转换损失:循环一致性损失:推理过程:优缺点: 参考文章: https://blog.csdn.net/ssshyeong/article/details/127210086 这篇文章对整个文章 UNIT-DDPM: UNpaired Imag…

关于 Vue-iClient-MapboxGL 的使用注意事项

官网:https://iclient.supermap.io/web/apis/vue/zh/api/guide/installation.html 关于图的使用,其余的引入步骤不再赘述,仅说注意事项。 推荐使用的是全局引入,也就是完整引入 因为单独引入我踩了不少坑,比如说 cs…

PCA和SVD数据降维

PCA(Principal Component Analysis) 是一种常见的数据分析方式,常用于高维数据的降维,可用于提取数据的主要特征分量。 最大可分性 基向量乘原始矩阵会将矩阵映射到这个基向量空间中,如果基的数量少于向量本身的维数…

Pyside6 安装和简单界面开发

Pyside6 安装和简单界面开发 Pyside6介绍Pysied6开发环境搭建Python安装Pysied6安装 Pyside6界面开发简单界面设计界面设计界面编译 编写界面初始化代码软件打包 Pyside6介绍 对于Python的GUI开发来说,Python自带的可视化编程模块的功能较弱,PySide是跨…

浙江工业大学2024年工商管理硕士(MBA)联考网报指南

2024年MBA全国联考报名系统已开放。考生登录“中国研究生招生信息网”http://yz.chsi.com.cn进行报名。 网报分为“填写考生信息”和“填写报考信息”两大步骤,MBA中心特制作注意事项流程图供参考,希望能够帮助大家顺利报考。 预报名成功的考生&…

Git 学习笔记 | Git 的简介与历史

Git 学习笔记 | Git 的简介与历史 Git 学习笔记 | Git 的简介与历史Git 简介Git 历史 Git 学习笔记 | Git 的简介与历史 Git 简介 Git是分布式版本控制系统(Distributed Version Control System,简称 DVCS),分为两种类型的仓库&…

网关、网桥、路由器和交换机之【李逵与李鬼】

概念 网关 网关简单来说是连接两个网络的设备,现在很多局域网都是采用路由器来接入网络,因此现在网关通常指的就是路由器的IP。网关可用于家庭或者小型企业,连接局域网和Internet,也有用于工业应用的。 网桥 网桥也叫桥接器,是连接两个局域网的一种存储/转发设备,它能…

AI智能创作系统ChatGPT商业运营源码+AI绘画系统/支持GPT联网提问/支持Midjourney绘画+支持国内AI提问模型+Prompt应用

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统,支持国内AI提问模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f…

【AI工程化】 如何让AI在企业多快好省的落地,提高生产效率?

文章目录 🌺前言🌺内容简介🌺读者对象🌺专家推荐🎆彩蛋 🌺前言 作为计算机科学的一个重要领域,机器学习也是目前人工智能领域非常活跃的分支之一。机器学习通过分析海量数据、总结规律&#xf…