ucOSii临界区

HarderHeng Lv5

临界区定义

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

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

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

临界区代码

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 ** 嵌入式操作系统中用到的中断即PendSVSysTick**等各种中断的最高的中断优先级,也就是说要屏蔽掉所有嵌入式操作系统中的中断,但是允许其他的硬件中断和异常。

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

  • Title: ucOSii临界区
  • Author: HarderHeng
  • Created at : 2025-03-07 16:00:25
  • Updated at : 2025-03-21 17:00:39
  • Link: https://harderheng.life/2025/03/07/ucOSii临界区/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
ucOSii临界区