FreeRTOS之开关中断

来源:互联网 发布:js有没有boolean 编辑:程序博客网 时间:2024/06/08 12:08

1.Cortex-M3和M4的中断介绍
Cortex-M3和M4的NVIC最多支持240个IRQ(中断请求)、一个不可屏蔽中断(NMI)、一个SysTick(滴答定时器)定时器中断和多个系统异常。

2.Cortex-M3和M4中断屏蔽寄存器介绍
这里介绍的寄存器有3个:PRIMASK、FAULTMASK、BASEPRI
(1)PRIMASK寄存器
PRIMASK寄存器可以禁止除NMI和HardFault两个中断外的所有的异常和中断。

CPSIE I;                                        // 清除PRIMASK(使能中断)CPSID I;                                        // 设置PRIMASK(禁止中断)

多说一句,在uC/OS中就是通过该方式实现中断的使能和禁止。
(2)FAULTMASK寄存器
FAULTMASK寄存器会把异常的优先级提升到-1,除复位外,其他的异常和中断都能屏蔽掉。

CPSIE F;                        // 清除FAULTMASKCPSID F;                        // 设置FAULTMASK

(3)BASEPRI寄存器
该寄存器可以屏蔽低于某一个阈值的中断。
注意:FreeRTOS的开关中断就是操作BASEPRI寄存器来实现的,它可以关闭低于某个阈值的中断,高于这个阈值的中断就不会被关闭。

3.FreeRTOS中断配置宏
(1)configPRIO_BITS
此宏用来设置MCU使用几位优先级。
(2)configLIBRARY_LOWEST_INTERRUPT_PRIORITY
此宏用来设置最低优先级。
(3)configKEYNEL_INTERRUPT_PRIORITY
此宏是configLIBRARY_LOWEST_INTERRUPT_PRIORITY左移得来的。
此宏用来配置系统调用(PendSV)和滴答定时器(Systick)的中断优先级。
(4)configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
此宏用来设置FreeRTOS系统可管理的最大优先级,也就是BASEPRI寄存器中存放的阈值。
(5)configMAX_SYSCALL_INTERRUPT_PRIORITY
此宏是configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY左移得来的。

4.FreeRTOS开关中断
FreeRTOS开关中断的函数为portENABLE_INTERRUPTS()和portDISABLE_INTERRUPTS(),它们都是宏定义。
函数的定义位于portmacro.h中:

#define portDISABLE_INTERRUPTS()        vPortRaiseBASEPRI()             // 关中断#define portENABLE_INTERRUPTS()         vPortSetBASEPRI( 0 )            // 开中断

由以上可以看出开关中断其实是由函数vPortSetBASEPRI(0)和vPortRaiseBASEPRI()来实现的,函数的原型定义如下:

// 开中断// 向basepri中写入0就表示开中断static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI ){    __asm    {        msr basepri, ulBASEPRI    }}// 关中断// 向basepri中写入configMAX_SYSCALL_INTERRUPT_PRIORITY,// 表明优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断都会被屏蔽static portFORCE_INLINE void vPortRaiseBASEPRI( void ){uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;    __asm    {        msr basepri, ulNewBASEPRI        dsb        isb    }}

5.临界段代码
临界段代码也叫临界区,是指那些必须完整运行、不能被打断的代码段。
FreeRTOS在进入临界段代码的时候需要关闭中断,处理完临界段代码以后再打开中断。
FreeRTOS与临界段代码保护有关的函数有4个:taskENTER_CRITICAL()、taskEXIT_CIRTICAL()、taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()。这些函数其实是宏定义,在task.h中定义。前两个是任务级的临界代码段保护,后两个是中断级的临界代码段保护。
(1)任务级临界代码段保护
taskENTER_CRITICAL()是进入临界段,taskEXIT_CRITICAL()是退出临界段,定义如下:

#define taskENTER_CRITICAL()        portENTER_CRITICAL()    #define taskEXIT_CRITICAL()         portEXIT_CRITICAL()

portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定义,在文件portmacro.h中有定义,如下:

#define portENTER_CRITICAL()                    vPortEnterCritical()#define portEXIT_CRITICAL()                     vPortExitCritical()

函数vPortEnterCritical()和vPortExitCritical()在文件port.c中定义,如下:

// 进入临界段代码的时候调用void vPortEnterCritical( void ){    portDISABLE_INTERRUPTS();                     // 关闭中断    uxCriticalNesting++;                          // uxCriticalNesting是一个全局变量,用来记录嵌套次数的。    if( uxCriticalNesting == 1 )    {        configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );    }}// 退出临界段代码的时候调用void vPortExitCritical( void ){    configASSERT( uxCriticalNesting );    uxCriticalNesting--;    if( uxCriticalNesting == 0 )    {        portENABLE_INTERRUPTS();                  // 打开中断    }}

(2)中断级临界段代码保护
函数taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()为中断级临界段代码保护函数,用在中断服务程序中,而且这个中断优先级一定要低于configMAX_SYSCALL_INTERRUPT_PRIORITY。这两个函数在文件task.h中定义。

#define taskENTER_CRITICAL_FROM_ISR()       portSET_INTERRUPT_MASK_FROM_ISR()#define taskEXIT_CRITICAL_FROM_ISR( x )     portCLEAR_INTERRUPT_MASK_FROM_ISR( x )

函数portSET_INTERRUPT_MASK_FROM_ISR()和port_CLEAR_INTERRUPT_MASK_FROM_ISR()在portmacro.h中定义,如下:

#define portSET_INTERRUPT_MASK_FROM_ISR()       ulPortRaiseBASEPRI()#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)    vPortSetBASEPRI(x)

函数ulPortRaiseBASEPRI()在portmacro.h中定义,如下:

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void ){uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;    __asm    {        mrs ulReturn, basepri                     // 读出basepri的值,放入ulReturn        msr basepri, ulNewBASEPRI                 // 将configMAX_SYSCALL_INTERRUPT_PRIORITY的值写入                                                  // basepri中        dsb        isb    }    return ulReturn;                              // 返回ulReturn}
原创粉丝点击