FreeRTOS基础(三):中断优先级配置和临界区

一、STM32中断优先级

1.1  Cortex-M有3个固定优先级(Reset、NMI、Hard Fault 优先级为负数)和256个可以编程优先级,最多128个抢占优先级。而STM32拥有16个优先级即高4bit,此为IC设计即硬件决定。

          

优先级分组:AIRCR寄存器配置PRIGROUP段位。

STM32支持5组优先级分组设置:

1.2  中断优先级配置,函数原型如下:SCB->AIRCR

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
  
  /* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
  NVIC_SetPriorityGrouping(PriorityGroup);
}

core_cm4.h下:
#define NVIC_SetPriorityGrouping    __NVIC_SetPriorityGrouping

__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  uint32_t reg_value;
  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);             /* only values 0..7 are used          */

  reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */
  reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change               */
  reg_value  =  (reg_value                                   |
                ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
                (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos)  );              /* Insert write key and priority group */
  SCB->AIRCR =  reg_value;
}

二、FreeRTOS里中断优先级配置

2.1  几个相关的定义

#define configPRIO_BITS         4
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5      //系统可屏蔽阈值优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15           //最低优先级即15
#define configKERNEL_INTERRUPT_PRIORITY       (                 configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
                                                               //内核优先级配置,0xF0
#define configMAX_SYSCALL_INTERRUPT_PRIORITY  (             
              configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
                                                               //内核可以管理中断等级

以下截图来自ALIENTEK的《STM32F103 FreeRTOS开发手册V1.1》

 2.2  SysTick和PendSV中断触发会引发系统调度,固需要将配置PendSV和SysTick的中断优先级设定为最低级别。

 portNVIC_SYSPRI2_REG的地址  0xe000ed20 + 2即PendSV的优先级,固左移16bit

 portNVIC_SYSPRI2_REG的地址  0xe000ed20 + 3即SysTick的优先级, 固左移24bit


#define portNVIC_SYSPRI2_REG				( * ( ( volatile uint32_t * ) 0xe000ed20 ) )

#define portNVIC_PENDSV_PRI	 ((( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ((( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )

BaseType_t xPortStartScheduler( void )
{
    .......
	/* Make PendSV and SysTick the lowest priority interrupts. */
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
    
    .......
}

三、临界区(运行过程不能被打断,如某些时序要求比较严格的通信)

#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 )

 3.1  任务级临界代码段保护

执行临界区的代码一定要精简,避免进入临界区后(中断关闭后),中断优先级在系统管控范围内即低于configMAX_SYSCALL_INTERRUPT_PRIORITY(<=5)的中断得不到及时响应。优先级>5的中断不受系统管控。

/******************************进入临界区***********************************/
void vPortEnterCritical( void )
{
	portDISABLE_INTERRUPTS();                //关中断
	uxCriticalNesting++;

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

//关中断,给BASEPRI写configMAX_SYSCALL_INTERRUPT_PRIORITY即0x50,则优先级<=5的中断被屏蔽


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. */
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}



/***************************退出临界区****************************************/

void vPortExitCritical( void )
{
	configASSERT( uxCriticalNesting );
	uxCriticalNesting--;
	if( uxCriticalNesting == 0 )
	{
		portENABLE_INTERRUPTS();            //使能中断,需要全局计数值为0
	}
}


//开中断,给BASEPRI写0

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. */
		msr basepri, ulBASEPRI
	}
}

3.2  中断级临界代码段保护

中断服务函数(该中断优先级必须低于configMAX_SYSCALL_INTERRUPT_PRIORITY)中使用临界区代码保护。

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. */
		mrs ulReturn, basepri
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}

	return ulReturn;
}


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. */
		msr basepri, ulBASEPRI
	}
}

  使用方法:

   void XXX_IRQHandler(void)

   { 

            ......

            value = taskENTER_CRITICAL_FROM_ISR();        //进入临界区

            .......

            taskEXIT_CRITICAL_FROM_ISR( value );          //退出临界区

    }

注意:在保证成对使用的情况下,通过保存和恢复寄存器 basepri 的数值可以实现中断嵌套,作用与使用全局中断嵌套计数值一致。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值