FreeRTOS 移植
说明
本文为个人学习 FreeRTOS 过程中的整理笔记,主要用于知识复习、技术交流与学习分享,并非 FreeRTOS 官方文档。
本文将从 FreeRTOS 的基本概念、源码结构、移植层选择以及 FreeRTOSConfig.h 配置等内容展开,并在文末提供 基于 STM32F103C8T6 + FreeRTOS V11.1.0 完成移植并验证运行的工程,方便读者结合实际工程理解整个移植过程。
文中部分知识点结合 FreeRTOS 官方资料、源码以及其他优秀技术文章进行学习整理;其中部分图片来自B站博主 “铁头山羊” 的相关内容,图片版权归原作者所有。若涉及转载或使用不当,请联系删除或修改。
本文中的文字整理、代码分析以及 FreeRTOS 移植工程均基于本人实际学习和实验过程整理。文末工程主要用于学习和交流,实际项目中请根据具体 MCU、FreeRTOS 版本、编译器及硬件环境重新检查相关配置。
本文实验环境:
STM32F103C8T6 + Cortex-M3 + Keil ARMCC5 + FreeRTOS V11.1.0
不同 FreeRTOS 版本、芯片型号及开发环境下,部分源码、API、配置宏和移植方式可能存在差异,具体请以 FreeRTOS 官方文档及对应版本源码为准。
如文中存在理解错误、表述不严谨或工程配置问题,欢迎交流指正。
FreeRTOS 移植
FreeRTOS 下载: https://freertos.org/

1. FreeRTOS 到底是什么
FreeRTOS 不是一种编程语言,也不是 STM32 芯片内部自带的功能。
它本质上是:
一套使用 C 语言和少量汇编语言编写的实时操作系统内核源码。
可以简单理解为:
你的 STM32 工程
│
├── 你自己写的代码
│ ├── main.c
│ ├── led.c
│ ├── can.c
│ └── adc.c
│
└── FreeRTOS 源码
├── tasks.c
├── queue.c
├── list.c
├── port.c
└── heap_4.c
当我们把 FreeRTOS 源码加入工程后,FreeRTOS 源码会和自己编写的代码一起参与:
编译
↓
链接
↓
生成 STM32 能够执行的机器码
↓
下载到 Flash
所以:
FreeRTOS 不是一个独立运行的软件,而是会被编译进 STM32 程序中,与应用程序一起运行。
2. FreeRTOS 移植文件选择

FreeRTOS 需要支持很多不同的 CPU 架构,例如:
Cortex-M0
Cortex-M3
Cortex-M4
Cortex-M7
RISC-V
ESP32
这些 CPU 的:
寄存器
指令集
中断机制
都可能不同。
但是:
任务管理
队列
链表
等内核逻辑,在不同 CPU 上基本是相似的。
因此,FreeRTOS 源码可以大致分成两部分:
FreeRTOS
├── 通用内核
└── 移植层
2.1 通用内核是什么
通用内核是与具体 CPU 架构关系相对较小的部分。
典型文件包括:
tasks.c
queue.c
list.c
timers.c
event_groups.c
stream_buffer.c
主要实现:
任务优先级管理
任务状态管理
就绪链表管理
阻塞链表管理
队列收发逻辑
信号量逻辑
软件定时器逻辑
事件组逻辑
这些逻辑在 Cortex-M3 和 Cortex-M4 等平台上基本一致,所以可以复用同一套 C 语言内核代码。
2.2 移植层
移植层英文通常称为:
Portable Layer
简称:
Port
移植层负责处理:
与具体 CPU 架构和编译器有关的底层操作。
例如:
任务栈最开始怎样初始化
任务上下文怎样保存
任务上下文怎样恢复
PendSV 中断怎样切换任务
SVC 怎样启动第一个任务
临界区怎样关闭中断
栈的数据类型是什么
CPU 对齐要求是什么
这些内容和 CPU 架构密切相关。
例如 STM32F103 使用的是:
ARM Cortex-M3
因此需要选择适用于:
Cortex-M3
的移植层。
2.3 工具链

即使使用相同的 Cortex-M3 内核,也可能使用不同的编译器:
Keil ARMCC
Keil ARMClang
GCC
IAR
虽然 CPU 都是 Cortex-M3,但不同编译器在以下方面可能存在差异:
汇编语法
函数属性写法
内联汇编语法
调用约定
关键字
编译器宏
因此选择 FreeRTOS 移植层时,不能只看 CPU,还需要看编译器。
需要同时满足:
CPU 架构正确
+
编译器正确
例如:
STM32F1 系列:
CubeIDE + STM32F1
=
GCC + ARM_CM3
Keil ARMCC5 + STM32F1
=
RVDS + ARM_CM3
而使用较新的 Keil ARMClang 编译器时,需要选择与 ARMClang 对应的移植目录。
3. FreeRTOS 内核文件架构
3.1 FreeRTOS 源码整体目录结构


