freeRTOS源码解析3--port.c 1
源码目录:\FreeRTOS\portable\RVDS\ARM_CM4F\portmacro.h、\FreeRTOS\portable\RVDS\ARM_CM4F\port.c
1、先分析portmacro.h中的几个宏,基本都是汇编代码,还涉及一些cortex-m3/4的知识。
1.1 portYIELD
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
在Cortex M3与M4权威指南的7.9.1有关于该寄存器的描述,该寄存器处于系统控制块(SCB)中,CMSIS-Core符号为SCB->ICSR,系统异常的控制和状态。
每一位的描述如下图所示:
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL ) // 将SCB->ICSR的该位置位,如果当前没有更高优先级的中断的话,会立即触发pendSV中断,否则将会挂起。 #define portEND_SWITCHING_ISR( xSwitchRequired ) do { if( xSwitchRequired != pdFALSE ) portYIELD(); } while( 0 ) #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) /* Constants used with memory barrier intrinsics. */ #define portSY_FULL_READ_WRITE ( 15 )
#define portYIELD() \ { \ /* Set a PendSV to request a context switch. */ \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ \ /* Barriers are normally not required but do ensure the code is completely \ * within the specified behaviour for the architecture. */ \ __dsb( portSY_FULL_READ_WRITE ); \ __isb( portSY_FULL_READ_WRITE ); \ }
portYELD宏的作用就是触发一个pendSV中断。
1.2 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* */ } }
basepri是一个寄存器,其描述在手册7.10.3处,用于屏蔽中断优先级等于小于该寄存器值的中断。(Cortex M3与M4的中断优先级数值越小,优先级越高)
手册示例如下:
1.3 vPortRaiseBASEPRI
#define __NVIC_PRIO_BITS 4 #define configPRIO_BITS __NVIC_PRIO_BITS #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) 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. */ /* *INDENT-OFF* */ msr basepri, ulNewBASEPRI dsb isb /* *INDENT-ON* */ } }
configMAX_SYSCALL_INTERRUPT_PRIORITY = 5 << (8 - 4) = 0x50
此内联函数仍然是修改basepri,用于屏蔽0x50~0xFF的中断。
1.4 vPortClearBASEPRIFromISR
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void ) { __asm { /* Set BASEPRI to 0 so no interrupts are masked. This function is only * used to lower the mask in an interrupt, so memory barriers are not * used. */ /* *INDENT-OFF* */ msr basepri, # 0 /* *INDENT-ON* */ } }
basepri清0,并非屏蔽所有中断,其上电的默认值为0,含义是不屏蔽任何中断。
1.5 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. */ /* *INDENT-OFF* */ mrs ulReturn, basepri msr basepri, ulNewBASEPRI dsb isb /* *INDENT-ON* */ } return ulReturn; }
此内联函数除了屏蔽0x50~0xFF的中断外,还返回了修改之前的basepri的值。
1.6 xPortIsInsideInterrupt
static portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void ) { uint32_t ulCurrentInterrupt; BaseType_t xReturn; /* Obtain the number of the currently executing interrupt. */ __asm { /* *INDENT-OFF* */ mrs ulCurrentInterrupt, ipsr /* *INDENT-ON* */ } if( ulCurrentInterrupt == 0 ) { xReturn = pdFALSE; } else { xReturn = pdTRUE; } return xReturn; }
此内联函数使用到了ipsr寄存器,ipsr是psr的一部分,用于指示当前中断的中断号,0表示当前没有处理任何中断。
中断号下图所示: