00. 目录
01. 概述
临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS在进入临界端代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。FreeRTOS系统本身就有很多的临界段代码。这些代码都加了临界段代码保护,我们在写自己的用户程序的时候有些地方也需要添加临界段代码保护。
FreeRTOS与临界段代码保护有关的函数有4个:
/**
* task. h
*
* Macro to mark the start of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
* \ingroup SchedulerControl
*/
#define taskENTER_CRITICAL() portENTER_CRITICAL() //任务级
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() //中断级
/**
* task. h
*
* Macro to mark the end of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
* \ingroup SchedulerControl
*/
#define taskEXIT_CRITICAL() portEXIT_CRITICAL() //任务级
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) //中断级
02. 任务级临界区代码保护
taskENTER_CRITICAL()和taskEXIT_CRITICAL()是任务级的临界区代码保护,一个是进入临界区,一个是退出临界区,这两个函数一定要成对的使用。
/**
* task. h
*
* Macro to mark the start of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
* \ingroup SchedulerControl
*/
#define taskENTER_CRITICAL() portENTER_CRITICAL() //任务级
/**
* task. h
*
* Macro to mark the end of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
* \ingroup SchedulerControl
*/
#define taskEXIT_CRITICAL() portEXIT_CRITICAL() //任务级
portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定义,在portmacro.h中有定义。
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
vPortEnterCritical()和vPortExitCritical()函数实现如下:
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();
}
}
03.中断级临界区代码保护
taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()是中断级别临界区代码保护,是用在中断服务程序中的,而且这个中断的优先级一定要低于预先设置的值。
/**
* task. h
*
* Macro to mark the start of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
* \ingroup SchedulerControl
*/
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR() //中断级
/**
* task. h
*
* Macro to mark the end of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
* \ingroup SchedulerControl
*/
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) //中断级
在portmacro.h文件中有如下定义:
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vPortSetBASEPRI( x )
ulPortRaiseBASEPRI()和vPortSetBASEPRI()相关实现
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. */
/* *INDENT-OFF* */
msr basepri, ulBASEPRI
/* *INDENT-ON* */
}
}
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. */
/* *INDENT-OFF* */
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
/* *INDENT-ON* */
}
return ulReturn;
}
中断级临界区代码应用示例
04. 预留
05. 预留
06. 附录
6.1 【STM32】STM32系列教程汇总
07. 参考
《FreeRTOS Reference Manual》
《Using the FreeRTOS Real Time Kernel -A Practical Guide》
《The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors,3rd Edition》