全网最全最细 FreeRTOS 手册详解——1-The FreeRTOS Distribution

全网最全最细 FreeRTOS 手册详解——1-The FreeRTOS Distribution,第1张

FreeRTOS :Real Time Engineers Ltd.
《A_Hands-On_Tutorial_Guide》 作者:Richard Barry

本专栏是对 FreeRTOS-《A Hands On Tutorial Guide》的翻译、解释、引申 加以本人一点点理解。

书可以在 FreeRTOS 官网 SUPPORT 下面的 Books & Maunals 找到,即 《Mastering the FreeRTOS Real Time Kernel-A Hands On Tutorial Guide》。

有关 FreeRTOS 接口的详细介绍在 《 Reference Manual 》中。

在开始正文之前,本节先用来介绍一些先验知识,以帮助大家更好更全面的理解 FreeRTOS。

什么是 FreeRTOS ? 什么是 RTOS

参考 wiki 可知:

实时 *** 作系统(Real-time operating system, RTOS),又称即时 *** 作系统,它会按照排序执行、管理系统资源,并为开发应用程序提供一致的基础。

实时 *** 作系统与一般的 *** 作系统相比,最大的特色就是“实时性”,如果有一个任务需要执行,实时 *** 作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。

为什么是 FreeRTOS

完全免费、开源、市场占有率高。

创始人 Richard Barry 提供了大量的移植代码和配套文档。基于 FreeRTOS 的 SafeRTOS 经过了安全性验证,侧面表现了 FreeRTOS 安全方面做的也是比较好的。FreeRTOS 代码量少,和 Linux 等其他系统动辄上多少万的代码量相比真是小巧精致,但是也是五脏俱全。

开源、免费、而且提供了大量的帮助和指导文档,Richard Barry 的开源精神,这些实在是非常让人无法拒绝的地方。

了解 FreeRTOS

本专栏将从如下方面了解 FreeRTOS:

  • FreeRTOS 文件结构和编码风格
  • 堆内存管理
  • 任务管理
  • 队列管理
  • 软件计时器管理
  • 中断管理
  • 资源管理
  • 事件管理
  • 任务通知
  • 开发者支持
  • 问题定位
两类实时性要求
  • 软实时:声明了 deadline,但是超过也不会导致整个系统无用(useless),例如键盘敲击的响应慢,只是让人感觉不好,但不会导致系统不可用,整个系统仍然是可用的
  • 硬实时:声明了 deadline,超过之后会引起系统绝对的错误(absolute failure),例如汽车安全气囊对碰撞传感器输入响应太慢,安全气囊可能产生的坏处大于好处(airbag has the potential to do more harm than good)。

FreeRTOS 是一个实时内核(或者实时调度器),在其之上可以构建嵌入式程序来满足其硬实时需求。他允许把多个程序组织为独立执行线程的集合。单核处理器下,内核通过检查程序设计者赋予程序的优先级来决定某一个时刻应该执行哪个线程。例如,程序可以被赋予高优先级,来满足其硬实时需求,低的优先级来满足软实时的需求,这会确保硬实时需求的程序总是在软实时需求的程序之前执行。但是优先级赋值是困难的(不总是简单的,are not always that simplistic)。

价值观 value proposition

FreeRTOS 是专业开发的、严格质量把控、健壮、被支持并且不存在任何知识产权模糊,在商业应用程序中免费使用且不需要暴露任何你拥有的源代码,更不要说支付费用。任何时候,想要一个书面的保证、保障或者备份,都有一个简单的低成本的商业升级路径。任何时候都可以选择走商业路径,十分便利(原文 peace of mind comes with you can take opt to commercial route an any time you choose)。在 FreeRTOS 中每个可执行的线程(thread)也被称为任务(task)。

优势

