目录
临界段代码保护简介
临界段代码保护函数介绍
任务级临界区函数详解
中断级临界区函数详解
临界段代码保护简介
什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段
适用场合如:
1.外设:需严格按照时序初始化的外设:IIC、SPI等等
2.系统:系统自身需求
3.用户:用户自身需求
什么时候可以打断当前程序的运行?
中断、任务调度
临界段代码保护函数介绍
FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断(注意是FreeRTOS管理的中断)
本质上和就是调用中断管理的开关中断那2个函数,只不过多了一个嵌套计数器
任务级临界区调用格式示例:
中断级临界区调用格式示例:
特点:
1.成对使用
2.支持嵌套
3.尽量保持临界段耗时短
4.强悍:临界区是直接屏蔽了中断,系统任务调度靠中断,ISR也靠中断
任务级临界区函数详解
进入临界区
#define taskENTER_CRITICAL() portENTER_CRITICAL() //任务级进入临界区
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()//中断级进入临界区
#define portENTER_CRITICAL() vPortEnterCritical()
void vPortEnterCritical( void )
{
/*关中断(关FreeRTOS管理的中断)*/
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 );
}
}
退出临界区
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define portEXIT_CRITICAL() vPortExitCritical()
void vPortExitCritical( void )
{
/*提示语句*/
configASSERT( uxCriticalNesting );
/*临界区嵌套变量*/
uxCriticalNesting--;
/*变量等于0的时候开中断*/
if( uxCriticalNesting == 0 )
{
/*开中断*/
portENABLE_INTERRUPTS();
}
}
中断级临界区函数详解
进入临界区
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
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;
}
退出临界区
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
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
}
}