3.2 tasks.c
tasks.c 主要负责:
任务管理和调度相关功能。
大量任务相关 API 都在其中实现,例如:
// 动态创建任务
xTaskCreate();
// 相对延时,使当前任务进入阻塞状态
vTaskDelay();
// 删除指定任务
vTaskDelete();
// 挂起任务
vTaskSuspend();
// 恢复被挂起的任务
vTaskResume();
// 启动 FreeRTOS 调度器
vTaskStartScheduler();
可以简单记忆:
tasks.c= FreeRTOS 的任务管理中心。
3.3 queue.c
queue.c 内部不仅实现了 Queue,还包含与以下内核对象相关的底层逻辑:
Semaphore
二值信号量
用于任务间同步、中断通知任务
Mutex
互斥锁
用于共享资源独占保护
Recursive Mutex
递归互斥锁
用于需要递归获取同一个互斥量的场景
Counting Semaphore
计数信号量
用于多资源或事件计数
因此:
FreeRTOS 内部的信号量和互斥量都建立在 Queue 的底层机制之上。
3.4 list.c
list.c 主要实现:
FreeRTOS 内部使用的链表数据结构。
例如:
就绪任务列表
├── Task1
└── Task2
延时任务列表
├── TaskA
└── TaskB
这些任务状态管理都需要使用链表。
因此:
list.c不是普通的工具文件,而是 FreeRTOS 调度器的重要数据结构基础。
3.5 port.c——CPU 适配层
可以先建立一个简单理解:
tasks.c决定什么时候需要进行任务切换,而port.c负责完成与 CPU 架构相关的实际切换工作。
当系统准备切换任务时,内核需要处理:
STM32 寄存器怎样保存
SP 怎样处理
PSP 怎样恢复
PendSV 怎样执行
任务上下文怎样恢复
这些操作与 CPU 架构密切相关。
因此,真正涉及:
保存 R4~R11
恢复 R4~R11
处理 PSP
PendSV 上下文切换
等 Cortex-M3 底层操作的代码,主要位于移植层。
可以简单记忆:
port.c= 与 CPU 架构相关的移植代码。
3.6 portmacro.h——CPU 相关类型和宏定义
portmacro.h 会告诉 FreeRTOS 内核:
BaseType_t 是什么类型
TickType_t 是什么类型
StackType_t 是什么类型
例如:
// 定义任务栈基本数据类型
typedef uint32_t StackType_t;
对于 STM32 Cortex-M3:
一个 StackType_t
=
32 bit
=
4 Byte
因此在理解 FreeRTOS:
任务栈大小
栈深度
CPU 数据宽度
等问题时,会用到 portmacro.h 中的定义。
3.7 heap_4.c——FreeRTOS 动态内存管理器
在使用动态创建方式时,FreeRTOS 中很多内核对象需要从 Heap 中申请空间,例如:
任务栈
TCB
Queue
Semaphore
Mutex
当前使用:
heap_4.c
作为 FreeRTOS 的动态内存管理方案。
3.8 文件职责归纳
| 文件 | 主要职责 | 是否与 CPU 相关 |
|---|---|---|
tasks.c | 任务管理、调度器、任务 API | ❌ 基本与 CPU 无关 |
queue.c | 队列、信号量、互斥量 | ❌ 基本与 CPU 无关 |
list.c | 链表数据结构,维护各种任务列表 | ❌ 基本与 CPU 无关 |
timers.c | 软件定时器 | ❌ 基本与 CPU 无关 |
event_groups.c | 事件组 | ❌ 基本与 CPU 无关 |
stream_buffer.c | 流缓冲区、消息缓冲区 | ❌ 基本与 CPU 无关 |
heap_4.c | FreeRTOS 动态内存管理 | ❌ 基本与 CPU 无关 |
port.c | 上下文切换、异常处理、临界区等移植实现 | ✅ CPU / Port 相关 |
portmacro.h | CPU 相关类型定义和宏 | ✅ CPU / Port 相关 |
FreeRTOSConfig.h | 用户配置、功能裁剪、系统参数 | ⚠️ 与平台和项目配置相关 |
4. 高频问题
4.1 为什么更换 STM32 型号时,大部分 FreeRTOS 源码不用修改?
因为
tasks.c、queue.c、list.c等主要实现的是通用内核逻辑,它们与具体 CPU 架构的耦合较低。真正依赖 CPU 寄存器、异常机制和上下文切换方式的是
port.c、portmacro.h等移植层代码。因此,更换 CPU 架构时,主要需要重新选择与目标 CPU 和编译器匹配的 Port。
4.2 为什么 port.c 不能删除?
因为
port.c实现了与 CPU 架构相关的底层功能,例如任务上下文切换、异常处理和临界区相关操作。对 Cortex-M3 Port 来说,任务切换会依赖 PendSV、SVC 等异常机制。
如果没有正确的移植层,FreeRTOS 内核就无法正常完成任务启动和上下文切换。
三、FreeRTOSConfig.h 文件配置
1. 配置原则
FreeRTOSConfig.h 并不是:
功能打开得越多越好。
也不能为了让当前简单示例快速运行,就把大量功能全部关闭。
配置项可以分为三类。
1.1 平台适配项
必须与当前使用的平台一致:
STM32F103C8
Cortex-M3
ARMCC5
对应的 FreeRTOS Port
如果配置错误,可能导致:
编译失败
调度器无法启动
进入 HardFault
系统 Tick 错误
延时时间错误
中断优先级配置异常
1.2 稳定性与调试项
建议从项目早期就考虑开启,例如:
configASSERT
栈溢出检测
Malloc 失败 Hook
任务栈水位查询
这些配置有助于后续定位:
内存不足
栈溢出
非法配置
任务栈使用异常
等问题。
1.3 项目规模相关项
下面这些配置不存在适用于所有项目的唯一数值:
Tick 频率
最大优先级数量
Heap 大小
软件定时器任务栈
需要根据:
任务数量
RAM 使用情况
系统实时性要求
实际测量结果
进行调整。
2. FreeRTOSConfig.h 修改总表
| 原始位置 | 宏或配置项 | 建议 | 类型 |
|---|---|---|---|
| 43 后 | #include "stm32f10x.h" | 新增 | 必须 / 推荐 |
| 54 | configCPU_CLOCK_HZ | 改为 SystemCoreClock | 必须检查 |
| 69 | configSYSTICK_CLOCK_HZ | 保持注释 | 必须确认 |
| 78 | configTICK_RATE_HZ | 通用学习基线可先设为 1000 | 项目相关 |
| 90 后 | configNUMBER_OF_CORES | 新增为 1 | 推荐明确 |
| 98 | configUSE_PORT_OPTIMISED_TASK_SELECTION | 改为 1 | 推荐 |
| 109 | configMAX_PRIORITIES | 可先设为 8,后续根据项目架构调整 | 项目相关 |
| 152 | configQUEUE_REGISTRY_SIZE | 调试版本建议设为 8 | 调试推荐 |
| 195 | configSTATS_BUFFER_MAX_LENGTH | 建议设为 1024 | 调试推荐 |
| 218 | configUSE_TIMERS | 保持 1,同时编译 timers.c | 功能一致性 |
| 248 | configUSE_EVENT_GROUPS | 保持 1,同时编译 event_groups.c | 功能一致性 |
| 259 | configUSE_STREAM_BUFFERS | 保持 1,同时编译 stream_buffer.c | 功能一致性 |
| 283 | configTOTAL_HEAP_SIZE | STM32F103C8 初始可设为 6 KB | 项目相关 |
| 311、319 | 内核 / 系统调用中断优先级 | 改为基于 __NVIC_PRIO_BITS 的写法 | 强烈推荐 |
| 323 | configMAX_API_CALL_INTERRUPT_PRIORITY | 与 configMAX_SYSCALL_INTERRUPT_PRIORITY 保持一致 | 推荐 |
| 335 | configUSE_MALLOC_FAILED_HOOK | 改为 1 | 稳定性推荐 |
| 357 | configCHECK_FOR_STACK_OVERFLOW | 保持 2 | 稳定性推荐 |
| 373 | configUSE_TRACE_FACILITY | 调试版本可改为 1 | 调试可选 |
| 409 | configASSERT | 改成可记录文件和行号的版本 | 强烈推荐 |
| 562 | configKERNEL_PROVIDED_STATIC_MEMORY | 保持 1 | 与静态分配配置一致 |
| 572 | configENABLE_TRUSTZONE | 改为 0 | 必须 |
| 579 | configRUN_FREERTOS_SECURE_ONLY | 改为 0 | 必须 |
| 583 | configENABLE_MPU | 改为 0 | 必须 |
| 587 | configENABLE_FPU | 改为 0 | 必须 |
| 594 | configENABLE_MVE | 改为 0 | 必须 |
| 612 | configCHECK_HANDLER_INSTALLATION | 保持 1 | 推荐 |
| 639 | INCLUDE_uxTaskGetStackHighWaterMark | 改为 1 | 调试推荐 |
| 641 | INCLUDE_eTaskGetState | 改为 1 | 调试推荐 |
| 648 前 | SVC、PendSV、SysTick 映射 | 新增三个宏 | 必须 |
更多推荐
所有评论(0)