临界段用一句话概括就是在执行程序的时候不能被中断的代码段。
那什么时候程序会被打断呢?
1、系统调度(Pendsv中断)
2、外部中断
因此FreeRtos对临界段的保护最终还是回到对中断的开关控制。
Cortex-M内核快速开关中断指令如下

在FreeRtos中 portmacro.h 文件中定义了如下对临界段保护的函数,实际是对BASEPRI的操作
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
//凡是有FROM_ISR的都是在中断中使用的
关中断函数2个
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;//可配置的中断优先级
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
msr basepri, ulNewBASEPRI//传入之后,中断优先级编号大于的都被屏蔽
dsb
isb
}
}
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
mrs ulReturn, basepri //先把之前的中断编号保存起来
msr basepri, ulNewBASEPRI //关中断
dsb
isb
}
return ulReturn;
}
开中断
//这个其实就是直接往BASEPRI写 0
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )//0
{
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
//把上一次保存在返回值里的数传进去,恢复之前的状态
__asm
{
/* Barrier instructions are not used as this function is only used to
lower the BASEPRI value. */
msr basepri, ulBASEPRI
}
}
进入临界段相关函数
void vPortEnterCritical( void )
{
//进入临界段先关中断
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
/* 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();
}
}
总结:临界段其实就是中断的开关,只不过在中断中使用时,必须定义一个返回值,再出临界段的时候容易找回之前的中断优先级
本文详细介绍了FreeRTOS如何通过Cortex-M内核的快速开关中断指令来保护临界段,防止系统调度和外部中断打断执行。主要涉及了portmacro.h文件中的中断开关函数,如portDISABLE_INTERRUPTS()和portENABLE_INTERRUPTS(),以及在中断中使用的FROM_ISR版本函数。在进入和退出临界段时,系统会通过调整BASEPRI寄存器来控制中断状态,并使用uxCriticalNesting计数器防止递归进入临界段。
753

被折叠的 条评论
为什么被折叠?