除了满足应用程序硬实时要求之外的优势:

  • 抽象出时序信息(Abstracting away timing information)
    • 内核负责执行的时许,并提供与之相关的 API。这允许应用代码的结构变得简单、体积更小
  • 可维护性、可扩展性(Maintainability/Extensibility)
    • 抽象时序细节使得模块之间的相互影响更低,并且软件会以可预测和控制的方式运行、演变。因为内核负责时序,因此应用程序的性能不太容易收到底层硬件变化的影响
  • 模块化(Modularity)
    • Tasks 是相互独立的模块,他们中的每一个都应有明确定义的目的
  • 团队开发(Team development)
    • Tasks 应该由定义良好的接口,允许被团队更简单的开发
  • 易测试(Easier testing)
    • 如果 Tasks 满足拥有简洁接口且明确定义的模块,那么它们可以被单独测试(can be tested in isolation)
  • 效率提升(Improved Efficiency)
    • 使用内核意味着软件是完全事件驱动的,在轮询没有发生的事件的时候没有执行时间会被浪费,因为代码仅当必须做一些事情的时候才会执行
    • 与效率提升相反的是处理时钟中断(tick interrupt)的需要,以及从执行一个 task 切换到另一个 task。通常不使用 RTOS 的程序,一般也包括某种形式时钟中断
  • 空闲时间(Idle time)
    • 当调度器开始运行时就会自动创建一个 idle task。只要没有想要执行的应用程序时,idle task 就会执行。 idle task 可以用来测量空闲时处理能力,或者做环境检查(background check),或者仅仅只是把处理器调整为低功耗模式。
  • 功耗管理(Power Management)
    • 通过使用 RTOS 获得的效率收益允许处理器待在低功耗模式下更长时间。每当 idel task 运行的时候,我们就把处理器置为低功耗状态,可以使功耗明显降低。
    • FreeRTOS 有 tick-less 模式,可以使处理器进入比其他模式功耗更低的功耗模式,并且保持在低功耗模式更长时间
  • 灵活的中断处理(Flexible Interrupt Handling)
    • 通过推迟中断处理程序到一个应用作者创建的任务或者 FreeRTOS 的 daemon task,可以保留中断非常短的时间
  • 混合处理需求(Mixed Processing Requirements)
    • 能用简单的设计模式在一个应用中实现周期、连续、事件驱动的处理的混合。此外,软硬实时需求也可以通过选择合适的任务和中断优先级来满足。
FreeRTOS 特性
  • 可抢断与不可抢断(pre-emptive or co-operative operation)
  • 灵活的任务优先级赋值(Flexible task priority assignment)
  • 灵活、快速、轻量的任务通知机制(Flexible, fast and light weight task notification mechanism)
  • 队列(Queues)
  • 二进制信号量(Binary semaphores:A Binary Semaphore is a semaphore whose integer value range over 0 and 1)
  • 计数信号量(Counting semaphores:Counting semaphores are synchronization mechanisms with values varying in a range [0,n])
  • 锁(Mutexes)
  • 递归锁(Recursive Mutexes)
  • 软件时钟(Software Timers:A software timer [or just a ‘timer’] allows a function to be executed at a set time in the future,允许一个函数在设定的将来的一个时间执行)
  • 事件组(Event groups)
  • 时钟钩子函数(Tick hook functions:The tick interrupt can optionally call an application defined hook [or callback] function - the tick hook. )
  • 空闲钩子函数(Idle hook functions)
  • 栈溢出检查(Stack overflow checking)
  • Trace recording
  • 任务运行时统计信息收集(Task run-time statistics gathering)
  • 可选的商业许可和支持(Optional commercial licensing and support)
  • 完全中断嵌套模型(Full interrupt nesting model)
  • 用于极低功耗的 tick-less 能力(A tick-less capability for extreme low power applications)
  • 适当时软件管理的中断栈(Software management interrupt stack when appropriate[this can help save RAM])
1 The FreeRTOS Distribution 1.1 FreeRTOS 文件结构 Freertos port 定义

每种支持的编译器和处理器的组合被认为是一个 freertos port

构建 freertos

