FreeRTOS 解析

article/2025/8/27 4:38:26

目录

Task

Task State

Task Priority

Idle Task

Run Time Statistics

Task Scheduling

Single-core 单核处理器

AMP 非对称多核处理器

SMP 对称多核处理器

Context Switch

Inter-task Communication and Synchronization

Queue 队列

Binary Semaphore 二值信号量

Counting Semaphore 多值信号量

Mutex 互斥锁

Recursive Mutex 循环互斥锁

Task Notifications 任务通知

Stream & Message Buffers

Event Bits (or flags) and Event Groups

Heap_5

Stack

Software Timers


FreeRTOS 是免费开源的轻量型实时操作系统,简单易学易用,广泛应用于各种嵌入式平台。

以下简要记录重读官网文档的心得,以备后续系统整理。

task = 任务 = 线程

one port = one specific CPU arch + one specific compiler

Task

Task State

Running:一个 CPU 核任意时刻只有一个运行态任务。

Blocked:不被调度器调度,不占用 CPU 时间,等待超时或者外部事件唤醒,例如 vTaskDelay()、等待 queue, semaphore, event group, notification or semaphore event。(注:An event group is a set of binary flags (or bits), to each of which the application writer can assign a meaning.)

Suspended:挂起态,不被调度器调度,不占用 CPU 时间,没有超时和事件唤醒,只能唯一通过执行 vTaskSuspend(),xTaskResume() 进出 Suspended state。任务A 可以挂起自己,也可以被别的运行态任务B 挂起(挂起前,A 处于就绪态、运行态或阻塞态);A 被挂起后,可以被运行态B 或中断函数再恢复到就绪态。挂起调用 vTaskSuspend(),退出调用 xTaskResume()。

状态机:

Task Priority

0 to ( configMAX_PRIORITIES - 1 )

数值越小,优先级越低。

idle 线程优先级 = tskIDLE_PRIORITY = 0

Idle Task

Idle 线程在 OS 调度器开始的时候自动被创建,优先级最低为 0。主要功能是在没有其他高优先级任务运行时,负责回收之前 deleted task 的栈等内存资源。除此之外,还可以执行用户自定义的其他功能,比如 power saving。

configUSE_IDLE_HOOK = 1 时,Idle 线程会回调用户自定义功能,用户需提供回调函数如下,注意回调函数中不能阻塞或死循环不返回。

void vApplicationIdleHook( void );

Run Time Statistics

函数 vTaskGetRunTimeStats() 可以统计任务运行花费的 CPU 绝对时间及百分比。前提是使能一个比系统 tick 精度高(越高统计越精确)的 timer 用于统计时间。

Task Scheduling

Single-core 单核处理器

固定优先级抢占、相同优先级时间片轮循调度算法。

“固定优先级” 指调度器不会永久改变一个任务的优先级,只在互斥锁优先级继承的时候临时提高低优先级锁持有者任务的优先级。

“抢占” 指高优先级任务可以在任务切换点(tick 中断)抢占低优先级任务;或者低优先级任务在它的时间片内被中断打断,中断之后调度器重新调度高优先级任务,于是低优先级任务在它的时间片内也被高优先级抢占了。

“轮循” 指具有相同优先级的多个任务,按时间片 one by one 轮流进入运行态。

AMP 非对称多核处理器

每个核独立运行一个调度器,调度算法同 single-core。

每个核的架构可以不同,需要一些共享的内存用于多核之前消息传递。

SMP 对称多核处理器

多个核共同运行一个调度器,每个核的架构必须相同。

调度算法同 single-core,不过每个核都可以有一个运行态任务,所以总的运行态任务个数可以跟核的个数一样多!也就意味着,优先级高但不相同的多个任务可以同时运行,而不是像单核那样只最高优先级的一个任务在运行!

Context Switch

说完任务和调度器,来看下任务切换时的上下文切换。当发生中断或者任务主动 yield 时会发生任务上下文切换。所谓上下文 context,就是任务在运行时硬件架构中各寄存器的值;上下文切换,就是将任务 A 的 context 保存到其栈中,调度器选择新任务 B,并将 B 的 context 从其栈中恢复到对应寄存器中,从而完成从 A 到 B 的切换。

