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表示当前没有处理任何中断。

 

 中断号下图所示:

 

 

 

posted @ 2022-09-30 11:20  freeManX1807  阅读(1022)  评论(0编辑  收藏  举报