uCOS-II和III主要是下面四种情况:
#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
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)注释的地方。 ================================================================================ 对于FreeRTOS临界区的处理代码有两个,一个是任务里面的临界区处理,另一个是中断里面的临界区处理,下面是任务里面临界区处理 #define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
================================================================
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
/*--------------------------------------------------------------------------------------------------------*/
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
} ===================================================================== 下面是是中断里面的临界区处理,其实这个方式跟uCOS的方式CPU_CRITICAL_METHOD_STATUS_LOCAL 基本一样。 #define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) ---------------------------------------------------------------------------------------------- __asm uint32_t ulPortSetInterruptMask( void ) { PRESERVE8
mrs r0, basepri mov r1, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r1 bx r14 } /*-----------------------------------------------------------*/ __asm void vPortClearInterruptMask( uint32_t ulNewMask ) { PRESERVE8
msr basepri, r0 bx r14 } ==================================================================== 其实不论是uCOS或者FreeRTOS为什么要采用这种方式处理临界区,直接开关中断不就可以了么,主要还是因为我们 直接的开关中断方式不支持在开关中断之间的代码的里面再次执行开关中断的嵌套处理,假如当前我们的代码是关闭 中断的,嵌套了一个含有开关中断的临界区代码后,退出时中断就成开的了,这样就出问题了。 |