网站xml,贵大网站建设多少钱,wordpress 上注册用户,做一个15页的网站怎么做前言
中断#xff0c;在单片机开发中再常见不过了。当然对于中断的原理和执行流程都了然于胸#xff0c;那么对于ARM单片机中断的具体处理行为#xff0c;你真的搞清楚了吗#xff1f;
今天来简单聊一聊#xff0c;ARM单片机中断处理过程中的具体行为是什么样的#xf…前言
中断在单片机开发中再常见不过了。当然对于中断的原理和执行流程都了然于胸那么对于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 时被中断则在服务例程中 LR0xFFFF_FFF9主程序被打断前的 LR 已被自动入栈。
如果主程序在线程模式下运行并且在使用 PSP 时被中断则在服务例程中 LR0xFFFF_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 的执行。 原文作者【 一起学嵌入式】