临界段保护
- 普通关中断:在
portmacro.h里通过操作 BASEPRI寄存器 来实现,用portDISABLE_INTERRUPTS() - 带返回值的关中断:在中断中使用,临界段保护也要分级,有的低优先级中断不能打断,高优先级可以碰,还有的高优先级也不能打断,但是BASEPRI只有一个,所以需要那个东西存一下,用
portDISABLE_INTERRUPTS_MASK_FROM_ISR() - 进临界段 : 就临界段嵌套计数(port.c)+1,加上
portDISABLE_INTERRUPTS(),代码放文末 - 带中断保护版本进临界段 :定义一个变量保存一下BASEPRI,然后用
portDISABLE_INTERRUPTS_MASK_FROM_ISR(),代码放文末
进临界段 — port.c(带嵌套计数)
任务上下文用 taskENTER_CRITICAL()/taskEXIT_CRITICAL()(宏链:taskENTER_CRITICAL → portENTER_CRITICAL → vPortEnterCritical)。嵌套计数保证「多次进入、只在最外层退出时开一次中断」:
/* 故意给非法初值:没进就退,计数变成 0xaaaaaaa9,configASSERT 必抓 */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* 只在嵌套计数 == 1 时断言:防止断言函数自身进临界段导致递归误报 */
if( uxCriticalNesting == 1 )
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
}
}
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting );
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}中断保护版本进临界段
中断里不能用带嵌套计数的版本(会破坏别处中断现场),改成「定义变量接住旧 BASEPRI,退出时用旧值恢复」:
/* task.h 里的映射 */
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )/* 中断里的用法 */
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); /* 关中断 + 存旧 BASEPRI */
{
/* 临界区代码:访问与任务共享的数据 */
}
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); /* 用旧值恢复 */