ARM单片机中断处理过程解析

news2024/9/29 9:23:57

前言

中断,在单片机开发中再常见不过了。当然对于中断的原理和执行流程都了然于胸,那么对于ARM单片机中断的具体处理行为,你真的搞清楚了吗?

今天来简单聊一聊,ARM单片机中断处理过程中的具体行为是什么样的,搞清楚了这些,让你彻底理解中断是如何执行的。

掌握了这些内容后,以后在开发过程中遇到中断问题,可以做到游刃有余。

本篇文章主要梳理一下 Cortex-M3 内核的单片机在处理中断事件的具体行为,以及不同的中断是如何处理的。

中断响应

Cortex-M3 单片机在开始响应一个中断时,会进行以下三个操作:

  • 寄存器入栈,将寄存器的值压入栈
  • 取向量:从向量表中找出对应的服务程序入口地址
  • 选择堆栈指针 MSP/PSP,更新堆栈指针SP,更新连接寄存器LR,更新程序计数器PC

响应中断的第一个动作,就是自动保存现场的必要部分:依次把 xPSR, PC, LR, R12 以及 R3-R0 由硬件自动压入适当的堆栈中。

当响应异常时,当前的代码正在使用 PSP,则压入 PSP,也就是使用进程堆栈;否则就压入 MSP,使用主堆栈。一旦进入了服务例程,就将一直使用主堆栈。

入栈顺序以及入栈后堆栈中的内容,如下图所示。在自动入栈的过程中,把寄存器写入堆栈内存的时间顺序,并不是与写入的空间顺序相对应的。但是机器会保证:正确的寄存器将被保存到正确的位置 。

先把PC与 xPSR 的值保存,就可以更早地启动服务例程指令的预取——因为这需要修改PC;同时,也做到了在早期就可以更新 xPSR 中 IPSR 位段的值。

取出中断服务例程地址,从中断向量表中找出正确的异常向量,然后在服务程序的入口处预取指。这部分由指令总线(I-Code总线)完成。

在入栈和取向量操作完成之后,执行中断服务例程之前,还要更新一系列的寄存器:

  • SP:在入栈后会把堆栈指针(PSP 或 MSP)更新到新的位置。在执行服务例程时,将由 MSP 负责对堆栈的访问。
  • PSR:更新 IPSR 位段(PSR的最低部分)的值为新响应的异常编号。
  • PC:在取向量完成后, PC将指向服务例程的入口地址。
  • LR:在出入 ISR 的时候, LR 的值将重新诠释为 “EXC_RETURN”。在异常进入时由系统计算并赋给 LR,并在异常返回时使用它。(后面会讲解 EXC_RETURN)

以上是在响应异常时通用寄存器的变化。另一方面,在 NVIC 中,也会更新若干个相关有寄存器。

在完成以上工作之后,系统开始执行中断服务程序里的指令。当指令执行完毕,进入中断返回处理阶段。

中断返回

当异常服务例程执行完毕后,需要做一个“异常返回”动作,从而恢复先前的系统状态,才能使被中断的程序得以继续执行 。触发中断返回的指令:

有些处理器会使用特殊的返回指令来标示中断返回,例如 8051 就使用 reti。但是在 CM3 中,是通过向 PC 中写入 EXC_RETURN 来识别返回动作的。

在进行中断返回操作后,会进行下面的处理:

  • 出栈:先前压入栈中的寄存器在这里恢复。内部的出栈顺序与入栈时的相对应,堆栈指针的值也改回先前的值。
  • 更新 NVIC 寄存器:伴随着异常的返回,它的活动位也被硬件清除。对于外部中断,倘若中断输入再次被置为有效,悬起位也将再次置位,新一次的中断响应序列也可随之再次开始。

中断返回值

前面已经讲到,在进入异常服务程序后,将自动更新 LR 的值为特殊的 EXC_RETURN 。这是一个高 28 位全为1的值,只有[3:0] 的值有特殊含义:

当中断服务例程把这个值送往 PC 时,就会启动处理器的中断返回操作。因为 LR 的值是由 CM3 自动设置的,所以只要没有特殊需求,就不要改动它。

总结一下上表,可以得到,合法的 EXC_RETURN 值共3个:

如果主程序在线程模式下运行,并且在使用 MSP 时被中断,则在服务例程中 LR=0xFFFF_FFF9(主程序被打断前的 LR 已被自动入栈)。

如果主程序在线程模式下运行,并且在使用 PSP 时被中断,则在服务例程中 LR=0xFFFF_FFFD(主程序被打断前的 LR 已被自动入栈) 。

这样描述可能比较抽象,不好理解。那就通过两张图来直观感受一下。

主程序运行在线程模式,且使用主堆栈,进入中断后,以及有中断嵌套情况下,模式切换和 LR 的变化如下图。

如果主程序在 Handler 模式下运行,则在服务例程中 LR = 0xFFFF_FFF1(主程序被打断前的LR已被自动入栈)。这时的所谓“主程序”,其实更可能是被抢占的服务例程。事实上,在嵌套时,更深层 ISR 所看到的 LR 总是 0xFFFF_FFF1。