1. 任务 A 运行中

 2. RTOS tick 中断发生,首先将 PC 压栈到 A 栈

 3. 中断 ISR

 3.1 portSAVE_CONTEXT() 将 A 的 context 压栈,更新并保存栈指针到 TCB_A 中

 3.2 vTaskIncrementTick() Tick 中断将内核 tick 数++,并检查被 delay() 的任务是否超时了,如果是,任务就变成可运行态。这里假设任务 B 变成可运行态并且优先级高于任务 A。

3.3 vTaskSwitchContext() 查看是否需要上下文切换,本例中任务 B 优先级高于任务 A,所以需要切换到任务 B,将 B 栈指针从 TCB_B 中恢复到系统 SP 寄存器中

 3.4 portRESTORE_CONTEXT() 将 B 的 context 从 B 栈中恢复到相应寄存器(除了 PC)

 3.5 asm volatile ( "reti" ) RETI 指令假设当前栈顶是返回地址即 PC,恢复到 PC 寄存器,至此完成切换到任务 B

 

Inter-task Communication and Synchronization

Queue 队列

用于线程间、线程与中断间通信。

线程安全 FIFO,可以队尾或队首插入。

多个任务读/写阻塞到同一个队列,最高优先级的任务先被 unblock。

Binary Semaphore 二值信号量

多用于同步。类似长度为 1 的队列。

Counting Semaphore 多值信号量

多用于同步。类似长度大于 1 的队列(长度在创建时指定)。

Mutex 互斥锁

多用于互斥操作。不能用在中断函数中,因为中断函数不能阻塞来等待 take mutex,没有 take 也就不会有 give。

优先级继承:低优先级任务A 当前占有锁,高优先级任务B take 时被阻塞,A 的优先级被临时提高到跟 B 一样,减少高优先级B 的阻塞时间。

Recursive Mutex 循环互斥锁

可以被一个任务多次 take,但 take 多少次要相应 give 相同次数,否则不能被其他任务 take。

Task Notifications 任务通知

FreeRTOS V8.2.0 版本引入的新功能,用来 线程<—>线程,中断—>线程通信/同步。
优点:

1. 比前面几种同步方式速度更快(45% faster

2. 更省 ram 空间:不需要单独创建用于同步/通信的信号量/队列等结构体变量,而是将通知信息放在线程控制块 TCB 中。

typedef struct tskTaskControlBlock
{... .../* configTASK_NOTIFICATION_ARRAY_ENTRIES = 1 */volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];... ...
} tskTCB;

3. 可以充当轻量型的二值信号量、计数信号量、event group、mailbox 来使用。

缺点:

1. 只能定向通知到具体某一个任务,而不能像信号量那样所有任务和 ISR 都可以 take。如上所说,通知信息是与某个任务捆绑的,所有只能通过任务的 taskHandle 定向通知给该任务。

2. 当用作队列使用时,接收线程可以阻塞等待,但发送线程不能在队列满时阻塞等待而只能返回错误。

Stream & Message Buffers

FreeRTOS V10.0.0 版本引入的新功能,用来 线程<—>线程,中断—>线程,CPU core <—> core 通信。

注意,一个 Stream/Message Buffer 允许被多个 readers/writers 操作,但不能同时进行,某一时刻只能有一个 reader/writer。

Event Bits (or flags) and Event Groups

用于通信/同步,类似于 Task Notifications,不过后者更轻量级。

Heap_5

类似于 Heap_4,提供初次匹配(first fit)的内存块申请算法和碎片合并的内存块回收算法。

不同的是,允许整个 heap 由多个不相邻的内存区域组成。在初次使用 heap 前需调用 vPortDefineHeapRegions() 进行初始化。各个内存区域按地址段从低到高的顺序放在数组里,并将该数组作为参数传给上述初始化函数。

 xPortGetFreeHeapSize() 返回当前空闲 heap 大小。

xPortGetMinimumEverFreeHeapSize() 返回系统空闲 heap 的历史最小值。

vPortGetHeapStats() 返回当前 heap 统计信息:

Stack

任务栈在任务被切出时因为要压栈,所以这时很有可能发生栈溢出。

在任务栈地址空间连续的前提下,FreeRTOS 提供两种任务切换时检测被切出任务是否发生栈溢出的方法:

