ucOSii临界区

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

临界区定义

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

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

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

临界区代码

临界区关中断时,需要操作做的是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))

  • CPU_CFG_NVIC_PRIO_BITS CPU中有多少位用来描述中断优先级,对CortexM来说是4位,两位响应优先级,两位抢占优先级。
  • CPU_CFG_KA_IPL_BOUNDARY ** 嵌入式操作系统中用到的中断即PendSV和SysTick**等各种中断的最高的中断优先级,也就是说要屏蔽掉所有嵌入式操作系统中的中断,但是允许其他的硬件中断和异常。

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