FreeRtos临界段代码保护

本文详细介绍了FreeRTOS如何通过Cortex-M内核的快速开关中断指令来保护临界段,防止系统调度和外部中断打断执行。主要涉及了portmacro.h文件中的中断开关函数,如portDISABLE_INTERRUPTS()和portENABLE_INTERRUPTS(),以及在中断中使用的FROM_ISR版本函数。在进入和退出临界段时,系统会通过调整BASEPRI寄存器来控制中断状态,并使用uxCriticalNesting计数器防止递归进入临界段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

临界段用一句话概括就是在执行程序的时候不能被中断的代码段。
那什么时候程序会被打断呢?
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();
	}
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值