芯 片: STM32F427VITx
指 令 集: ARMV7、Thumb2
编译环境: arm gcc
FreeRTOS有如下临界节管理的宏定义。
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI() // 设置中断标志位
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x) // 清除中断标志位
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() // 禁止中断
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0) // 允许中断
#define portENTER_CRITICAL() vPortEnterCritical() // 进入临界
#define portEXIT_CRITICAL() vPortExitCritical() // 退出临界
/*
* 预备知识:
*/
特殊功能寄存器
程序状态字寄存器组(PSRs)
中断屏蔽寄存器组(PRIMASK, FAULTMASK, BASEPRI)
控制寄存器(CONTROL)
寄存器 功能
xPSR 记录 ALU标志(0标志,进位标志,负数标志,溢出标志),执行状态,以及当前正服务的中断号
PRIMASK 除能所有的中断,但不可屏蔽中断(NMI)无效
FAULTMASK 除能所有的 fault,但NMI依然不受影响
BASEPRI 除能所有优先级不高于某个具体数值的中断。
CONTROL 定义特权状态,并且决定使用哪一个堆栈指针
指令
MRS <gp_reg>, <special_reg> ; 读特殊功能寄存器的值到通用寄存器
MSR <special_reg>, <gp_reg> ; 写通用寄存器的值到特殊功能寄存器
DMB 数据存储器隔离。DMB 指令保证仅当所有在它前面的存储器访问操作都执行完毕后,才提交在它后面的存储器访问操作
DSB 数据同步隔离。比 DMB 严格,仅当所有在它前面的存储器访问操作都执行完毕后,才执行在它后面的指令
ISB 指令同步隔离。最严格,它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
屏蔽寄存器组
名字 功能描述
PRIMASK 这是个只有单一比特的寄存器。在它被置 1 后,就关掉所有可屏蔽的异常,只剩下NMI和硬fault可以响应。
它的缺省值是0,表示没有关中断。
FAULTMASK 这是个只有1个位的寄存器。当它置1时,只有NMI才能响应,所有其它的异常,甚至是硬fault,也通通闭嘴。
它的缺省值也是0,表示没有关异常。
BASEPRI 这个寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,
所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,
0也是缺省值。
各函数代码如下
/*
* portable/gcc/arm_cm4f/portmacro.h
*/
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
( 5 << ( 8 - 3)) = 0xA0
portFORCE_INLINE static uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
__asm volatile
(
" mrs %0, basepri \n" \ ; 把 basepri 值读到ulOriginalBASEPRI. mrs r0, basepri
" mov %1, %2 \n" \ ; ulNewBASEPRI = 0xA0
" msr basepri, %1 \n" \ ; 把0xA0写入basepri
" isb \n" \
" dsb \n" \
:"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
/* This return will not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
{
__asm volatile
(
" msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory" ; 给 basepri 设定一个值
);
}
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \ ; ulNewBASEPRI = 0xA0
" msr basepri, %0 \n" \ ; basepri = 0xA0
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*
* portable/gcc/arm_cm4f/port.c
*/
#define portNVIC_INT_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed04 ) ) // 中断控制及状态寄存器ICSR
#define portVECTACTIVE_MASK ( 0xFFUL )
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 ) // 仅当临界嵌套计数为1时才断言,以防止递归调用
{
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); // 当前活动的ISR编号,0:无活动ISR
}
}
void vPortExitCritical( void )
{
configASSERT( uxCriticalNesting ); // 临界嵌套计数不为0
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS(); // 允许中断
}
}
/*
* 进一步封装
*/
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}