所谓临界区,即某些大家都使用到的一些变量,例如全局变量,当我们的某个函数要修改全局变量时,如果有中断打断了该中断过程,就会造成全局变量的混乱,为了避免此时其他中断打断该修改过程,我们可以在修改前将中断关闭,修改完成之后再开中断。在os_cpu.h中有OS_CRITICAL_METHOD,它定义了进入临界区的方法。一般的移植过程而言,有三种进入临界区的方法:
1>OS_CRITICAL_MOTHOD==1.
#define
OS_ENTER_CRITICAL() _asm sei;
#define
OS_EXIT_CRITICAL() _asm cli;
这种方法是直接开关中断,并没有保存中断屏蔽寄存器的值(见PRIMASK FAULTMASK
BASEPRI这三个寄存器),不管进入临界区之前中断是否是已经打开或者关闭,退出临界区后中断就被强制性的打开了。这在任务级代码中这样做没有太大的问题,因为在执行任务代码时中断基本都是打开的,但是在中断处理函数中情况就不是这样了。
2>OS_CRITICAL_MOTHOD==2
#define OS_ENTER_CRITICAL()
_asm{PUSHF;CLI}
#define OS_EXIT_CRITICAL()
_asm POPF
这种方法是关中断前将CPU状态寄存器的值存入堆栈中,然后在关中断。开中断时将CPU状态寄存器出栈,这样中断也恢复到了原来的状态。但是这样做的坏处就是会导致堆栈寄存器的内容的改变,从而导致对局部变量的访问产生了错位。从而产生严重的错误。
3>OS_CRITICAL_MOTHOD==3
#define OS_ENTER_CRITICAL
(cpu_sr=OSCPUSaveSR())
#define OS_EXIT_CRITICAL
(OSCPURestoreSR(cpu_sr))
方法三将CPU状态寄存器的值存至局部变量cpu_sr,而不是像方法二一样存到任务堆栈中,这样就避免用到了堆栈指针,防止了方法二错误的发生。开中断时将局部变量cpu_sr的值恢复到cpu状态寄存器中,这样就恢复到了中断前的状态。里面的OSCPUSaveSR()和OSCPURestoreSR()需要我们自己去实现,具体的实现是在os_cpu_a.asm中,这是我们移植时需要修改的一部分。
加载中,请稍候......