主程序运行在线程模式,且使用进程堆栈的情况下,LR 值的变化如下

通过这两张图,可以很好地理解异常返回值的变化情况。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

中断嵌套

Cortex-M3 内核单片机支持中断嵌套,即高优先级中断可以抢占低优先级去执行指令。我们要根据实际使用情况,为每个中断建立适当的优先级。

NVIC 和 CM3 处理器会根据优先级的设置来控制抢占与嵌套行为。有了自动入栈和出栈,我们不用担心在中断发生嵌套时,会使寄存器的数据损毁。

我们知道,所有服务例程都只使用主堆栈(MSP)。所以当中断嵌套加深时,对主堆栈的压力会增大:每嵌套一级,就至少再需要8个字,即32字节的堆栈空间(这没算上 ISR 对堆栈的额外需求),并且何时嵌套多少级也是不可预料的。

如果主堆栈的容量本来就已经所剩无几了,中断嵌套又突然加深,则主堆栈有溢出的凶险。堆栈溢出是很致命的,新入栈数据会覆盖掉主堆栈前面的数据,数据遭到了破坏。

若在服务例程返回前混迭区的数据又被更改了,则在执行中断返回后,系统极可能功能紊乱,甚至出现程序跑飞的问题。

要注意的,相同的异常(中断)是不允许重入的。因为每个异常都有自己的优先级,并且在异常处理期间,同级或低优先级的异常是要阻塞的。

因此对于同一个异常,只有在上次实例的服务例程执行完毕后,方可继续响应新的请求。因此,在 SVC 服务例程中,就不得再使用SVC指令,否则将产生 fault 现象。

咬尾中断

Cortex-M3 内核为了缩短中断延迟,新增了 “咬尾中断” 机制。

当处理器在响应某个中断时,如果又发生低优先级或者相同优先级中断,则被阻塞。在当前的中断执行返回后,系统处理悬起的中断时,不再先POP,然后又把 POP 出来的内容PUSH回去;而是继续使用上一个中断已经 PUSH 好的成果。

这么一来,看上去好像后一个中断把前一个中断的尾巴咬掉了,前前后后只执行了一次 入栈/出栈 操作。于是,这两个异常之间的“时间沟”变窄了很多。

晚到中断

CM3 的中断处理还有另一个机制,这就是“晚到的异常处理”。

当 CM3 对某异常的响应序列还处在早期:入栈的阶段,尚未执行其服务例程时,如果此时收到了高优先级异常的请求,则本次入栈就成了为高优先级中断所做的了。

入栈后,将执行高优先级异常的服务例程。可见,它虽然来晚了,却还是因优先级高而优先执行。

比如,若在响应某低优先级 异常#1 的早期,检测到了高优先级 异常#2,则只要 #2 没有太晚,就能以“晚到中断”的方式处理:在入栈完毕后执行ISR #2。

如果 异常#2 来得太晚,以至于已经执行了 ISR #1 的指令,则按普通的抢占处理,这会需要更多的处理器时间和额外的堆栈空间。

在 ISR #2 执行完毕后,则以“咬尾中断”方式,来启动 ISR #1 的执行。

原文作者:【 一起学嵌入式

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

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

相关文章

spring5源码篇(13)——spring mvc无xml整合tomcat与父子容器的启动

spring-framework 版本:v5.3.19 文章目录 整合步骤实现原理ServletContainerInitializer与WebApplicationInitializer父容器的启动子容器的启动 相关面试题 整合步骤 试想这么一个场景。只用 spring mvc(确切来说是spring-framework)&#x…

Windows环境下安装及部署Nginx

一、安装Nginx教程 1、官网下载地址:https://nginx.org/en/download.html 2、下载教程:选择Stable version版本下载到本地 3、下载完成后,解压放入本地非中文的文件夹中: 4、启动nginx:双击nginx.exe,若双击…

Vue 3:玩一下web前端技术(五)

前言 本章内容为VUE语法的简单学习与相关语法讨论。 上一篇文章地址: Vue 3:玩一下web前端技术(四)_Lion King的博客-CSDN博客 下一篇文章地址: Vue 3:玩一下web前端技术(六)_L…

算法与数据结构(四)--排序算法

