FreeRTOS资源管理

1.以前临界资源的保护方式

有使用过静态局部变量来保护临界资源,也有用队列,信号量,互斥量来保护临界资源。这些都是在多个任务会共同使用临界资源的情况下我们的保护方式。

问题提出:如果有个传感器在读取数据时有严格的时序,如果在读取数据中途被打断,就会读取错误,为了防止这一过程被打断我们会进行一些管理(关闭中断或调度器)。

1.2队列,信号量/互斥量,事件组,任务通知内部如何实现互斥的?

核心就是谁跟我抢我就屏蔽谁,中断抢我就屏蔽中断,任务要抢我就进制调度器。什么意思呢?举两个例子。

1.2.1队列例子:

我们可以在中断里去写队列,也可以在任务里写队列,所以在写队列的函数里一定是去关闭中断的。我们要知道调度器切换任务也是基于中断的,我只关闭所有中断就可以达到防止任务和中断抢。因此写队列里一定是去关闭中断的。要注意的是关闭中断前先要记录当前中断的状态,再关闭中断,之后在根据记录的当前状态去恢复中断的状态。

写队列源码分析:

中断写队列

从图中可以看出在中断中写队列先记录当前中断状态,在返回中断状态的函数里执行了关闭中断的操作。在第二张图中是xQueueGenericSendFromISR()函数末尾执行的一个恢复中断的一个函数。

任务写队列:

1.2.2事件组例子:

没有中断参与的我们只需要关闭调度器即可,比如事件组,事件组也有在中断中写事件组的函数为什么是关闭调度器呢?

在写事件组函数内部去写一个Timer队列,然后去守护任务会去唤醒定时器任务,在任务里去写事件值。虽然他是在中断中执行的,但是本质是去唤醒一个任务在任务中进行操作我们只需要停止调度器即可无需关中断。

​​

2.如何去关闭中断,如何去关闭调度器?

关闭中断:

关闭中断就是去操作某个寄存器。

关闭调度器:

设置一个变量,把这个变量++,根据这个变量是否为0,去判断是否要切换任务。

切换上下文, 加了之后这个变量就不等于0,就不进行切换。else才是执行任务切换。

2.1在任务中屏蔽中断

在任务中屏蔽中断的示例代码如下:

复制代码
/* 在任务中,当前时刻中断是使能的
 * 执行这句代码后,屏蔽中断
 */
taskENTER_CRITICAL();

/* 访问临界资源 */

/* 重新使能中断 */
taskEXIT_CRITICAL();

taskENTER_CRITICA()/taskEXIT_CRITICAL() 之间:

  • 低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
  • 高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
    • 但是,这些中断ISR里,不允许使用FreeRTOS的API函数
  • 任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生

这套 taskENTER_CRITICA()/taskEXIT_CRITICAL() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为0时,调用 taskEXIT_CRITICAL() 才会重新使能中断。

使用 taskENTER_CRITICA()/taskEXIT_CRITICAL() 来访问临界资源是很粗鲁的方法:

  • 中断无法正常运行
  • 任务调度无法进行
  • 所以,之间的代码要尽可能快速地执行

2.2 在ISR中屏蔽中断

要使用含有"FROM_ISR"后缀的宏,示例代码如下:

复制代码
void vAnInterruptServiceRoutine( void )
{
    /* 用来记录当前中断是否使能 */
    UBaseType_t uxSavedInterruptStatus;
    
    /* 在ISR中,当前时刻中断可能是使能的,也可能是禁止的
     * 所以要记录当前状态, 后面要恢复为原先的状态
     * 执行这句代码后,屏蔽中断
     */
    uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
    
    /* 访问临界资源 */

    /* 恢复中断状态 */
    taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
    /* 现在,当前ISR可以被更高优先级的中断打断了 */
}

taskENTER_CRITICA_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR() 之间:

  • 低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
  • 高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
    • 但是,这些中断ISR里,不允许使用FreeRTOS的API函数
  • 任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生

2.3 暂停调度器

如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务运行,但是这代价太大了。它会影响到中断的处理。

如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,中断还是可以发生、处理。

使用这2个函数来暂停、恢复调度器:

复制代码
/* 暂停调度器 */
void vTaskSuspendAll( void );

/* 恢复调度器
 * 返回值: pdTRUE表示在暂定期间有更高优先级的任务就绪了
 *        可以不理会这个返回值
 */
BaseType_t xTaskResumeAll( void );

示例代码如下:

复制代码
vTaskSuspendScheduler();

/* 访问临界资源 */

xTaskResumeScheduler();

这套 vTaskSuspendScheduler()/xTaskResumeScheduler() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为0时,调用 taskEXIT_CRITICAL() 才会重新使能中断。

3.总结

在使用临界资源时,需要严格的读取时序图时我们的管理方式为,在中断中我们就先关闭中断,在任务中我们就暂停调度器,除此之外互斥操作尽可能是使用信号量,互斥量来实现。

相关推荐
LS_learner3 分钟前
ros2中的话题、订阅、发布和服务简介
嵌入式硬件
Digitally1 小时前
如何通过 5 种方法轻松格式化 USB 驱动器
stm32·单片机·嵌入式硬件
三佛科技-134163842121 小时前
HN20N03快充用MOS管30V20A(20N03)应用分析
单片机·嵌入式硬件·智能家居·pcb工艺
qq_385507452 小时前
指针用法-指针解引用
单片机
BT-BOX2 小时前
STM32各系列芯片编译支持包 Pack下载
stm32·单片机·嵌入式硬件
麦托团子2 小时前
51单片机学习笔记5-模块化编程
单片机·嵌入式硬件
jiang153237942433 小时前
NUC977DK63YC 新唐 ARM9
arm开发·嵌入式硬件
夜月yeyue3 小时前
Netlink 套接字详解
linux·运维·服务器·网络·单片机·uboot
llilian_163 小时前
NTP时间同步服务器 卫星时钟同步服务器在气象监测方向的深度应用 授时服务器
服务器·功能测试·单片机·嵌入式硬件·测试工具
代码游侠3 小时前
学习笔记——嵌入式系统通信基础及串口开发
运维·arm开发·笔记·单片机·嵌入式硬件·学习