本帖最后由 Eric2013 于 2014-12-24 19:44 编辑
11.7 临界段
11.7.1 临界段基本概念 代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打入。为确保临界段代码的执行,在进入临界段之前要关中断,而临界段代码执行完以后要立即开中断。 从代码上来看,处在关中断和开中断之间的代码段就是临界段。 由于各厂商的CPU和C编译器的关中断和开中断的方法以及指令不尽相同,为增强μCOS-III的可移植性(即在μCOS-III的各个C语言函数中尽可能地不出现汇编语言代码),μCOS-III用CPU_INT_DIS()和CPU_INT_EN()这两个宏封装了与系统硬件相关的关中断和开中断指令。 另外,不要在临界段中调用μCOS-III提供的功能函数,防止系统崩溃。 11.7.2 临界段相关的宏定义 CPU_INT_DIS()和CPU_INT_EN()可以以下四种不同的实现方法。 #define CPU_CRITICAL_METHOD_NONE 0u
#define CPU_CRITICAL_METHOD_INT_DIS_EN 1u
#define CPU_CRITICAL_METHOD_STATUS_STK 2u
#define CPU_CRITICAL_METHOD_STATUS_LOCAL 3u
至于在实际应用时使用哪种方法,取决于用户使用的处理器和C编译器。用户可以通过cpu.h文件中的宏定义进行选择: #define CPU_CFG_CRITICAL_METHOD CPU_CRITICAL_METHOD_STATUS_LOCAL
typedef CPU_INT32U CPU_SR;
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0
#else
#define CPU_SR_ALLOC()
#endif
#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0) (1)
#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0) (2)
#ifdef CPU_CFG_INT_DIS_MEAS_EN
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); \
CPU_IntDisMeasStart(); } while (0)
#define CPU_CRITICAL_EXIT() do { CPU_IntDisMeasStop(); \
CPU_INT_EN(); } while (0)
#else
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0)
#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0)
#endif
1. 当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_INT_DIS_EN时 这种方式最简单,即直接使用处理器的开中断和关中断指令来实现宏。但是不推荐使用这种方式,因为不支持中断嵌套,但是考虑到有些处理器或者编译器仅支持这种方式,不得不选择这种方式。 2. 当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_INT_DIS_EN时 这种方法稍复杂些,但可使CPU中断使能标志的状态在临界段前和临界段后不发生变化。 进入临界段前: (1) Push/save 中断状态保存到堆栈中 (2) Disable 关闭中断 退出临界段: (3) Pop/restore 恢复中断标志 3. 当CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL时 这种方法的前提是,用户使用的C编译器具有扩展功能。用户可获得程序状态字的值,这样就可把该值保存在C函数的局部变量中,而不必压到堆栈里。上面的宏定义就是采用的这种方式,也就是(1),(2)注释的地方。 4. 关于临界段,在文件os.h中也有几个相关的宏定义,这几个宏定义的含义会在后面跟大家讲 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN> 0u && defined(CPU_CFG_INT_DIS_MEAS_EN) #define OS_SCHED_LOCK_TIME_MEAS_START() OS_SchedLockTimeMeasStart() #else #define OS_SCHED_LOCK_TIME_MEAS_START() #endif
#if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u && defined(CPU_CFG_INT_DIS_MEAS_EN) #define OS_SCHED_LOCK_TIME_MEAS_STOP() OS_SchedLockTimeMeasStop() #else #define OS_SCHED_LOCK_TIME_MEAS_STOP() #endif
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u /* Deferred ISR Posts */ /* Lock the scheduler */ #define OS_CRITICAL_ENTER() \ do { \ CPU_CRITICAL_ENTER(); \ OSSchedLockNestingCtr++; \ if(OSSchedLockNestingCtr == 1u) { \ OS_SCHED_LOCK_TIME_MEAS_START(); \ } \ CPU_CRITICAL_EXIT(); \ } while (0) /* Lock the scheduler but re-enable interrupts*/ #define OS_CRITICAL_ENTER_CPU_EXIT() \ do { \ OSSchedLockNestingCtr++; \ \ if(OSSchedLockNestingCtr == 1u) { \ OS_SCHED_LOCK_TIME_MEAS_START(); \ } \ CPU_CRITICAL_EXIT(); \ } while (0)
/* Scheduling occurs only if an interruptoccurs */ #define OS_CRITICAL_EXIT() \ do { \ CPU_CRITICAL_ENTER(); \ OSSchedLockNestingCtr--; \ if(OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \ OS_SCHED_LOCK_TIME_MEAS_STOP(); \ if(OSIntQNbrEntries > (OS_OBJ_QTY)0) { \ CPU_CRITICAL_EXIT(); \ OS_Sched0(); \ } else { \ CPU_CRITICAL_EXIT(); \ } \ } else { \ CPU_CRITICAL_EXIT(); \ } \ } while (0)
#define OS_CRITICAL_EXIT_NO_SCHED() \ do { \ CPU_CRITICAL_ENTER(); \ OSSchedLockNestingCtr--; \ if(OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \ OS_SCHED_LOCK_TIME_MEAS_STOP(); \ } \ CPU_CRITICAL_EXIT(); \ } while (0)
#else /* Direct ISR Posts */
#define OS_CRITICAL_ENTER() CPU_CRITICAL_ENTER()
#define OS_CRITICAL_ENTER_CPU_EXIT()
#define OS_CRITICAL_EXIT() CPU_CRITICAL_EXIT()
#define OS_CRITICAL_EXIT_NO_SCHED() CPU_CRITICAL_EXIT()
#endif
|