Freertos 可以被认为是一个为裸机应用程序提供多任务能力的库。Freertos 是一系列 C 源文件的形式。一些源文件对于所有 freertos port 通用,一些只适用于特定的 freertos port。每个官方的 freertos port 都提供了一个已经配置好的 demo。Demo 应该是拿来就能用,虽然有些发布的比较早,并且只要构建工具一个改变就可能导致构建出现问题。

FreeRTOSConfig.h

Freertos 是通过头文件 FreeRTOSConfig.h 配置的。FreeRTOSConfig.h 为特定应用程序定制 FreeRTOS。例如,其包含了 configUSE_PREEMPTION 等常量,这些常量的设置,定义了会使用协作式调度算法还是抢占式调度算法。FreeRTOSConfig.h 包含了特定应用程序的定义(application specific definitions),其应该放到作为被构建的应用程序的一部分的目录中,而不是放到 FreeRTOS 的源码目录中。推荐从给出的 demo 中相应 port 的 FreeRTOSConfig.h 开始,然后逐步修改适应,无需从头创建。

官方 freertos 的文件结构

在构建应用程序的过程中并不是 freertos 的所有文件都会被用到。文件包含了对所有 freertos port 通用的 freertos 的源码以及 freertos port 相应的 demo project。也包含了 freertos+ 生态的一系列组件和 demo application。

  • Freertos
    • Source:freertos source files
    • demo:预配置的和特定 port 的 freertos demo projects
  • Freertos Plus
    • Source:freertos+ ecosystem components(组件)的源码
    • demo:freertos+ ecosystem components demo projects
通用源文件
  • FreeRTOS
    • Source
      • tasks.c:[通用]
      • list.c:[通用]
      • queue.c:[几乎通用] 提供队列和信号量服务
      • timers.c:[可选] 软件计时器功能
      • event_groups.c:[可选] 事件组
      • croutine.c:[可选] 实现了协程功能,原本是用于非常小的微控制器(Microcontroller)。但是现在很少使用,因此不会维护到和其他特性相同的水平。
特定 FreeRTOS port 的构建

如果你使用名为“arch”架构的处理器,用名为”cp“的编译器进行构建,那么除了核心源文件,还需要和 FreeRTOS/Source/portable/[cp]/[arch] 下的文件一起构建。

  • Freertos
  • Source
    • Portable:containing all port specific source files
      • MenMang: the 5 alternative heap allocation source files
      • [compiler 1]:port files specific to compiler 1
        • [architecture 1 ]:port files specific for the compiler1 architecture 1
        • [architecture 2 ]
      • [compiler 2]