configCHECK_FOR_STACK_OVERFLOW = 1 时,检查栈指针是否在栈空间范围内,如果不在就认为发生了栈溢出。该方法无法判断在任务执行过程中是否发生过栈溢出,因为在切换之前栈指针再回到栈空间内的话还是会当作没发生溢出。相比之下,这种情况可以被下面的方法检测到。

configCHECK_FOR_STACK_OVERFLOW = 2 时,任务创建时任务栈被填充已知的固定值,任务切换时检查栈空间末尾的 16 个字节,如果其中任意一个字节被改变就认为发生了栈溢出。

若 configCHECK_FOR_STACK_OVERFLOW != 0,应用上要定义一个如下回调函数当栈溢出时调用。

void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName );

Software Timers

定时器 API 将相关操作 cmd 放入 timer command queue,timer service task 从 queue 中取出 cmd 并执行,该任务的优先级一般很高。所以,定时器回调函数中不能有阻塞操作,比如 vTaskDelay(), vTaskDelayUntil() 或者队列/信号量的阻塞操作。


http://chatgpt.dhexx.cn/article/HS7N3xUJ.shtml

相关文章

FreeRTOS队列

在实际的应用中&#xff0c;常常会遇到一个任务或者中断服务需要和另外一个任务进行“沟通交流”&#xff0c;这个“沟通交流”的过程其实就是消息传递的过程。在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式&#xff0c;但是如果在使用操作系统的应用中…

FreeRTOS任务状态

1. 任务状态介绍 FreeRTOS中的任务状态&#xff0c;可以简单的分为运行态&#xff08;running&#xff09;和非运行态&#xff08;not running&#xff09;。 但是对于非运行态我们还可以继续细分&#xff1a; 阻塞状态&#xff08;Blocked&#xff09;暂停&#xff08;挂起…

FreeRTOS延时

1、相对延时函数 将当前任务添加到阻塞列表pxDelayedTaskList&#xff0c;任务进入阻塞态。 vTaskDelay → prvAddCurrentTaskToDelayedList → vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) )。任务的阻塞时间更新到状态列表项xStateListItem x…

FreeRTOS多任务管理

文章目录 1、任务1.1 任务简介1.2 任务调度1.3 任务的状态 (就绪态 / 运行态 / 阻塞态 / 挂起态)1.4 空闲任务 2、动态创建两个任务2.1 定义动态内存空间的堆2.2 定义任务函数2.3 定义 任务控制块 指针2.4 动态创建任务 xTaskCreate()2.5 启动任务 vTaskStartScheduler() 3、常…

FreeRTOS 移植

源码 FreeRTOS源码 选择 FreeRTOS 的最新版本 V9.0.0&#xff08;2016 年&#xff09;比较稳定 1&#xff09;解压后的文件 提取的文件&#xff0c; FreeRTOS—>Source->portable目录下的MemMang&#xff0c;RVDS MemMang 存放内存相关的源文件,heap_1.c,heap_2.c,he…

初识FreeRTos

初识FreeRTos Preface一、FreeRTos简介二、 为什么选择FreeRTos三、FreeRTos资料和源码的下载四、介绍我自己的开发环境4.1FreeRTos4.2AlienTek Summary Preface 距离我上一次写博客已经差不多有5个月了&#xff0c;最近想给自己挖个新坑&#xff0c;讲一讲关于FreeRTos 相关的…

FreeRTOS移植

1. 前言 本文是基于FreeRTOSv9.0.0版本的实时系统&#xff0c;移植到STM32F103芯片平台上。移植环境使用的是MDK5.32版本&#xff0c;我在移植之前就已经构建好了一个裸机工程源码了&#xff0c;而且已经确保了这份裸机代码是没有问题的。开始移植之前我强烈建议一定要确认自己…

FreeRTOS快速入门-初探FreeRTOS

首发&#xff0c;公众号【一起学嵌入式】 对于 RTOS 入门系列文章&#xff0c;已经更新完一款&#xff08;RT-Thread&#xff09;&#xff1a; 助你快速入门 RT-Thread 这个系列的文章结合 RT-Thread&#xff0c;介绍过 RTOS 相关的核心知识。 接下来&#xff0c;开始另外一…

FreeRTOS系列|FreeRTOS简介

