目的
1 了解 RT-Theard 内部处理中断
正文
1 寄存器构成
stack pointer–>SP 堆栈指针寄存器
Link Register --> LR 连接寄存器 用于 调用子程序
Program Counter --> PC 程序计数器
MSP --> 主堆栈指针
PSP --> 进程堆栈指针
PSRs --> 程序状态字寄存器组
PRIMASK/FAULTMASK/BASEPRI 中断屏蔽寄存器组
CONTROL --> 控制寄存器
2 Cortex-M 运行模式
操作模式:线程 和 处理 两种模式
处理模式:进入异常或中断
线程模式:其它
运行级别:特权级 和 用户级
处理模式:运行在特权级
RT-Thread 中断工作机制
1 中断向量表
2 中断处理过程
RT-Thread 分为 中断前导程序/用户中断服务程序/中断后续程序
2.1 中断前导程序
2.1.1 保存 CPU 中断时上下文信息
2.1.2 通知内核进入中断状态,调用 rt_interrupt_enter() 函数,作用是把全局变量 rt_interrupt_nest 加 1,用以记录中断嵌套层数
void rt_interrupt_enter(void) {
rt_base_t level;
level = rt_hw_interrupt_disable();
rt_interrupt_nest ++;
rt_hw_interrupt_enable(level);
}
2.2 中断服务程序
2.2.1 不进行线程切换,运行结束之后就会返回中断的线程
2.2.2 中断过程中需要进行线程切换 rt_hw_context_switch_interrupt()
然后触发 PendSV 异常(PendSV 异常是专门用来辅助上下文切换的,且被初始化为最低优先级的异常)。PendSV 异常被触发后,不会立即进行 PendSV 异常中断处理程序,因为此时还在中断处理中,只有当中断后续程序运行完毕,真正退出中断处理后,才进入 PendSV 异常中断处理程序
2.3 中断后续程序
2.3.1 通知内核离开中断状态 rt_interrupt_leave(), 将全局变量 rt_interrupt_nest 减 1
void rt_interrupt_leave(void) {
rt_base_t level;
level = rt_hw_interrupt_disable():
rt_interrupt_nest --;
rt_hw_interrupt_enable(level);
}
2.3.2 恢复中断前的 CPU 上下文
恢复中断前的 CPU 上下文,如果在中断处理过程中未进行线程切换,那么恢复 from 线程的 CPU 上下文,如果在中断中进行了线程切换,那么恢复 to 线程的 CPU 上下文。这部分实现跟 CPU 架构相关,不同 CPU 架构的实现方式有差异
中断嵌套
当一个中断发生时,中断服务程序需要取得相应的硬件状态或者数据。如果中断服务程序接下来要对状态或者数据进行简单处理,比如 CPU 时钟中断,中断服务程序只需对一个系统时钟变量进行加一操作,然后就结束中断服务程序。这类中断需要的运行时间往往都比较短。但对于另外一些中断,中断服务程序在取得硬件状态或数据以后,还需要进行一系列更耗时的处理过程,通常需要将该中断分割为两部分,即上半部分(Top Half)和底半部分(Bottom Half)。在上半部分中,取得硬件状态和数据后,打开被屏蔽的中断,给相关线程发送一条通知(可以是 RT-Thread 所提供的信号量、事件、邮箱或消息队列等方式),然后结束中断服务程序;而接下来,相关的线程在接收到通知后,接着对状态或数据进行进一步的处理,这一过程称之为底半处理。
底半处理:是指将中断过程分为两部分,前一部分用于保存的各类信息启动中断过程,后一部分是异步的直到等待 Bottom half 信号之后在处理
接口管理
API 并不会出现在每一个移植分支中,例如通常 Cortex-M0/M3/M4 的移植分支中就没有这个 API。
由于关闭全局中断会导致整个系统不能响应中断,所以在使用关闭全局中断做为互斥访问临界区的手段时,必须需要保证关闭全局中断的时间非常短,例如运行数条机器指令的时间。