中断向量表

  • VTOR寄存器:中断向量地址Vn = VTOR + 中断号N * 4
  • 每个中断向量的大小=4B,所以是N*4
  • 由于实际有256个中断向量,所以中断向量表大小为1024B,因此该表必须以1024对齐,即链接脚本中使用ALIGN(1024)
  • 所以VTOR也必须以1024对齐,即VTOR低10位必须为0

CM3编程模型

  • 两种模式:thread模式(特权/用户级)、handler模式(特权级)
  • 堆栈指针
  • MSP(特权级):中断服务程序(ISR)、RTOS的特权级任务使用
  • PSP(特权/用户级):用户程序、RTOS的用户任务使用

  • 特殊寄存器CONTROL

  • CONTROL[1]决定使用哪一个SP,只有在特权的thread模式中可写(handler只能选MSP所以不可写)
  • CONTROL[0]决定特权级/用户级,只有特权中可写
  • 执行ISR的开头会修改CONTROL,将用户态切换到特权态

中断/异常模型

  • 抢占优先级(preemptive)与次优先级:实现优先级分组
  • 可抢占=>中断嵌套,不可抢占=>单中断;默认可抢占。
  • 抢占优先级:决定了谁先抢占
  • 次优先级:在挂起队列中,决定谁先
  • 注意:中断A(抢占=1,次=5)正在运行,此时来了中断B(抢占=1,次=1),中断B不能抢占,因为次优先级只决定挂起队列的优先级
  • 尾链特性(Tail-chain):如果执行完中断A后,需要连续执行中断B,此时会省略出入栈过程,直接ISRA->ISRB
  • 迟来特性(Late Arrival):若中断A正在软件保存环境时,此时来了更高的中断B,会暂停保存,立刻转去服务中断B

  • 中断发生到ISR执行的流程

  • 硬件保存断点:PSRx、PC、LR、r12、r3-r0(8*32b=32B)

  • 读中断向量表,找到新的SP和跳转的PC

  • 加载流水线:跳转到PC并更新LR,执行指令

  • 软件保存环境:保存剩下的寄存器(8*32b=32B)

  • 中断发生到ISR执行的时间(中断延迟计算)

  • NVIC识别延迟+流水线延迟(执行指令+取下一个指令)+NVIC处理延迟+硬件保存断点延迟 = 12CLK

  • 使用尾链和迟来特性优化

中断行为分析(重点)

  • 单次中断(正常)

  • 过程:中断请求->挂起位置位->经过一个中断延迟后才响应->执行ISR->挂起位清0

image-20260119213714401

  • 单次中断(挂起时取消中断)

image-20260119213443503

  • 持续中断

  • 再次进入ISR时,由于Tail-chain机制,会产生一个尖刺

image-20260119214214273

  • 多次脉冲中断(挂起中出现第2~n个)

  • 原因:挂起中出现的多个脉冲被识别为了一个中断

image-20260119214534507

  • 多次脉冲中断(解挂后出现第2~n个)

  • 原因:挂起中出现的第二个脉冲被识别为了新的中断

  • 中断结束又重新进入中断时,会被咬尾优化:
    • 正常情况:中断1->主程序->中断2
    • 咬尾优化:中断1->中断2(将两次上下文切换变为了一次)

image-20260119214712727

丢中断原因分析

  • 多个中断产生太快
  • 原因:中断1挂起时,又来了多个同类型中断,由于使用的是同一个pending寄存器,所以导致后面的中断没有被记录上
  • ISR过程太长
  • 原因:中断1执行ISR时,中断2触发并挂起,但当ISR执行结束时将挂起标志也清除了,导致中断2没有被识别

  • 解决方案

  • 异步解决方案:设置一个队列,ISR中只入队中断信息,在主循环中while查询队列并执行程序

  • 关中断解决方案:进入中断后立刻关闭中断