FreeRTOS基础学习

news2024/11/17 7:48:37
一、学习资源
1、正点原子免费教学视频: 原子哥,专注电子技术教学
2、FreeRTOS官方网站: FreeRTOS - Market leading RTOS (Real Time Operating System) for embedded systems with Internet of Things extensions
3、PPT与源码资料:在"FreeRTOS资料"目录里。
二、FreeRTOS基本介绍
1、FreeRTOS简介
        是一个 免费的 嵌入式 实时操作系统;属于 轻量级小系统,核心代码9000行左右,包含在3个.c文件中;软件实现优先级数量不限,硬件优先级受CPU限制, 任务优先级值越大则越高;可以创建不限数量的任务,但要考虑堆栈内存资源;支持 抢占式、协程式、时间片流转 等任务调度算法。
///
2、FreeRTOS基础知识
任务调度简介
        调度器就是使用相关的调度算法来决定当前需要执行的哪个任务,FreeRTOS一共支持 三种任务调度方式
① 抢占式调度:主要是针对 优先级不同的任务,每个任务都有一个优先级,优先级高的任务可以抢占优先级低的任务。
② 时间片调度:主要针对 优先级相同的任务,当多个任务的优先级相同时,任务调度器会在 每一次系统时钟节拍到的时候切换任务( sysTick的中断时间可设置)。
③ 协程式调度当前执行任务将会 一直运行,同时高优先级的任务 不会抢占低优先级任务( FreeRTOS现在虽然还支持,但已经不再更新这种调度算法了)。
任务状态
① 运行态:正在执行的任务,该任务就处于运行态, 同一个时间仅有一个任务处于运行态
② 就绪态:如果该任务已经 能够被执行,但当前 还未被执行,那么该任务处于就绪态;
③ 阻塞态:如果一个任务因 延时或等待外部事件发生,那么这个任务就处于阻塞态;
④ 挂起态类似暂停,调用函数 vTaskSuspend()进入 挂起态,需要调用 vTaskResume()函数来解挂进入 就绪态;
任务状态转换图
        除了运行态,其他的任务状态都有其 任务状态列表
① 就绪列表(哈希表):pxReadyTasksLists[x],其中x代表任务优先级数值,每个优先级对应32位变量的一个位(bit=1代表该优先级有就绪的任务);
② 阻塞列表:pxDelayedTaskList;
③ 挂起列表:xSuspendedTaskList;
///
3、FreeRTOS的下载
        直接从官网上点击“下载”后,默认选择最新的版本即可。
///
4、FreeRTOS源码文件结构解析
        
FreeRTOS内核目录:./FreeRTOS
① Demo:FreeRTOS演示例程;(主要)
② License:FreeRTOS相关许可;
③ Source:FreeRTOS源码;(核心)
④ Test:公用以及移植层测试代码;
内核源码的Demo文件夹:./FreeRTOS/Demo
        提供各种CPU架构和不同厂家SOC的移植例程。
内核源码的Source文件夹:./FreeRTOS/Source
① include目录:包含了FreeRTOS的头文件,必须添加;
② portable目录:包含了FreeRTOS的移植文件,必须添加;
③ croutine.c文件:协程调度相关,可以选择性使用;
④ event_groups.c文件:事件触发相关,可以选择;
⑤ list.c文件:列表实现相关文件,必须添加;
⑥ queue.c文件:队列实现相关,必须添加;
⑦ stream_buffer.c文件:流式缓冲区相关文件,可以选择;
⑧ tasks.c文件:任务处理相关文件,必须添加;
⑨ timers.c文件:软件定时器实现相关,可以选择;
软硬件桥梁portable目录:./FreeRTOS/Source/portable
        portable目录提供的FreeRTOS与不同硬件平台的连接桥梁, 实现FreeRTOS可移植的关键对于STM32这种ARM架构来讲,实际上使用到的是图片中的红圈内容
① Keil:我们使用的开发平台,它还指向RVDS;
② RVDS:不同内核芯片的移植文件;
③ MemMang:内存管理文件;
///
三、FreeRTOS的移植
1、基于正点原子STM32F103开发平台
        这里并没有说明FreeRTOS的原理,只是通过移植过程去 感性体验了一下FreeRTOS系统。移植的具体过程可以参考正点原子提供的 《FreeRTOS开发指南》第二章; 下面是本次移植过程的个人总结
