Skip to content

ucOSii临界区

· 4 min · RTOS / uCOS / 嵌入式开发 / 中断 / 学习笔记

临界区定义#

操作系统在处理关键代码时,也就是进入临界区时,需要关闭中断,防止中断打断当前执行的关键代码,造成系统资源的破坏。

关键就在于关闭中断,控制中断寄存器进行中断关闭。但是,如果单纯的在进入临界区之前关中断,在退出临界区之后开中断,岂不是破坏了原本的中断状态?例如在某些地方可能已经被关闭了中断,那么退出临界区之后我们要恢复的就是关中断的状态。

我们要做的就是在进入临界区前记录一下此刻的中断状态,然后关中断。在退出临界区之后,恢复之前记录的状态即可。

临界区代码#

临界区关中断时,需要操作做的是CPSR寄存器,也就是硬件相关的寄存器,临界区代码也就是port代码。

OS_CPU_SR_Save:
CPSID I ;禁用中断
PUSH {R1} ;这里虽然已经保存过R1,但是为了安全冗余还是再次保存R1
MRS R1, BASEPRI ;保存中断屏蔽寄存器,将来用来恢复
MSR BASEPRI, R0 ;将R0传入中断屏蔽寄存器,传入一个优先级,屏蔽这个优先级以下的中断
DSB ;确保数据操作到此为止全部执行完毕,控制流水线
ISB ;确保指令操作到此为止全部执行完毕,控制流水线
;在修改系统寄存器的场景中,一定要先DSB后ISB
MOV R0, R1 ;将R1放到R0作为返回值
POP R1 ;将先前R1的值从栈中弹出
CPSIE I ;启用中断
BX LR ;返回
OS_CPU_SR_Restore:
CPSID I ;禁用中断
MSR BASEPRI, R0 ;恢复原来的中断屏蔽
DSB
ISB
;指令和数据屏障
CPSIE I
BX LR ;返回

总体的流程大致是:

  1. 完全关闭中断
  2. 保存中断屏蔽寄存器BASEPRI
  3. 传递新的值给BASEPRI
  4. 将之前保存的BASEPRI的值拿来做返回值并返回

其中传递新的值给BASEPRI,新的值是一个有关硬件和操作系统的值,在这里没有给出。让我们来看一下这个宏定义。

cpu_sr = OS_CPU_SR_Save(CPU_CFG_KA_IPL_BOUNDARY << (8u - CPU_CFG_NVIC_PRIO_BITS))

在CortexM架构中,优先级又分为主优先级和子优先级,NVIC负责处理二者之间的关系。抢占优先级更高的允许中断其他的中断,响应优先级更高的在同样的抢占优先级下优先顺序执行。但是二者优先级组合在一起一共4位,是整个中断的优先级。而BASEPRI进行屏蔽时,就是使用的这个优先级进行屏蔽。