FreeRtos临界段代码保护

临界段用一句话概括就是在执行程序的时候不能被中断的代码段。
那什么时候程序会被打断呢?
1、系统调度(Pendsv中断)
2、外部中断
因此FreeRtos对临界段的保护最终还是回到对中断的开关控制。
Cortex-M内核快速开关中断指令如下
在这里插入图片描述
在FreeRtos中 portmacro.h 文件中定义了如下对临界段保护的函数,实际是对BASEPRI的操作

#define portDISABLE_INTERRUPTS()				vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS()					vPortSetBASEPRI( 0 )
#define portSET_INTERRUPT_MASK_FROM_ISR()		ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)	vPortSetBASEPRI(x)
//凡是有FROM_ISR的都是在中断中使用的

关中断函数2个

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
	}
}
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;
}

开中断

//这个其实就是直接往BASEPRI写 0
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )//0
{
	__asm
	{
		/* Barrier instructions are not used as this function is only used to
		lower the BASEPRI value. */
		msr basepri, ulBASEPRI
	}
}
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 vPortEnterCritical( void )
{
	//进入临界段先关中断
	portDISABLE_INTERRUPTS();
	uxCriticalNesting++;

	/* This is not the interrupt safe version of the enter critical function so
	assert() if it is being called from an interrupt context.  Only API
	functions that end in "FromISR" can be used in an interrupt.  Only assert if
	the critical nesting count is 1 to protect against recursive calls if the
	assert function also uses a critical section. */
	if( uxCriticalNesting == 1 )
	{
		configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
	}
}

退出临界段函数

void vPortExitCritical( void )
{
	configASSERT( uxCriticalNesting );
	uxCriticalNesting--;
	if( uxCriticalNesting == 0 )
	{
		portENABLE_INTERRUPTS();
	}
}

总结:临界段其实就是中断的开关,只不过在中断中使用时,必须定义一个返回值,再出临界段的时候容易找回之前的中断优先级

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值