【FreeRTOS】中断与临界段

本文详细介绍了Cortex-M处理器的中断系统,包括中断简介、优先级配置和中断屏蔽寄存器的使用。此外,还深入探讨了FreeRTOS在中断管理中的应用,如相关宏配置和开关中断函数,并解析了临界段代码的实现及其用法,确保任务执行的连续性和安全性。
摘要由CSDN通过智能技术生成

目录

一、Cortex-M中断

1、中断简介

2、中断优先级

3、中断屏蔽寄存器

(1)PRIMASK和FAULTMASK寄存器

(2)BASEPRI寄存器(重点)

二、FreeRTOS的中断

1、相关宏配置

2、FreeRTOS开关中断

三、临界段代码

1、进入临界段函数

2、退出临界段

3、用法


一、Cortex-M中断

1、中断简介

        Cortex-M内核MCU提供了一个用于中断管理的嵌套向量中断控制器(NVIC),M3、M4的NVIC最多支持240个中断请求(IRQ)、一个不可屏蔽中断(NMI)、一个SysTick定时器中断和多个异常请求。可分为系统异常(编号1-15)和外部中断(编号大于等于16),具体详细如下表单:

2、中断优先级

       中断优先级越高(优先级数值越小),中断响应越及时。对于三个系统异常:复位、NMI和硬fault,它们的优先级是固定的,且都是负数,所以它们的优先级是最高的。

       每个中断都有一个8位的优先级配置寄存器,最少使用3位(8个优先级),最多使用8位(256个优先级)。具体使用多少位由芯片设计厂商决定,STM32使用的是4位(16个优先级)

       中断优先级又分为抢占优先级与亚优先级。只有高抢占优先级才能打断低抢占优先级的执行。对于同级别的抢占优先级中断,亚优先级高的先执行。用来表达优先级的8位可以分为两部分,高位部分表示抢占优先级,低位部分表示亚优先级。亚优先级至少有一位,因此抢占优先级最多只有128个。

       优先级分组配置在控制寄存器的位[10:8],该位写入几就是从第几位开始分组。不使用的位并不影响分组。

3、中断屏蔽寄存器

       与中断屏蔽相关的寄存器有三个:PRIMASK, FAULTMASK以及BASEPRI

(1)PRIMASK和FAULTMASK寄存器

        PRIMASK寄存器用于禁止除NMI和HardFalut外的所有异常和中断。

FAULTMASK寄存器用于禁止除NMI外的所有异常和中断。

(2)BASEPRI寄存器(重点)

        BASEPRI寄存器用于关闭除复位、NMI和HardFalut外的其他中断。可以设置屏蔽优先级阈值,高于这个阈值的中断将不被屏蔽,低于的将被屏蔽。只需将这个阈值写入BASEPRI寄存器即可,写入0就会停止屏蔽中断。(FreeRTOS的开关中断就是对这个寄存器进行操作的)

 

二、FreeRTOS的中断

1、相关宏配置

#define configPRIO_BITS                     4
//设置MCU使用几位表示优先级,STM32为4位

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY               0xf
//设置最低优先级,STM32用4位表示优先级,当中断优先级分组为组4时,4位都用来表示抢占优先级,
//所以共有16级,因此该宏为16-1=15。不同的MCU和不同的优先级分组对应该宏都不一样。

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY      5
//设置上面所讲的可屏蔽中断阈值,优先级数值低于该值的不会被屏蔽

#define configKERNEL_INTERRUPT_PRIORITY     \   
        ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//设置内核中断优先级,将最低优先级数值写入表达优先级的高4位(0xf<<(8-4))
//此宏用来设置PendSV和SysTick定时器中断的优先级port.c中:
#define portNVIC_PENDSV_PRI  ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
//设置PendSV和SysTick定时器中断的优先级,都为最低优先级

#define configMAX_SYSCALL_INTERRUPT_PRIORITY        \
        ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//此宏是将可屏蔽中断阈值写入表示优先级高4位,方便将其直接写入到对于寄存器中

2、FreeRTOS开关中断

开中断函数:portDISABLE_INTERRUPTS()

关中断函数:portENABLE_INTERRUPTS()

函数是两个宏:

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

开关中断具体实现函数:

/*关中断*/
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
 {
   uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; //阈值优先级的宏
   __asm
      {
         msr basepri, ulNewBASEPRI               //写入BASEPRI寄存器中(开启屏蔽中断)
         dsb
         isb
        }
}



/*开中断*/
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
  {
      __asm

     {
        msr basepri, ulBASEPRI       //写入BASEPRI寄存器中(传入0停止屏蔽中断)

     }

  }

三、临界段代码

       临界段代码也叫临界区,指那些必须完整运行,不能被打断的代码段。比如某些外设的驱动过程需要严格的时序,过程中不能被打断。进入临界段只需将能打断的中断关闭即可,推出临界段则打开中断即可。任务的切换在SysTick中断和PendSV中断作用下进行,进入临界段这两个中断将被屏蔽,因此不会进行任务切换。

1、进入临界段函数

两个函数都是宏:

#define taskENTER_CRITICAL()            portENTER_CRITICAL()              //任务级
#define taskENTER_CRITICAL_FROM_ISR()   portSET_INTERRUPT_MASK_FROM_ISR() //中断级

实现函数

void vPortEnterCritical( void ) //任务级
{
    portDISABLE_INTERRUPTS();        //关中断函数
    uxCriticalNesting++;

    if( uxCriticalNesting == 1 )
        {
         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
        }
}



//中断级函数是关中断的实现函数

2、退出临界段

两个函数都是宏:

#define taskEXIT_CRITICAL()              portEXIT_CRITICAL()     //任务级
#define taskEXIT_CRITICAL_FROM_ISR( x )  portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) //中断级

实现函数

void vPortExitCritical( void )  //任务级
{
    configASSERT( uxCriticalNesting );
    uxCriticalNesting--;

    if( uxCriticalNesting == 0 )
    {
        portENABLE_INTERRUPTS();     //开中断函数
    }

}



//中断级函数是开中断的实现函数

3、用法

        在需要进入临界段的程序前调用taskENTER_CRITICAL()进入临界段,程序执行结束后调用taskEXIT_CRITICAL()退出临界段。

注意:调用多少次函数taskENTER_CRITICAL()进入临界段,就要调用多少次函数taskEXIT_CRITICAL()退出临界段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值