1. RTOS简介 RTOS全称为 Real Time Operation System&#xff0c;即实时操作系统。RTOS强调的是实时性&#xff0c;又分为硬实时和软实时。硬实时要求在规定的时间内必须完成操作&#xff0c;不允许超时&#xff1b;而软实时里对处理过程超时的要求则没有很严格。RTOS的核心就…

freertos任务基础知识(freertos篇)

多任务 对于单任务系统就是常说裸机大while循环&#xff0c;有的时候也需要加一些中断服务函数完成一些处理&#xff0c;相比于多任务而言上面的单任务系统也叫做前后台系统&#xff0c;即&#xff08;中断服务函数叫前台程序&#xff0c;大while叫后台程序&#xff09; 前后台…

FreeRTOS学习,适用于FreeRTOS初学者,FreeRTOS整体知识框架

目录 一、为什么要学习FreeRTOS 二、前言------从0到1认识FreeRTOS 1、逻辑系统与多任务系统 1.1、裸机系统&#xff1a;裸机系统通常分成轮询系统和前后台系统 1.2、多任务系统 2、数据结构-列表与列表项 三、任务 3.1基本属性 3.1.1任务栈 3.1.2任务控制块 3.1.3任…

一、初识FreeRTOS之FreeRTOS简介

目录 一、什么是FreeRTOS&#xff1f; 二、为什么选择FreeRTOS&#xff1f; 三、FreeRTOS的特点 四、FreeRTOS资料与源码下载 五、FreeRTOS源码文件介绍 一、什么是FreeRTOS&#xff1f; Free即免费的&#xff0c;RTOS的全称是Real time operating system,中文就是实时操作…

Docker技术入门与实战-第3版.pdf OCR 高清 可复制

Docker技术入门与实战-第3版.pdf OCR 高清 可复制 Docker技术入门与实战-第3版.pdf OCR 高清 可复制简介预览下载地址 Docker技术入门与实战-第3版.pdf OCR 高清 可复制 简介 本书从Docker基本原理开始&#xff0c;深入浅出地讲解Docker的构建与操作&#xff0c;内容系统全面…

从docker到kubernetes(k8s)入门与实战--docker教程

安装docker 装个依赖 yum -y install gcc gcc-c 卸载旧版本 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine 安装依…

Docker 入门到实战教程(二)安装Docker

一.卸载旧版本 较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序&#xff0c;请卸载它们以及相关的依赖项。 $ sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate…

Docker入门及进阶教程

阅读声明&#xff1a; 该教程笔记来源于dockers——菜鸟教程 一、Docker介绍 1. Docker教程 Docker是一个开源的容器引擎&#xff0c;基于Go语言并遵从Apache2.0协议开源。 Docker可以让开发者打包他们的应用以及依赖包到一个轻量级&#xff0c;可移植的容器&#xff0c;然后发…

Docker 实战

目录 一、常用操作 1、镜像创建 2、镜像查询 3、镜像删除 4、镜像运行 5、查询容器进程 6、查询容器执行日志 7、删除容器 8、进入容器 二、导入和导出 1、save 和 load 2、export 和 import 3、区别 三、案例 1、检查是否安装依赖 2、安装依赖 3、docker打包镜…

Docker 实战教程之从入门到提高 (四)

本系列的前三篇文章&#xff0c;我们学习了如何在 Ubuntu 操作系统安装 Docker&#xff0c;并且通过实战练习&#xff0c;了解了 Docker 和宿主机操作系统文件目录互相隔离的实现原理&#xff0c;以及 Docker Volume 的工作原理。通过动手对 Nginx Docker 镜像进行修改&#xf…

Docker快速入门实战

为什么使用容器&#xff1f; 1、上线流程繁琐 2、资源利用率低 3、扩容/缩容不及时 4、服务器环境臃肿 5、环境不一致性 容器VS虚拟机 VM VS Container Docker 是什么 1、使用最广泛的开源容器引擎 2、一种操作系统级的虚拟化技术 3 、依赖于Linux内核特性&#xff1…

Docker教程(Docker实战)

Docker快速入门教程 **欢迎关注公众号【程猿薇茑】** 【仅需一次订阅,作者所有专栏都能看】 推荐【Kafka】https://bigbird.blog.csdn.net/article/details/108770504 推荐【rabbitmq】https://bigbird.blog.csdn.net/article/details/81436980 推荐【Flink】https://blog.csdn…