Include path
  1. Freertos 源文件的头文件 FreeRTOS/Soucre/include
  2. 特定 freertos port 的源文件 FreeRTOS/Source/portable/[[compiler]/[architecture]
  3. 到 FreeRTOSConfig.h 的路径
Header Files

一个使用 FreeRTOS API 的源文件必须包含头文件 FreeRTOS.h,然后紧跟着包含要使用的特定函数原型的头文件,例如 task.h、queue.h、semphr.h、timers.h、event_groups.h

1.2 Demo Applications

每个 freertos port 都会至少有一个 demo 可以没有错误和警告的进行构建。FreeRTOS 是在 windows 上开发和测试的,所以当工程在 linux 上进行构建的时候可能偶尔会发生错误。但是错误总是在引用文件名字的时候和字母大小写和斜线的方向有关系。

Demo Application 的目的:

  • 提供一个可以运行的预先配置好的工程,有正确的 include files,和正确的编译选项设置
  • 允许拿出即用的实验,只需要最少的设置和先验知识
  • 如何使用 FreeRTOS 正确使用的演示
  • 提供一个真正的应用程序可以在其上创建的基础

每一个工程都放在 FreeRTOS/Demo 下唯一的子目录中,子目录的名字意义是和 demo 工程相关的 freertos port。所有 demo project 都是通用 demo task 的子集,他们的实现放在 FreeRTOS/Demo/Common/Minimal 目录下。通用代码的存在存粹是为了演示如何使用 FreeRTOS API,他们不实现任何具体的有用的功能。

1.3 创建一个 FreeRTOS 工程 调整提供的 demo project

建议通过调整存在的项目来创建新的项目,这会让工程包含正确的文件,正确安装中断处理程序,以及正确的编译器选项设置。

  1. 打开提供的一个代码,确保它可以按预料的那样构建和执行
  2. 删除定义 demo tasks 的源文件,所有放在 Demo/Common 中的文件都可以删除
  3. 删除 main 函数中除 prvSetupHardware 和 vTaskStartScheduler 外的所有函数调用
  4. 检查项目能否正常构建
int main(void)
{
    prvSetupHardware();
    
    vTaskStartScheduler();
    
    for (;;);
    return 0;
}
从头创建一个新工程

推荐从已有的 demo 创建新的工程,如果这不可取的时候,可以按以下步骤创建新工程:

  1. 使用你的工具链,创建一个新的不包含任何 FreeRTOS 源代码的工程
  2. 确保工程可以被构建,下载到你的目标硬件,然后执行
  3. 确保已有的工程可以工作,然后添加如下文件
  4. tasks.c
  5. queue.c
  6. list.c
  7. timers.c
  8. event_groups.c
  9. All c and assembler files (FreeRTOS/portable/[compiler]/[architecture])
  10. heap_n.c(FreeRTOS/portable/MemMang)
  11. 复制 demo 为当前 port 提供的 project 中的 FreeRTOSConfig.h
  12. 增加下面的头文件搜索路径
  13. FreeRTOS/Source/inlcude
  14. FreeRTOS/Source/portable/[compiler]/[architecture]
  15. 包含 FreeRTOSConfig.h 的目录
  16. 从相关 demo 中复制编译器的设置
  17. 根据相关 demo 和 port 的相关描述,安装任何可能必要的中断处理程序
1.4 数据类型和编码风格
  • TickType_t
    • FreeRTOS 配置了周期的中断称为时钟中断
    • 从 FreeRTOS 应用开始运行,时钟中断的次数被称为 tick count,用来测量时间
    • 两次中断之间的时间,称作时间周期。时间被指定为时间周期的倍数。
    • TickType_t 就是用来保存 tick count 以计算时间的数据类型
    • 可以是 unsigned 16-bit type 也可以是 unsigned 32-bit type,取决于 FreeRTOSConfig.h 中配置的 configUSE_16_BIT_TICKS
    • 使用 uint16 可以提升在 8 位和 16 位架构上的处理效率,但是会严重限制可以计算的最大时间
  • BaseType_t
    • 总是被设置成适合架构的最高效的数据类型。在 32 位架构的机器上就是 32-bit type,16 位架构机器上就是 16-bit type
      一些编译器的 char 是 unsigned 的,一些事 unsigned 的。处于这个原因,FreeRTOS 的代码每次使用 char 都会赋值。除非 char 用来存储 ASCII 字符,或者 char * 指向一个字符串。而且从来不使用 int。
Variable names

前缀:

  • c - char, s - uint16_t, l - uint_32, x - BaseType(以及其他非标准类型)
  • u - unsigned, p - pointer
Function names

前缀:返回值类型 + 函数定义所在的文件

  • vTaskPrioritySet(),返回值为 void,定义在 task.c 中
  • xQueueReceive(),返回值为 BaseType_t,定义在 queue.c
  • pvTimerGetTimerID(),返回值为 void * 的指针,定义在 timers.c
  • 文件内私有函数,前缀为 prv
制表符

一个 tab 等于 4 个空格

宏名

宏以大写形式书写,前缀为小写的宏定义所在位置的文件。信号量 API 几乎全是写为一系列宏,这些宏遵守函数命名规则,而不是宏的命名规则。
贯穿整个 FreeRTOS 的宏定义:

  • pdTRUE 1
  • pdFALSE 0
  • pdPASS 1
  • pdFAIL 0

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/740377.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存