Chapter 1 FreeRTOS 分布
1.1 引言
该章节帮助了解FreeRTOS ZIP的内容分布,方便读者能对FreeRTOS产生明确定位。
- 提供FreeRTOS的顶层视图
- 描述具体某个项目需要哪些文件
- 介绍演示应用程序
- 提供如何创建新项目的信息
1.2 理解FreeRTOS分布
-
定义:FreeRTOS端口
FreeRTOS可以被20多种编译器构建
可以在30多种处理器架构上运行
编译器+处理器的组合即为一种端口
-
构建FreeRTOS
FreeRTOS可被认为是一个库文件,为裸机提供多任务功能
每个端口都配有配置例程,包含配置源文件与头文件。
-
FreeRTOSConfig.h
FreeRTOS的配置文件
该文件属于正在构建的应用程序目录,不属于源文件(因为是需要配置的)。
-
FreeRTOS官方发行版本
通过一个zip压缩包发行,包含了所有的端口配置例程。
-
FreeRTOS发行版的*目录
- FreeRTOS
- Source
- Demo
- FreeRTOS-Plus
- Source
- Demo
- FreeRTOS
-
FreeRTOS源文件适配所有端口
- 核心FreeRTOS源代码仅包含在tasks.c和list.c中(FreeRTOS/Source)
- Source文件中还包含有:
- queue.c(提供队列和信号量服务)
- timers.c(提供软件定时器功能)
- event_groups.c(提供事件组功能)
- croutine.c(共同例程功能,不重要)
-
特定于端口的FreeRTOS源文件
包含在FreeRTOS/Source/portable目录(第二章详述)
FreeRTOS将堆内存管理作为可移植层的一部分,提供了五个堆分配示例(heap_1到heap_5)
-
包含路径
FreeRTOS要求编译器包含三个路径:
- FreeRTOS/Source/include(始终包含,核心FreeRTOS头文件)
- FreeRTOS/Source/portable/[compiler]/[architecture](正在使用端口的源文件)
- FreeRTOSConfig.h
-
头文件
- FreeRTOS.h
- 调用的API任务的头文件:
- task.h
- queue.h
- timer.h
- event_groups.h
1.3 演示应用程序
演示应用程序目的:
- 提供一个工作和预配置项目的示例(正确的文件和正确的编译器选项集)
- 允许“开箱即用”的实验,只需最少的设置或事先了解。
- 演示如何使用FreeRTOS API
- 作为实际项目的基础
1.4 建立一个FreeRTOS项目
-
调整演示项目之一
-
打开源文件
-
删除main函数中除"prvSetupHardware()"和"vTaskStartScheduler()"的函数
-
检查是否能够编译
-
-
从头开始创建新项目
-
创建新项目(不含FreeRTOS)
-
添加FreeRTOS源文件到项目中
-
将FreeRTOSConfig.h头文件复制到项目目录中(从对应端口的演示项目中Copy)
-
将以下目录添加到path
- FreeRTOS/Source/include
- FreeRTOS/Source/portable/[compiler]/[architecture]
- 包含FreeRTOSConfig.h的目录
-
从演示项目复制编译器设置
-
安装FreeRTOS中断处理程序
-
早版本的FreeRTOS还需要配置"heap_n.c"文件
-
1.5 数据类型与编码规范
-
数据类型
每个端口都有独立的"portmacre.h"头文件
该头文件包含了两个端口特定数据类型定义"TickType_t"、"BaseType_t"
-
TickType_t
滴答周期中断,"tick period"用于计量FreeRTOS应用启动以来发生的滴答中断次数。
TickType_t是用于保存tick period和时间的数据结构
-
BaseType_t
BaseType_t只能接受非常有限的值范围的返回类型
-
-
变量名
c——char
s——int16_t
l——int32_t
x——BaseType_t
u——unsigned
p——pointer
-
函数名
函数的前缀——返回类型/函数其中定义的文件
- vTaskPrioritySet()——返回void,并在task.c中定义
- xQueueReceive()——返回BaseType_t类型变量,并在queue.c中定义
- pvTimerGetTimerID()——返回空指针(a pointer to void),并在timer.c中定义
-
格式
一个Tab等于四个空格
-
宏命名
大多数宏都是以小写字母为前缀的大写字母命名
- port——portMAX_DELAY
- task——taskENTER_CRITICAL
- pd——configUSE_PREEMPTION
- err——errQUEUE_FULL
信号量API几乎都是作为宏编写,但却遵循函数命名约定。(不是宏命名约定)
-
强制转换的基本原理
不同编译器希望以不同方式实现强制类型转换
FreeRTOS源代码中包含更多的强制类型转换
Chapter 2 堆内存管理(heap)
2.1 引言
- 预备知识
- 动态内存分配与FreeRTOS的相关性
- 动态内存分配选项
- 总结
2.2 内存分配示例
- heap_1
- heap_2
- heap_3
- heap_4
- heap_5
- vPortDefineHeapRegions() API函数
2.3 与堆相关的函数
- xPortGetFreeHeapSize()
- xPortGetMinimumEverFreeHeapSize()
- Malloc失败的钩子函数
Chapter 3 任务管理
3.1 引言
总结
3.2 任务函数
3.3 *任务状态
3.4 创建任务
3.5 任务优先级
3.6 时间测量与滴答中断
3.7 扩展“未运行”状态
- Blocked状态
- Suspended(挂起)状态
- Ready(就绪)状态
- 完成状态转换图
- vTaskDelayUntil() 函数
3.8 Idle(空闲)任务和空闲任务钩子
- 空闲任务钩子函数
- 对空闲任务钩子函数实现的限制
3.9 更改任务的优先级
- vTaskPrioritySet() 函数
- uxTaskPriorityGet() 函数
3.10 删除任务
- vTaskDelete() 函数
3.11 线程本地存储
3.12 调度算法
-
任务状态和事件的概述
-
配置调度算法
-
带时间切片的优先抢占式调度
-
优先抢占式调度(无时间切片)
-
合作调度
Chapter 4 队列管理
4.1 引言
总结
4.2 队列的特征
- 多任务访问
- 阻塞队列读取
- 阻塞队列写入
- 阻塞多个队列
4.3 使用一个队列
- xQueueCreate() 函数
- xQueueSendToBack() 和 xQueueSendToFront() 函数
- xQueueReceive() 函数
- uxQueueMessagesWaiting() 函数
4.4 从多个来源接收数据
4.5 处理大型/可变大小数据
- 队列指针
- 使用队列发送不同类型和长度的数据
4.6 从多个队列接收数据
- 队列集
- xQueueCreateSet() 函数
- xQueueAddToSet() 函数
- xQueueSelectFromSet() 函数
- 更多实际的队列集用例
4.7 使用队列创建邮箱
- xQueueOverwrite() 函数
- xQueuePeek() 函数
Chapter 5 软件定时器管理
5.1 引言
总结
5.2 软件定时器回调函数
5.3 软件定时器的属性和状态
- 软件定时器的周期
- 一次性和自动重加载定时器
- 软件定时器状态
5.4 软件定时器的上下文
- RTOS守护进程服务
- 定时器命令队列
- 守护进程任务调度
5.5 创建和启动任务定时器
- xTimerCreate() 函数
- xTimerStart() 函数
5.6 定时器ID
- vTimerSetTimerID() 函数
- pvTimerGetTimerID() 函数
5.7 更改定时器周期
- xTimerChangePeriod() 函数
5.8 重置软件定时器
- xTimerReset() 函数
Chapter 6 中断管理
6.1 引言
- 事件
- 总结
6.2 从ISR使用FreeRTOS API
- 中断安全API
- 使用单独的中断安全API的好处
- 使用单独的中断安全API的缺点
- xHigherPriorityTaskWoken 参数
- portYIELD_FROM_ISR() 和 portEND_SWITCHING_ISR()宏
6.3 延迟中断处理
6.4 用于同步的二进制信号量
- xSemaphoreCreateBinary() 函数
- xSemaphoreTask() 函数
- xSemaphoreGiveFromISR() 函数
6.5 计数信号量
- xSemaphoreCreateCounting() 函数
6.6 将工作推迟到RTOS守护进程任务
- xTimerPendFunctionCallFromISR() 函数
6.7 再中断服务例程中使用队列
- xQueueSendToFrontFromISR 和 xQueueSendToBackFromISR 函数
- 使用ISR队列的注意事项
6.8 中断嵌套
Chapter 7 资源管理
7.1 引言
- 进程互斥
- 总结
7.2 关键部分和挂起调度程序
- 基本临界截面
- 挂起(或锁定)调度
- xTaskSuspendAll() 函数
- xTaskResumeAll() 函数
7.3 互斥量(和二进制信号量)
- xSemaphoreCreateMutex() 函数
- 优先级反转
- 优先级继承
- 死锁(Deadlock)
- 递归互斥
- 互斥体和任务调度
7.4 守门员任务
Chapter 8 时间组
8.1 引言
总结
8.2 事件组的特征
- 事件组、事件标志和事件位
- "EventBits_t"数据类型
- 多任务访问
- 使用事件组的实际示例
8.3 使用事件组的事件管理
- xEventGroupCreate() 函数
- xEventGroupSetBits() 函数
- xEventGroupSetBitsFromISR() 函数
- xEventGroupWaitBits() 函数
8.4 使用事件组的任务同步
- xEventGroupSync() 函数
Chapter 9 任务通知
9.1 引言
- 通过中间对象进行通信
- 任务通知——直接与任务通信
- 总结
9.2 任务通知的优点与缺陷
- 任务通知的性能优势
- 任务通知的RAM占用优势
- 任务通知的限制
9.3 使用任务通知
- 任务通知API选项
- xTaskNotifyGive() 函数
- xTaskNotifyGiveFromISR() 函数
- ulTaskNotifyTake() 函数
- xTaskNotify() 和 xTaskNotifyFromISR() 函数
- xTaskNotifyWait() 函数
- 外围设备驱动程序使用任务通知——串口例子
- 外围设备驱动程序使用任务通知——ADC例子
- 直接在应用程序中使用的任务通知