一.冒泡排序 原理图: 实现代码: /* 冒泡排序或者是沉底排序 *//* int arr[]: 排序目标数组,这里元素类型以整型为例; int len: 元素个数 */ void bubbleSort (elemType arr[], int len) {//为什么外循环小于len-1次?//考虑临界情况&#xf…

自动驾驶感知系统-全球卫星定位系统

卫星定位系统 车辆定位是让无人驾驶汽车获取自身确切位置的技术,在自动驾驶技术中定位担负着相当重要的职责。车辆自身定位信息获取的方式多样,涉及多种传感器类型与相关技术。自动驾驶汽车能够持续安全可靠运行的一个关键前提是车辆的定位系统必须实时…

为什么你的独立站有流量没转化?如何做诊断检查?

新店的创业初期,即使网站有流量,但是销售额为零的情况也常有发生。如果你确定流量是高质量的,寻找阻止潜在客户购买的具体因素可能会感到困难重重。 从“立即购买”按钮的色彩选择这样的细节,到构建品牌故事这样的大计划&#xf…

开发一个RISC-V上的操作系统(四)—— 内存管理

目录 往期文章传送门 一、内存管理简介 二、Linker Script 链接脚本 三、动态分配内存 四、测试 往期文章传送门 开发一个RISC-V上的操作系统(一)—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统(二…

springboot创建并配置环境(三) - 配置扩展属性(上集)

文章目录 一、介绍二、配置文件application.yml 一、介绍 在上一篇文章:springboot创建并配置环境(二) - 配置基础环境中,我们介绍了springboot如何配置基础环境变量。本篇文章讨论如何处理配置文件。即来自不同位置的配置属性,如&#xff1…

chatglm2外挂知识库问答的简单实现

一、背景 大语言模型应用未来一定是开发热点,现在一个比较成功的应用是外挂知识库。相比chatgpt这个知识库比较庞大,效果比较好的接口。外挂知识库大模型的方式可以在不损失太多效果的条件下获得数据安全。 二、原理 现在比较流行的一个方案是langcha…

OpenLayers入门,OpenLayers使用瓦片加载事件实现瓦片加载进度条,进度条根据瓦片加载数量自动更新进度,加载完毕后隐藏进度条

专栏目录: OpenLayers入门教程汇总目录 前言 本章主要讲解OpenLayers如何使用瓦片加载事件(tileloadstart)、瓦片加载完成事件(tileloadend)以及瓦片加载错误事件(tileloadend)。 并通过OpenLayers使用瓦片加载事件通过实现瓦片加载进度条的案例,实现进度条根据瓦片加…

vue3 vant上传图片

在 Vue 3 中使用 Vant 组件库进行图片上传,您可以使用 Vant 的 ImageUploader 组件。ImageUploader 是 Vant 提供的图片上传组件,可以方便地实现图片上传功能。 以下是一个简单的示例,演示如何在 Vue 3 中使用 Vant 的 ImageUploader 组件进行…

解决Font family [‘sans-serif’] not found问题

序言 以下测试环境都是在 anaconda3 虚拟环境下执行。 激活虚拟环境 conda activate test_python_env 或 source activate test_python_env工具: WinSCP Visual Studio Code 这里笔者使用 WinSCP 工具连接,编辑工具是 Visual Studio Code 一、字体…

【Python数据分析】Python基本数据类型

🎉欢迎来到Python专栏~Python基本数据类型 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒🍹 ✨博客主页:小夏与酒的博客 🎈该系列文章专栏:Python学习专栏 文章作者技术和水平有限,如果文中出现错误,希望…

C\C++内存管理

目录 1.C/C内存分布2.C语言中动态内存管理方式3.C中动态内存管理3.1new/delete内置类型3.2new和delete操作自定义类型 4.operator new与operator delete函数4.2重载operator new与operator delete(了解) 5.new和delete的实现原理5.1内置类型5.2 自定义类…

Vue 3:玩一下web前端技术(六)

前言 本章内容为VUE请求后端技术与相关技术讨论。 上一篇文章地址: Vue 3:玩一下web前端技术(五)_Lion King的博客-CSDN博客 下一篇文章地址: (暂无) 一、请求后端技术 1、使用Mock.js模…

【业务功能篇60】Springboot + Spring Security 权限管理 【终篇】

4.4.7 权限校验扩展 4.4.7.1 PreAuthorize注解中的其他方法 hasAuthority:检查调用者是否具有指定的权限; RequestMapping("/hello")PreAuthorize("hasAuthority(system:user:list)")public String hello(){return "hello Sp…

基于BSV的高性能并行CRC硬件电路生成器

01、引 言 循环冗余校验码,即Cyclic Redundancy Check (CRC), 是一种在各种通信系统中广泛应用的检错机制。CRC算法的工作原理和哈希函数类似,具体来说,其对任意长度的数据计算出一段唯一的标识(校验和), 然后根据这个…

#typescript 使用file-saver模块#

场景:前端使用file-saver模块做导出文档的时候,出现两个错误 1:npm run build 提示找不到模块,如图 解决方法: 先卸载,不管是否安装都先要卸载 ,然后安装: npm uninstall file-saver npm…

AD21原理图的高级应用(二)层次原理图设计

(二)层次原理图设计 1.层次原理图概述2.层次化原理图的应用2.1 自上而下的层次化原理图2.2 自下而上的层次化原理图 3.生成层次设计表 对于大规模的电路系统,需要将其按功能分解为若干个电路模块,用户可以单独绘制好各个功能模块,再将它们组合起来继续处…

DevOps-Jenkins

Jenkins Jenkins是一个可扩展的持续集成引擎,是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。 官网 应用场景 场景一 研发人员上传开发好的代码到github代码仓库需要将代码下载nginx服务器部署手动下载再…