FreeRTOS 移植总结 — LPC55S69目标板: LPC55S69JBD100 (Cortex-M33, 150MHz, 608KB Flash, 272KB RAM)编译器: ARMCLANG V6.16 (Keil MDK-ARM V5.42)IDE: Keil µVision V5FreeRTOS 内核版本: V11.1.0 (LTS — 2024.06)SDK: MCUXpresso SDK (LPC55S69_DFP.26.06.00)移植日期: 2026-07-18一、下载操作系统代码库下载地址: https://freertos.org/zh-cn点击 “Download” → 选择 “FreeRTOS Kernel” → 下载案例包下载网址(chrome/夸克打开):http://103.236.97.252:48791点击 “Download” → 选择FreeRTOS 202406.05 LTS。解压后得到源码目录FreeRTOS 内核源码路径D:\freertos\FreeRTOSv202406.05-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\关键目录结构FreeRTOS-Kernel/ ├── include/ ← 所有头文件22 个 .h ├── *.c ← 内核源文件7 个 .c │ ├── tasks.c │ ├── queue.c │ ├── list.c │ ├── timers.c │ ├── event_groups.c │ ├── stream_buffer.c │ └── croutine.c ← 协程不推荐使用 └── portable/ ├── ARMv8M/non_secure/ ← Cortex-M33/ARMv8-M 移植层 │ ├── port.c ← 通用移植代码 │ ├── portasm.h ← 汇编函数声明 │ ├── portmacrocommon.h ← ARMv8-M 公共宏 │ └── portable/ │ ├── GCC/ │ │ └── ARM_CM33_NTZ/ ← 本工程选用此目录 │ │ ├── portmacro.h ← CM33 特定宏 │ │ └── portasm.c ← 汇编实现 (SVC/PendSV/SysTick) │ └── IAR/ │ └── ARM_CM33_NTZ/ │ └── portmacro.h └── MemMang/ ← 内存管理方案 ├── heap_1.c ~ heap_5.c └── heap_4.c ← 本工程选用 heap_4二、工程中新建文件夹在裸机工程根目录下创建以下目录结构hello_world_cm33_core0/ └── FreeRTOS/ ├── include/ ← 存放 FreeRTOS 头文件 ├── src/ ← 存放 FreeRTOS 内核源文件 ├── portable/ │ └── MemMang/ ← 存放内存管理文件 └── config/ ← 存放 FreeRTOSConfig.h与 STM32 移植的差异LPC55S69 是 Cortex-M33移植层使用ARMv8M/non_secure。移植文件不放进编译器子目录如portable/GCC/ARM_CM33_NTZ/而是统一放在portable/根目录下通过 include path 让port.c能找到portmacro.h和portasm.h。这种扁平化布局是因为 ARMv8M 版本的port.c位于non_secure/根目录它通过#include portmacro.h和#include portasm.h引用同目录下的文件不深入编译器子目录。三、拷贝移植文件3.1 头文件 — 拷贝到FreeRTOS/include/从FreeRTOS-Kernel/include/拷贝全部 22 个文件文件名说明FreeRTOS.h主头文件 — TickType 定义、配置校验、API 重定向task.h任务管理 APIqueue.h队列 APIsemphr.h信号量 APItimers.h软件定时器 APIevent_groups.h事件组 APIstream_buffer.h流缓冲区 APImessage_buffer.h消息缓冲区 APIlist.h链表数据结构内核内部使用croutine.h协程 APIportable.h移植层抽象接口projdefs.h内核宏定义StackMacros.h栈检查宏stack_macros.h栈检查宏 — 小写版atomic.h原子操作deprecated_definitions.h废弃 API 兼容宏mpu_prototypes.hMPU 内存保护函数原型mpu_wrappers.hMPU 包装宏mpu_syscall_numbers.hMPU 系统调用号newlib-freertos.hNewlib C 库集成picolibc-freertos.hPicoLibc C 库集成3.2 内核源码 — 拷贝到FreeRTOS/src/从FreeRTOS-Kernel/拷贝7 个 .c 文件文件名说明tasks.c任务管理核心 — 调度器、任务创建/删除、栈溢出检测、Idle 任务queue.c队列核心 — 队列、信号量、互斥锁list.c链表操作 — 内核数据结构timers.c软件定时器event_groups.c事件组stream_buffer.c流缓冲区和消息缓冲区croutine.c协程可省略configUSE_CO_ROUTINES0时不编译3.3 移植层 — 拷贝到FreeRTOS/portable/这是 ARMv8M 移植与 STM32ARMv7-M/ARM_CM4F最大的不同移植层拆成了 4 个文件分布于两个层级。序号源文件目标位置说明1ARMv8M/non_secure/port.cportable/port.c通用移植代码2ARMv8M/non_secure/portasm.hportable/portasm.h汇编函数声明3ARMv8M/non_secure/portmacrocommon.hportable/portmacrocommon.hARMv8-M 公共宏4ARMv8M/non_secure/portable/GCC/ARM_CM33_NTZ/portmacro.hportable/portmacro.hCM33 ARMCLANG 特定宏5ARMv8M/non_secure/portable/GCC/ARM_CM33_NTZ/portasm.cportable/portasm.c汇编实现SVC/PendSV/SysTick handler关键ARMCLANG 兼容 GCC 内联汇编语法所以选用GCC/ARM_CM33_NTZ子目录的portmacro.h和portasm.c。不要选IAR/下的文件。STM32 移植通常只有port.cportmacro.h两个文件而 ARMv8M 版本多出portasm.c和portasm.h漏掉任何一个都会导致编译/链接失败。3.4 内存管理 — 拷贝到FreeRTOS/portable/MemMang/从FreeRTOS-Kernel/portable/MemMang/选择1 个文件文件名说明heap_4.c首次适配 相邻空闲块合并最推荐的单核方案四、编写 FreeRTOSConfig.hFreeRTOS/config/FreeRTOSConfig.h以官方模板为起点针对 LPC55S69 (Cortex-M33)修改 9 处。此文件来自官方模板文件源路径为D:\freertos\FreeRTOSv202406.05-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\examples\template_configuration\FreeRTOSConfig.h改动 ①tick 频率 (第 78 行)修改前修改后#define configTICK_RATE_HZ 100#define configTICK_RATE_HZ 1000100Hz 10ms tick粒度太粗。1000Hz 1ms tick 是主流选择。改动 ②开启时间片轮转 (第 90 行)修改前修改后#define configUSE_TIME_SLICING 0#define configUSE_TIME_SLICING 1改动 ③tick 类型位宽 (第 135 行)修改前修改后#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_32_BITSCortex-M33 是 32 位架构64 位 tick 每个 tick 都要做 64 位运算白白浪费性能。32 位 tick 在 1000Hz 下约 49 天溢出完全够用。改动 ④增大内核堆 (第 283 行)修改前修改后#define configTOTAL_HEAP_SIZE 4096#define configTOTAL_HEAP_SIZE 10*1024每个任务 TCB stack 从 FreeRTOS 堆中分配。4KB 只能勉强支持 2~3 个轻量任务。10KB 适合入门验证。改动 ⑤中断优先级 — 致命配置 (第 311–315 行)修改前修改后#define configKERNEL_INTERRUPT_PRIORITY 0#define configPRIO_BITS 3#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0#define configKERNEL_INTERRUPT_PRIORITY ( 7 ( 8 - configPRIO_BITS ) )#define configMAX_API_CALL_INTERRUPT_PRIORITY 0#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 1 ( 8 - configPRIO_BITS ) )这是 Cortex-M 移植最常见的致命错误。ARM Cortex-M NVIC 使用 bits [7:5] 表示优先级3 位优先级宏值必须左移到寄存器位。0xE0 逻辑优先级 7最低给 SysTick/PendSV0x20 逻辑优先级 1高于此优先级的中断不受 RTOS 管控。如果全部设为 0portasm.c内联汇编中basepri0无法屏蔽任何中断编译还会触发#error。同时删除多余的configMAX_API_CALL_INTERRUPT_PRIORITY已废弃被configMAX_SYSCALL_INTERRUPT_PRIORITY替代。改动 ⑥关闭 TrustZone (第 578、585 行)修改前修改后#define configENABLE_TRUSTZONE 1#define configENABLE_TRUSTZONE 0#define configRUN_FREERTOS_SECURE_ONLY 1#define configRUN_FREERTOS_SECURE_ONLY 0原始 hello_world 是普通 non-secure 单核应用不需要 TrustZone。两个宏同时为 1 构成逻辑矛盾开启 TZ 又声称只跑在 Secure 侧。改动 ⑦关闭 MPU (第 589 行)修改前修改后#define configENABLE_MPU 1#define configENABLE_MPU 0开启 MPU 需要额外链接mpu_wrappers_v2.c和mpu_wrappers_v2_asm.c还会使portasm.c中大量#if ( configENABLE_MPU 1 )的代码路径生效增大代码体积。入门移植先关闭。改动 ⑧关闭 MVE (第 594 行)修改前修改后#define configENABLE_MVE 1#define configENABLE_MVE 0会直接导致编译报错#error。MVE (M-Profile Vector Extension) 是 Cortex-M55/M85 才有的向量扩展指令Cortex-M33 不支持。portmacro.h第 62 行有硬检查#elif(configENABLE_MVE!0)#errorconfigENABLE_MVE must be left undefined,or defined to0forthe Cortex-M33.改动 ⑨保留 FPU 开启 (第 593 行)#defineconfigENABLE_FPU1// ← 保持为 1LPC55S69 有 FPULPC55S69 集成单精度 FPU (SFPU)工程中CpuCPUTYPE(Cortex-M33) FPU3(SFPU) TZ DSP/Cpu已声明。五、Keil 工程配置5.1 添加头文件搜索路径操作: Options for Target (AltF7) → C/C(AC6) 标签页 → Include Paths → 末尾新增 3 个路径.\FreeRTOS\include;.\FreeRTOS\config;.\FreeRTOS\portable完整路径board;CMSIS;CMSIS/m-profile;component/uart;device;device/periph;drivers;utilities;utilities/debug_console_lite;utilities/str;..\hello_world_cm33_core0;.\source;.\FreeRTOS\include;.\FreeRTOS\config;.\FreeRTOS\portable同样在Asm标签页也添加这三个路径。debug 和 release 两个 Target 都要改。5.2 在工程中新增 File Group在 Keil 左侧 Project 窗口中创建以下分组并添加对应文件Group 名称添加的文件FreeRTOS/srcFreeRTOS\src\tasks.c、queue.c、list.c、timers.c、event_groups.c、stream_buffer.c、croutine.cFreeRTOS/portableFreeRTOS\portable\port.c、portasm.c、MemMang\heap_4.c注意文件类型选择All Files才能看到portasm.c不需要添加.h头文件到分组编译器通过 include path 自动查找debug 和 release 两个 Target 都要添加确保Include in Target Build勾选croutine.c虽然添加了但configUSE_CO_ROUTINES0时不参与实际编译5.3 编译器选项现有 Misc Controls 保持不变-include source/mcux_config.h -include source/mcuxsdk_version.h -fno-common -fdata-sections -fno-builtin -mthumbarmclang兼容 GCC 内联汇编语法无需像 ARMCC V5 那样替换为__asm{}块不需要开启 Keil RTX OS 支持选项mOS0/mOS保持关闭六、修改工程现有文件6.1 启动文件 —startup/arm/startup_LPC55S69_cm33_core0.S无需修改。启动文件中 SVC_Handler、PendSV_Handler、SysTick_Handler 全部是.weak声明.weak SVC_Handler .weak PendSV_Handler .weak SysTick_Handler.weak意味着链接器会优先使用port.c/portasm.c中定义的同名强符号。与 STM32 移植不同不需要在 FreeRTOSConfig.h 中添加#define vPortSVCHandler SVC_Handler等宏映射——因为 ARMv8M 版portasm.c中直接定义了SVC_Handler、PendSV_Handler函数名与启动文件向量表中的符号名天然匹配。6.2 主程序 —source/hello_world.c必须添加栈溢出钩子函数configCHECK_FOR_STACK_OVERFLOW 2要求voidvApplicationStackOverflowHook(TaskHandle_t xTask,char*pcTaskName){(void)xTask;(void)pcTaskName;for(;;){/* 死循环调试时在此打断点定位溢出任务 */}}七、调试过程中遇到的错误序号报错/现象根本原因解决方法1error: portmacro.h file not found— 9 个错误portmacro.h未从编译器子目录复制到portable/根目录从ARMv8M/non_secure/portable/GCC/ARM_CM33_NTZ/portmacro.h复制到FreeRTOS/portable/portmacro.h2error: portasm.h file not found— 1 个错误port.c依赖portasm.h但该文件未复制从ARMv8M/non_secure/portasm.h复制到FreeRTOS/portable/portasm.h3L6218E: Undefined symbol ulSetInterruptMaskL6218E: Undefined symbol vClearInterruptMaskL6218E: Undefined symbol vRestoreContextOfFirstTaskL6218E: Undefined symbol vStartFirstTask— 4 个错误portasm.c未加入 Keil 工程编译这几个函数全部在portasm.c中实现Keil 工程 FreeRTOS/portable 分组中添加portasm.c同时需将portasm.h放到portable/目录include path 已配置4L6218E: Undefined symbol vApplicationStackOverflowHook— 1 个错误configCHECK_FOR_STACK_OVERFLOW 2开启栈检测但未提供回调函数在hello_world.c中添加空实现八、ARMv8M 移植与 STM32 ARMv7-M 移植的关键差异总结对比维度STM32F407 (ARMv7-M/CM4F)LPC55S69 (ARMv8-M/CM33)移植层目录portable/RVDS/ARM_CM4F/portable/ARMv8M/non_secure/移植文件数量2 个port.cportmacro.h5 个port.cportmacrocommon.hportasm.hportmacro.hportasm.c汇编文件汇编内嵌在port.c中独立portasm.c文件ISR 命名vPortSVCHandler等 → 需要宏映射SVC_Handler等 → 直接匹配启动文件中断优先级位数4 bitbits [7:4]3 bitbits [7:5]优先级宏值0xF0/0x500xE0/0x20FPU 支持portable/RVDS/ARM_CM4F内置portmacro.h宏configENABLE_FPU1控制TrustZone不支持支持本移植中关闭编译器ARMCC V5 → 需要替换内联汇编语法ARMCLANG V6 → 直接兼容 GCC 语法九、验证结果移植完成后编译 0 错误 0 警告链接成功生成hello_world_cm33_core0.out。最终工程结构hello_world_cm33_core0/ ├── FreeRTOS/ │ ├── include/ ← 22 个 .h │ ├── src/ ← 7 个 .c │ ├── portable/ ← port.c, portasm.c, portasm.h, portmacro.h, portmacrocommon.h │ │ └── MemMang/ │ │ └── heap_4.c │ ├── config/ │ │ └── FreeRTOSConfig.h ├── source/ │ └── hello_world.c ├── startup/arm/ │ └── startup_LPC55S69_cm33_core0.S ├── board/ ├── CMSIS/ ├── drivers/ ├── device/ ├── utilities/ ├── component/ └── hello_world_cm33_core0.uvprojx