① 需要在工程中添加 FreeRTOS的源码 以及 板级支持.c文件 ;
设备驱动其实还是需要 自己编写实现的,也可以利用HAL库函数;
③ 对于 sysTick中断,需要添加FreeRTOS提供的的回调函数;因为FreeRTOS是通过sysTick来实现周期任务切换的;
④ FreeRTOS源码已经 实现了svc中断和PandSV中断,所以必须 删除其他地方的实现
⑤ FreeRTOS其实 只是提供的多任务算法和内存管理算法,其他都需要自己开发;
///
2、基于华大CPU的系统移植( 揉面机项目
过程讲解
① 需要移植FreeRTOS的源码文件到工程目录中,包括与内核相关的文件;
FreeRTOSConfig.h文件中的 中断、堆内存、系统时钟频率、空闲任务栈空间以及任务优先级方式等,需要根据MCU实际资源来配置;
③ 本次实验发现,需要 修改FreeRTOS源码中 对systick的 配置宏portNVIC_SYSTICK_CLK_BIT_CONFIG,可能因为内核M0和M3不一样吧( 选择时钟源不一样!!);
④ 试验中发现, 只允许使用 软件优先级来管理任务,无法使用硬件优先级;
从任务调度上来说软件优先级不再依靠32位的变量bit位,而是 循环从高到低 检查 对应就绪列表是否为空,第一个不为空的就是目前最高优先级任务;取出其中一个任务控制块作为新的任务,随后记录目前最高优先级;
对于新建任务来说,每次添加 新的任务都需要 和历史最高优先级做对比
⑦ 如果 .s文件 中有 复位向量表与中断控制器 的相关指令, 请屏蔽
///
3、基于STM32G0的移植( 端子机项目
过程讲解
① 根据应用需求的不同,这里的 硬件设备扫描任务优先级要 大于 应用逻辑
② 由于应用上使用了 TIM1发送脉冲中断,且此中断需要保证即时响应,所以必须 脱离FreeRTOS的管理
///
四、FreeRTOS的系统配置文件
1、参考资料
① 官方文档: FreeRTOS - The Free RTOS configuration constants and configuration options - FREE Open Source RTOS for small real time embedded systems
② 正点原子提供: 《FreeRTOS开发指南》第三章;
2、基本配置项的了解: 
        使用FreeRTOS系统的工程,必须在工程中创建一个对应的配置文件: FreeRTOSConfig.h;该文件提供 各种全局宏定义来 选择性编译FreeRTOS源码 以及 为工程提供系统相关参数;配置文件中的 宏定义主要 分为三大类:config、INCLUDE 和 其他配置项。
        下面基于 正点原子提供的 STM32F103 案例中的配置文件,其他芯片可以基于此案例来修改:
3、与FreeRTOS中断相关的配置项
        在配置FreeRTOS的中断配置项之前,需要先知道使用的SOC的中断管理资源;以下是 FreeRTOS中断有关配置项的简介
① configPRIO_BITS:此宏是用于辅助配置的宏,主要用于辅助配置宏configKERNEL_INTERRUPT_PRIORITY 和宏configMAX_SYSCALL_INTERRUPT_PRIORITY 的;此宏 应定义为 MCU 8 位优先级配置寄存器实际使用的位数;因为STM32 只使用到了中断优先级配置寄存器的高4 位,因此,此宏应配置为4。
② configLIBRARY_LOWEST_INTERRUPT_PRIORITY:此宏是用于辅助配置宏configKERNEL_INTERRUPT_PRIORITY 的,此宏 应设置为 MCU 的最低优先等级;因为STM32 只使用了中断优先级配置寄存器的高4 位,因此MCU 的最低优先等级就是2^4-1=15,因此,此宏应配置为15。
③ configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY:此宏是用于辅助配置宏configMAX_SYSCALL_INTERRUPT_PRIORITY 的;此宏 适用于配置 FreeRTOS 可管理的最高优先级的中断,此功能就是 操作 BASEPRI 寄存器来实现的;此宏的值可以根据用户的实际使用场景来决定。
④ configKERNEL_INTERRUPT_PRIORITY:此宏应配置为MCU 的最低优先级在中断优先级配置寄存器中的值, FreeRTOS 的源码中,使用此宏将 SysTick PenSV 的中断优先级设置为最低优先级;因为STM32 只使用了中断优先级配置寄存器的高4 位,因此,此宏应配置为最低中断优先级在中断优先级配置寄存器高4 位的表示,即(configLIBRARY_LOWEST_INTERRUPT_PRIORITY<<(8-configPRIO_BITS))。
⑤ configMAX_SYSCALL_INTERRUPT_PRIORITY:此宏 用于配置 FreeRTOS 可管理的最高优先级的中断,在 FreeRTOS 的源码中,使用此宏来打开和关闭中断;因为STM32 只使用了中断优先级配置寄存器的高4 位,因此,此宏应配置为(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY<<(8-configPRIO_BITS))。
⑥ configMAX_API_CALL_INTERRUPT_PRIORITY此宏为宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 的新名称,只被用在FreeRTOS 官方一些新的移植当中;此宏与宏configMAX_SYSCALL_INTERRUPT_PRIORITY 是等价的。
五、FreeRTOS任务基础知识
1、FreeRTOS 任务控制块
        FreeRTOS中 每一个已创建任务都包含 一个任务控制块任务控制块是一个结构体变量,FreeRTOS用任务控制块结构体存储任务的属性( typedef struct tskTaskControlBlock)。FreeRTOS的任务控制块结构体中包含了很多成员变量,但是,大部分的 成员变量都是可以通过 FreeRTOSConfig.h 配置文件中的配置项宏定义进行裁剪的。
2、FreeRTOS 创建和删除任务 相关API函数
1、动态方式创建任务
        此函数用于使用动态的方式创建任务,任务的任务控制块以及任务的栈空间所需的内存,均由FreeRTOS从FreeRTOS管理的堆中分配,若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 configSUPPORT_DYNAMIC_ALLOCATION 配置为 1;此函数创建的任务会立刻进入就绪态,由任务调度器调度运行; 函数原型如下所示
函数返回值
2、静态方式创建任务
        此函数用于使用静态的方式创建任务,任务的任务控制块以及任务的栈空间所需的内存,需要由用户分配提供,若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 configSUPPORT_STATIC_ALLOCATION 配置为 1;此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。 函数原型如下所示
函数返回值
3、任务的删除
        此函数用于删除已被创建的任务,被删除的任务将被从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除; 要注意的是,空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存,则需要由用户在任务被删除前提前释放,否则将导致内存泄露;若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 INCLUDE_vTaskDelete 配置为 1函数原型如下所示
3、FreeRTOS 任务的挂起和恢复 相关API函数
1、挂起任务
        此函数用于挂起任务,若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 INCLUDE_vTaskSuspend 配置为 1;无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复;此函数并不支持嵌套,不论使用此函数重复挂起任务多少次,只需调用一次恢复任务的函数,那么任务就不再被挂起。 函数原型如下所示
2、在任务中恢复被挂起的任务
        此函数用于 在任务中恢复被挂起的任务,若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 INCLUDE_vTaskSuspend 配置为 1;不论一个任务被函数vTaskSuspend()挂起多少次,只需要使用函数vTakResume()恢复一次,就可以继续运行。 函数原型如下所示
3、在中断中恢复被挂起的任务
        此函数用于 在中断中恢复被挂起的任务,若使用此函数, 需要在 FreeRTOSConfig.h 文件中将宏 INCLUDE_xTaskResumeFromISR 配置为 1必须在FreeRTOS所管理的 中断优先级 中断中才可以恢复任务;不论一个任务被函数vTaskSuspend()挂起多少次,只需要使用函数vTakResumeFromISR()恢复一次,就可以继续运行。 函数原型如下所示
4、运行任务的切换
        在 中断中恢复任务后,函数如果 返回pdTRUE,代表恢复的任务优先级比较高, 需要手动切换执行。这时候可以调用FreeRTOS提供的特殊函数来实现任务切换。 函数原型如下
void portYIELD_FROM_ISR(BaseType_t xYieldRequired);    // 实际上是一个宏定义函数,最终调用portYIELD()
六、FreeRTOS中断管理
1、ARM Cortex-M系列的中断
        ARM Cortex-M的NVIC最大可 支持 256 个中断源,其中包括 16 个系统中断和 240 个外部中断;然而 芯片厂商一般情况下都用不完这些资源,以正点原子的战舰开发板为例,所使用的 STM32F103ZET6 芯片就只用到了10个系统中断和60个外部中断。
中断优先级管理
        在NVIC的相关结构体中,成员 变量 IP 用于配置外部中断的优先级,成员变量IP的 定义如下所示:ARM Cortex-M 使用了8 位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器,因此 最大中断的优先级配置范围位 0~255
        但是芯片厂商一般用不完这些资源, 对于 STM32,只用到了中断优先级配置寄存器的高4 位[7:4],低四位[3:0]取零处理,因此STM32 提供了最大2^4=16 级的中断优先等级, 如下图所示STM32 的中断优先级可以分为 抢占优先级和子优先级
三个 系统中断优先级 配置寄存器
        除了外部中断, 系统中断有独立的中断优先级配置寄存器,分别为 SHPR1 SHPR2 SHPR3,下面就分别来看一下这三个寄存器的作用。
三个 中断屏蔽 寄存器
        ARM Cortex-M有三个用于屏蔽中断的寄存器,分别为 PRIMASK FAULTMASK BASEPRI,下面就分别来看一下这三个寄存器的作用。
        PRIMASK:PRIMASK寄存器有32bit,但只有bit0有效,是可读可写的,将PRIMASK寄存器设置为1用于 屏蔽除 NMI HardFault 的所有异常和中断,将PRIMASK寄存器清0用于使能中断。
        FAULTMASK:FAULTMASK寄存器有32bit,但只有bit0有效,也是可读可写的,将FAULTMASK寄存器设置为1用于屏蔽 NMI 外的所有异常和中断,将FAULTMASK寄存器清零用于使能中断。
        BASEPRI:BASEPRI有32bit,但只有 8 [7:0] 有效,也是可读可写的;BASEPRI寄存器比起PRIMASK和FAULTMASK寄存器直接屏蔽掉大部分中断的方式,BASEPRI寄存器的功能显得更加细腻,BASEPRI 用于设置一个中断屏蔽的阈值,设置好BASEPRI后, 中断优先级低于 BASEPRI 的中断就都会被屏蔽掉FreeRTOS 就是使用 BASEPRI 寄存器来管理受 FreeRTOS 管理的中断的
中断控制状态寄存器
        中断控制状态寄存器( ICSR)的地址为0xE000ED04,用于设置和清除异常的挂起状态,以及获取当前系统正在执行的异常编号, 各比特位的功能描述如下表所示
         这个寄存器主要关注 VECTACTIVE [8:0] ,通过读取 VECTACTIVE 段就能够判断当前执行的代码是否在中断中( FreeRTOS的中断判断原理
2、FreeRTOS中断管理详解
PendSV和SysTick中断优先级的实现
        FreeRTOS使用SHPR3寄存器配置PendSV和SysTick的中断优先级,那么FreeRTOS是如何配置的呢? FreeRTOS 的源码中有如下定义
        接着FreeRTOS 在启动任务调度器的函数中设置了PendSV和SysTick的中断优先级, 代码如下所示
FreeRTOS中断的屏蔽与启用
        FreeRTOS 使用 BASEPRI 寄存器来管理受FreeRTOS管理的中断,而不受FreeRTOS管理的中断不受FreeRTOS开关中断的影响,那么FreeRTOS开关中断是如何操作的呢?首先来看一下 FreeRTOS 开关中断的宏定义,代码如下所示
        屏蔽中断函数vPortRaiseBASEPRI()
        解除屏蔽函数vPortSetBASEPRI(0)
FreeRTOS进出临界区
        临界区是指那些必须完整运行的区域,在 临界区中的代码必须完整运行,不能被打断;例如一些使用软件模拟的通信协议,通信协议在通信时,必须严格按照通信协议的时序进行,不能被打断。 FreeRTOS 在进出临界区的时候,通过关闭和打开受 FreeRTOS 管理的中断,以保护临界区中的代码;FreeRTOS的源码中就包含了许多临界区的代码,这部分代码都是用临界区进行保护,用户在使用FreeRTOS编写应用程序的时候,也要注意一些不能被打断的操作,并为这部分代码加上临界区进行保护。
        对于进出临界区,FreeRTOS的源码中有四个相关的宏定义,分别为 taskENTER_CRITICAL() taskENTER_CRITICAL_FROM_ISR() taskEXIT_CRITICAL() taskEXIT_CRITICAL_FROM_ISR(x),这四个宏定义分别用于在中断和非中断中进出临界区, 定义代码如下所示
        任务级的进出临界区允许嵌套,但 中断级的不允许嵌套!!
任务调度器的挂起与恢复
        这是是对整个任务调度器的操作, 调度器被挂起,意味这 任务将无法切换,但是 不需要关闭中断;函数只能在任务中被调用, 不能在中断处理函数中使用具体函数如下
vTaskSuspendAll()  //挂起任务调度器;仅仅防止任务之间的资源争夺, 中断仍然可以响应;支持嵌套使用。
vTaskResumeAll()  //恢复任务调度器,在任意任务中调用;需要 和挂起函数成对出现返回值 为bpTRUE则不需要手动任务切换,为pdFALSE则需要手动切换任务( portYIELD_WITHIN_API
七、FreeRTOS的列表与列表项
1、列表与列表项简介
列表(List):列表是FreeRTOS中最基本的一种数据结构,其在物理存储单元上是非连续、非顺序的;列表在FreeRTOS中的应用十分广泛,要注意的是, FreeRTOS 中的列表是一个双向链表,在list.h文件中,有列表的相关定义, 具体代码如下所示
参数解释
① 包含了两个宏,分别为 listFIRST_LIST_INTEGRITY_CHECK_VALUE listSECOND_LIST_INTEGRITY_CHECK_VALUE,这两个宏用于存放确定已知常量,FreeRTOS通过 检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏;类似这样的宏定义在列表项和迷你列表项中也有出现; 该功能一般用于调试,默认是不开启的
② 成员变量 uxNumberOfItems用于记录列表中 列表项的个数( 不包含 xListEnd ,当往列表中插入列表项时,该值加1;当从列表中移除列表项时,该值减1。
③ 成员变量 pxIndex用于指向列表中的 某个列表项,一般 用于遍历列表中的所有列表项
④ 成员变量 xListEnd是一个迷你列表项;列表中迷你列表项的值 一般被设置为最大值用于将列表中的所有列表项按升序排序时,排在最末尾;同时xListEnd 也用于挂载其他插入到列表中的列表项
结构示意
列表项(List Item):列表项是用于指向一个数据的列表中的节点,在list.h 文件中,有列表项的相关定义, 具体代码如下所示
参数解释
① 如同列表一样,列表项中也包含了两个用于检测列表项数据完整性的宏定义。
② 成员变量 xItemValue 为列表项的值,这个值 多用于按升序对列表中的列表项进行排序
③ 成员变量 pxNext pxPrevious 分别用于指向列表中 列表项的下一个列表项和上一个列表项
④ 成员变量 pxOwner 用于 指向包含列表项的对象( 通常是任务控制块 ,因此,列表项和包含列表项的对象之间存在双向链接。
⑤ 成员变量 pxContainer 用于指向 列表项所在列表
结构示意图
迷你列表项(Mini List Item):迷你列表项也是列表项,但迷你列表项 仅用于标记列表的末尾和挂载其他插入列表中的列表项用户是用不到迷你列表项的;在list.h 文件中,有迷你列表项的相关定义, 具体的代码录下所示
参数解释
① 迷你列表项中也同样包含用于检测列表项数据完整性的宏定义。
② 成员变量 xItemValue 为列表项的值( 通常配置为最大值),这个值多用于按升序对列表中的列表项进行排序。
③ 成员变量 pxNextpxPrevious 分别用于指向列表中 列表项的下一个列表项和上一个列表项
结构示意
2、相关的API函数
初始化列表:函数 vListInitialise()
        此函数用于初始化列表,在定义列表之后,需要先对其进行初始化,只有初始化后的列表,才能够正常地被使用;列表初始化的过程,其实就是初始化列表中的成员变量。 函数原型如下所示
函数的实现源码如下
初始化列表项:函数 vListInitialiseItem()
        此函数用于初始化列表项,如同列表一样,在定义列表项之后,也需要先对其进行初始化;只有初始化好的列表项,才能够被正常地使用;列表项初始化的过程,也是初始化列表项中的成员变量。 函数原型如下所示
函数的实现源码如下
列表项的无序插入:函数 vListInsertEnd()
        此函数用于将待插入列表的列表项 插入到列表 pxIndex 指针指向列表项的前面,是一种 无序的插入方法函数原型如下所示
函数的实现源码如下
列表项升序插入:函数 vListInsert()
        此函数用于将待插入列表的列表项 按照列表项值升序排序的顺序,有序地插入到列表中。 函数原型如下所示
函数的实现源码如下
从列表中删除列表项:函数 uxListRemove()
        此函数用于将列表项从列表项所在列表中移除, 函数原型如下所示
函数的实现源码如下
3、其他用于操作列表和列表项的宏
八、FreeRTOS启动与任务底层原理解析
1、ARM的汇编指令集列表( 来自《Cortex-M3权威指南》
         边框加粗的是从 ARMv6T2 才支持的指令。 双线边框的是从 Cortex‐M3 才支持的指令( v7 的其它款式不一定支持)
//
2、开启任务调度器
        这里 总结性的描述整体过程,具体的源码分析 参考《FreeRTOS开发指南》第八章
创建 空闲任务 和 定时器任务( 如果配置启动软件定时器的话);
关闭全局中断,防止中断打断启动进程;
初始化FreeRTOS的全局变量,包括任务阻塞超时时间、FreeRTOS任务调度器状态等;
调用硬件平台相关函数,初始化 systick和pendsvc中断,初始化 进入临界区的计数器为0;
⑤ 初始化MSP指针到堆栈起始地址,启动全局中断,并触发一次SVC中断( ARM汇编);
找到就绪任务中优先级最高的任务,将堆栈的寄存器信息恢复到CPU的寄存器中,配置启用PSP指针,配置PC指针指向任务函数,开始执行任务( ARM汇编)。
//
3、任务状态列表
        在开始介绍FreeRTOS中任务相关的API函数之前,先介绍一下FreeRTOS中的任务状态列表,前面章节说了, FreeRTOS 中的任务无非就四种状态,分别为运行态、就绪态、阻塞态和挂起态,这四种状态中,除了运行态,其他三种任务状态的任务都有其对应的任务状态列表;FreeRTOS使用这些任务状态列表来管理处于不同状态的任务。任务状态列表在task.c文件中有定义, 具体的定义代码如下所示
① 就绪态列表,从定义可以看出,就绪态任务列表,从定义中可以看出,就绪态任务列表是一个数组,数组中元素的个数由宏configMAX_PRIORITY确定,宏configMAX_PRIORITY为配置的系统最大任务优先级。由此可见,FreeRTOS为每个优先等级的任务都分配了一个就绪态任务列表。
② 阻塞态任务列表,阻塞态任务列表 一共有两个,分别为是阻塞态任务列表1和阻塞态任务列表2,并且该有两个阻塞态任务列表指针;这么做是为了解决任务阻塞时间溢出的问题,这个会在后续讲解阻塞相关的内容时,具体分析。
③ 挂起任务列表,被挂起的任务就会被添加到挂起态任务列表中。
//
4、任务创建函数解析( vTaskCreate()
函数接口原型
过程解析
① 函数xTaskCreate()创建任务,首先 为任务的任务控制块以及任务栈空间申请内存,如果任务控制块或任务栈空间的内存申请失败,则释放已经申请到的内存,并返回内存申请失败的错误。
调用函数prvInitialiseNewTask()初始化任务控制块中的成员变量,包括任务函数指针、任务名、任务栈大小、任务函数参数、任务优先级等。
③ 然后 调用函数prvAddNewTaskToReadyList(),将任务添加到对应优先级的就绪任务列表中。
///
5、任务删除函数解析( vTaskDelete()
函数接口原型
过程解析
① 使用vTaskDelete()删除任务时, 需要考虑两种情况,分别为 待删除任务不是当前正在运行的任务(调用该函数的任务)和 待删除任务为当前正在运行的任 (调用该函数的任务)。第一种情况比较简单,当前正在运行的任务可以直接删除待删除任务;而第二种情况下,待删除任务时无法删除自己的,因此需要将当前任务添加到任务待删除列表中,空闲任务会处理这个任务待删除列表,将待删除的任务统一删除。
② 在待删除任务不是当前正在运行的任务这种情况下,当前正在运行的任务可以删除待删除的任务,因此调用了函数prvDeleteTCB(),将待删除的任务删除。
///
6、挂起任务函数解析( vTaskSuspend()
函数接口原型
过程解析
① 任务句柄将会从就绪态被转移到挂起态列表;
② 使用函数vTaskSuspend()挂起任务时,如果任务调度器没有运行,并且待挂起的任务又是调用函数vTaskSuspend()的任务,那么pxCurrentTCB需要指向其他优先级最高的就绪态任务; 更新 pxCurrentTCB 的操作是通过调用函数 vTaskSwitchContext() 实现的
③ 如果任务调度器正在运行,且将要挂起的任务正在运行,则需要切换任务。
///
7、恢复任务函数解析( vTaskResume()
函数接口原型
过程解析
① 将要恢复的任务从挂起列表恢复到就绪列表;
② 如果任务优先级高于当前正在运行的任务,则需要切换任务;
///
九、FreeRTOS任务切换原理
1、PendSV中断服务函数
         PendSV Pended Service Call ,可挂起服务调用),是一个对RTOS 非常重要的异常。PendSV 的中断优先级是可以编程的,用户可以根据实际的需求,对其进行配置; PendSV 的中断由将中断控制状态寄存器( ICSR )中 PENDSVSET 为置一触发。PendSV 与SVC 不同, PendSV 的中断是非实时的,即 PendSV 的中断可以在更高优先级的中断中触发,但是在更高优先级中断结束后才执行
        利用PendSV 的这个可挂起特性, 在设计 RTOS 时,可以将 PendSV 的中断优先级设置为最低的中断优先级; 这么一来, PendSV 的中断服务函数就会在其他所有中断处理完成后才执行。任务切换时,就需要用到PendSV 的这个特性。
FreeRTOS中的函数原型:__asm void xPortPendSVHandler( void )
函数执行过程解析
① R0寄存器保存当前执行任务的PSP指针( CPU会在进入中断之前, 自动 保存部分寄存器到任务堆栈);
② R2保存了任务控制块栈顶指针成员的地址;
③ 利用RO寄存器中PSP指针位置, 手动将R4~R11寄存器的值入栈到任务堆栈中;
④ 保存当前PSP指针最新堆栈位置到任务控制块的栈顶指针成员变量中;
⑤ 保存R3和R14的值到MSP指针中,一会要用( R3保存的是当前执行任务控制块变量的地址);
⑥ 屏蔽FreeRTOS所管理的所有中断;
⑦ 调用 函数vTaskSwitchContext()查找下一个任务控制块;
⑧ 重新取消中断屏蔽,从MSP寄存器中恢复R3和R14寄存器( 此时R3所指的实际任务控制块已经被替换了);
⑨ R1获取到R3所指的任务控制块对象地址;
⑩ R0获取R1中的任务栈顶指针,接着将任务堆栈中的内存出栈到R4~R11中;
11)设备PSP指针执行新的任务堆栈位置;
12)触发PC指针,开始切换执行新的任务;
2、任务选择函数vTaskSwitchContext()
函数原型:void vTaskSwitchContext( void )
函数运行解析
① 判断任务调度器是否运行,如果没运行则标记需要启动,并重复调用PandSV直到运行;
② 调用宏函数taskSELECT_HIGHEST_PRIORITY_TASK()实现具体动作;
③ 通过 优先级就绪任务变量的bit位,找到存在就绪任务的最高优先级列表并返回;
④ 根据返回的优先级,确认对应列表中是否有就绪任务;
⑤ 从列表中找出尾节点的下个任务的控制块,并返回作为新的执行任务;
3、同等优先级任务时间片轮询的原理
        在FreeRTOSConfig.h中,需要 配置  configUSE_PREEMPTION=1 和 configUSE_TIME_SLICING=1 ,才可以使能时间片调度;且时间片调度算法 只能发生在任务优先级相同的任务之间
4、个人总结( 重要
        在FreeRTOS系统中,无论是 抢占式任务调度算法 还是 时间片轮询算法 ,其 主要路径是同一个:都是通过systick中断触发pandSV中断,然后在中断中 先查看就序列表中,存在任务的最高优先级任务;如果优先级相同,则采取时间片轮询。
        在其他情况下,如任务阻塞,挂起等,则通过 提前触发pandSV中断来切换任务,并将 当前任务从就序列表中移除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/604918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Node.js+vue多用户个人博客网站i03nz

基于nodejs语言设计并实现了个人博客。该系统基于B/S即所谓浏览器/服务器模式&#xff0c;应用Vue框架&#xff0c;选择MySQL作为后台数据库。系统主要包括首页、个人中心、用户管理、文章分类管理、博客文章管理、留言板管理、系统管理等功能模块。要循序渐进&#xff0c;心急…

chatgpt赋能python:Python列表分割与排序:完美解决数据处理问题

Python列表分割与排序&#xff1a;完美解决数据处理问题 在Python的开发实践中&#xff0c;数据处理是一项必不可少的操作。列表&#xff08;list&#xff09;是Python语言中常用的数据类型之一&#xff0c;列表中的元素可以是任意类型。列表的分割和排序是Python中常见的操作…

Apk编译过程1 - Android Studio 与 gradle

Apk编译过程1 - Android Studio 与 gradle 文章目录 Apk编译过程1 - Android Studio 与 gradlegradlewAndroid studio 的 gradle plugingradle脚本AGP&#xff1a;Android Gradle Plugin gradle 是 Android 开发者比较熟悉的构建工具了&#xff0c;因为 Android Studio 默认使用…

Java常用类及使用方法

目录 1.String 1.String的基本概念 2.String的不可变性 3.String的实例化方式及内存解析 1.两种方式 2.new构造器的方式的内存解析 3.字符串对象的存储 4.字符串拼接后的内存解析 6.String中的常用方法 7.什么时候indexOf (str)和LastIndexOf (str)返回值相同 8.Str…

用gpt定制一个pytest接口测试框(附源码)

目的&#xff1a; 描述我的需求和目标让gpt给我写一个测试接口框架 并且让他自己完善。 我说:帮我写一个基于python语言的 pytest的接口测试框架 支持post get put delete请求 添加详细的断言&#xff0c;处理身份验证和授权&#xff0c;处理HTTP错误 加上allure2报告和有请求…

代码随想录第51天

1.最佳买卖股票时机含冷冻期 淦&#xff0c;自己写&#xff0c;用3个状态死活写不出来。 动规五部曲&#xff0c;分析如下&#xff1a; 确定dp数组以及下标的含义 dp[i][j]&#xff0c;第i天状态为j&#xff0c;所剩的最多现金为dp[i][j]。 其实本题很多同学搞的比较懵&…

SecurityAccess(0x27)服务

SecurityAccess&#xff08;0x27&#xff09;服务 此服务的目的是提供访问数据和/或诊断服务的手段&#xff0c;这些服务因安全&#xff0c;排放或安全原因而受到限制。 用于将 例程或数据下载/上传到服务器和从服务器读取特定存储器位置的诊断服务是可能需要安全访问的情况。…

使用Inkscape绘制矢量电路图

GNU Inkscape是一个免费的开源矢量图形编辑器&#xff0c;非常适合画论文中的矢量插图。 Inkscape Inkscape支持win mac linux全平台&#xff08;下载&#xff09;&#xff0c;windows端还发布了uwp版本&#xff0c;可在Windows store安装。 基本操作&#xff1a; inkscape工…

2023年前端面试题汇总-性能优化

1. CDN 1.1. CDN的概念 CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;是指一种通过互联网互相连接的电脑网络系统&#xff0c;利用最靠近每位用户的服务器&#xff0c;更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户&…

简谈软件版本周期 | Alpha、Beta、RC、Stable版本之间的区别

目录 &#x1f48c; 引言 ⭕ 软件版本周期 &#x1f6e0;️ 软件开发期 ⚖️ 软件完成期 &#x1f4b0; 商业软件版本 &#x1f48c; 引言 定义好版本号&#xff0c;对于产品的版本发布与持续更新很重要&#xff1b;但是对于版本怎么定义&#xff0c;规则如何确定&#x…

【微服务架构】无法在Sentinel Dashboard查看到服务的监控信息原因

&#xff08;目前项目中使用的Hystrix&#xff0c;而Hystrix已经不维护了&#xff0c;至今仍然是2018年发布的1.5.8版本。&#xff09; 开始学习一下新的服务治理框架Sentinel Sentinel官网介绍 在集成Sentinel案例中碰到的问题 微服务&#xff0c;无法在sentinel dashboard…

Oracle中的数据导出(3)

假如我现在不想再打开DOS界面输入命令导出数据&#xff0c;那又有什么简单便捷的方法实现呢&#xff1f; 我将在本篇描述一种自动化的操作方法&#xff0c;简单讲就是&#xff1a;我把需要查询的数据脚本放在桌面的一个mini&#xff0c;通过双击快捷图标直接实现数据结果导出到…

VMware ESXI7.0.3的安装

文章目录 一、VMware ESXI7.0版本的安装与配置1.1、VMware概述。1.2、VMware 解析&#xff1a;1.3、VMware ESXI解析&#xff1a;2.1、准备资料2.2.1、VMware ESXI的ISO下载 3.1、安装ESXI4.1、浏览器键入esxi上述ipv4地址&#xff1a;192.168.229.171 一、VMware ESXI7.0版本的…

VMware ESXi 8.0b Unlocker OEM BIOS 集成 REALTEK 网卡驱动和 NVMe 驱动 (集成驱动版)

VMware ESXi 8.0b Unlocker & OEM BIOS 集成 REALTEK 网卡驱动和 NVMe 驱动 (集成驱动版) 发布 ESXi 8.0 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-sysin/&#xff0c;查看最新版。原创作…

C语言——分段函数求值

一、题目描述 二、题目分析 本题是简单的分段函数的求解&#xff0c;应学会合理的运用for\if\swich函数解答问题。 三、代码实现 //for语句解题#include <stdio.h> int main() {int x,y;scanf("%d",&x);if(x<1){yx;}else if(1<x && x<…

FL Studio软件最新21中文版本安装包下载

FL Studio21集合最新FL基础操作、编曲技巧、混音技巧、乐理基础、声乐演奏等各类内容&#xff0c;编曲软件FL Studio 简称FL&#xff0c;全称&#xff1a;Fruity Loops Studio&#xff0c;因此国人习惯叫它"水果"。目前版本是FL Studio20&#xff0c;它让你的计算机就…

章节1:远程代码执行渗透与防御

章节1&#xff1a;远程代码执行渗透与防御 01 什么是远程代码执行&#xff1f; 远程代码执行&#xff08;RCE漏洞&#xff09; 远程代码执行&#xff1a;Remote Code Execute 远程命令执行&#xff08;命令注入漏洞&#xff09;&#xff1a;Remote Command Execute 定义&a…

高速PCB Layout设计要用哪些工具?

随着时代高速发展&#xff0c;高速PCB项目逐渐成为主流项目之一&#xff0c;越来越多的电子工程师需要掌握高速PCB Layout设计能力&#xff0c;同时电子工程师在进行高速PCB Layout时需要用到多种工具&#xff0c;下面来看看有哪些工具和软件&#xff1f; 1、设计软件 ①Altiu…

Redis的常用数据结构之列表类型

列表类型的数据特点 用于存储多个有序的字符串单个列表最多可以存储2的32次方-1个元素&#xff08;4294967295&#xff09;。列表的元素是可以重复的可以分别对列表的两端做插入&#xff08;push&#xff09;和弹出&#xff08;pop&#xff09;操作 List相关的操作命令 向右…

Vue3(二):Vue3生命周期、自定义hook、其他API、Suspense等组件

Vue3&#xff1a;第二章 一、Vue3生命周期二、自定义hook函数三、toRef四、其他Composition API1.shallowRef与shallowReactive2.readonly与shallowReadonly3.toRaw 与 markRaw&#xff0c;customRef4.provide和inject5.响应式数据的判断 五、组合式API的优势1.选项式API的问题…