三、FreeRTOS 临界段的保护

FreeRTOS

作者:解琛
时间:2020 年 8 月 19 日

[野火®]《FreeRTOS 内核实现与应用开发实战—基于STM32》

三、临界段的保护

3.1 临界段

临界段用一句话概括就是一段在执行的时候不能被中断的代码段。

在 FreeRTOS 里面,这个临界段最常出现的就是对全局变量的操作,全局变量就好像是一个枪把子,谁都可以对他开枪,但是我开枪的时候,你就不能开枪,否则就不知道是谁命中了靶子。

在进行系统调度和处理外部中断时,临界段会被打断。系统调度,最终也是产生 PendSV 中断,在 PendSV Handler 里面实现任务的切换,所以还是可以归结为中断。所以,FreeRTOS 对临界段的保护可以理解为对中断的开和关的控制。

3.2 Cortex-M 内核的中断指令

为了快速地开关中断, Cortex-M 内核专门设置了一条 CPS 指令,有 4 种用法。

CPSID   I    ;PRIMASK=1          ;关中断
CPSIE    I   ;PRIMASK=0          ;开中断
CPSID   F   ;FAULTMASK=1    ;关异常
CPSIE   F   ;FAULTMASK=0    ;开异常

Cortex-M 内核 里面三个中断屏蔽寄存器描述如下。

寄存器名称 描述
PRIMASK 这是个只有单一比特的寄存器。 在它被置 1 后,就关掉所有可屏蔽的异常,只剩下 NMI 和硬 FAULT 可以响应。它的缺省值是 0,表示没有关中断。
FAULTMASK 这是个只有 1 个位的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异常,甚至是硬 FAULT 也被关闭。它的缺省值也是 0,表示没有关异常。
BASEPRI 这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成 0,则不关闭任何中断, 0 也是缺省值。

在 FreeRTOS 中,对中断的开和关是通过操作 BASEPRI 寄存器来实现的,即大于等于 BASEPRI 的值的中断会被屏蔽,小于 BASEPRI 的值的中断则不会被屏蔽,不受FreeRTOS 管理。

3.3 关中断

FreeRTOS 关中断的函数在 portmacro.h 中定义,分无返回值和有返回值两种。

3.3.1 无返回值

在往 BASEPRI 写入新的值的时候,不用先将 BASEPRI 的值保存起来,即不用管当前的中断状态是怎么样的,既然不用管当前的中断状态,也就意味着这样的函数不能在中断里面调用。

/* 不带返回值的关中断函数,不能嵌套,不能在中断里面使用;*/
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
   
    uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

    /* configMAX_SYSCALL_INTERRUPT_PRIORITY 是 一 个 在 FreeRTOSConfig.h 中定义的宏,即要写入到 BASEPRI 寄存器的值。*/
    /* 该宏默认定义为 191,高四位有效,即等于 0xb0,或者是 11,即优先级大于等于 11 的中断都会被屏蔽,11 以内的中断则不受 FreeRTOS 管理。*/

	__asm
	{
   
		/* Set BASEPRI to the max syscall priority to effect a critical
		section. */
		msr basepri, ulNewBASEPRI

        /* 将 configMAX_SYSCALL_INTERRUPT_PRIORITY 的值写入 BASEPRI 寄存器,实现关中断(准确来说是关部分中断)。*/

		dsb
		isb
	
FreeRTOS提供了多种方法来保护临界资源,其中最常用的是使用任务间通信机制中的二值信号量(Binary Semaphore)或互斥量(Mutex)。这两种机制都可以用来保护临界资源,防止多个任务同时访问临界资源导致数据不一致或错误。 使用二值信号量时,可以将信号量的初始值设置为1,表示临界资源未被占用。当一个任务需要访问临界资源时,首先获取信号量,如果信号量的值为1,则表示临界资源未被占用,该任务可以访问临界资源;如果信号量的值为0,则表示临界资源已被占用,该任务需要等待直到信号量的值变为1才能访问临界资源。当任务访问完临界资源后,需要释放信号量,将其值设置为1,表示临界资源已经被释放。 使用互斥量时,可以将互斥量的初始值设置为1,表示临界资源未被占用。当一个任务需要访问临界资源时,首先获取互斥量,如果互斥量的值为1,则表示临界资源未被占用,该任务可以访问临界资源;如果互斥量的值为0,则表示临界资源已被占用,该任务需要等待直到互斥量的值变为1才能访问临界资源。当任务访问完临界资源后,需要释放互斥量,将其值设置为1,表示临界资源已经被释放。 需要注意的是,使用二值信号量或互斥量保护临界资源时,需要保证所有访问该临界资源的任务都使用同一个信号量或互斥量对象进行保护,否则会出现数据不一致或错误的情况。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

解琛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值