安装与部署:把 FreeRTOS 接进 Cortex-M 工程
安装与部署:把 FreeRTOS 接进 Cortex-M 工程
接入方式有三种,优先选第一种:厂商 SDK 或 IDE 里已经带了 FreeRTOS(STM32CubeMX 勾选 FreeRTOS、MCUXpresso、ESP-IDF 内置),配置项通过图形化工具或配置系统暴露;第二种是从官方 FreeRTOS-Kernel 仓库取源码手工集成;第三种是拿别人调好的模板工程改。下面讲手工集成这条路径,搞清它,另两种都不难。
- 取源码。
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git # 主要目录: # Source/ 内核通用实现 # tasks.c queue.c list.c timers.c event_groups.c stream_buffer.c # Source/include/ 内核公共头文件 # Source/portable/ 移植层,按「编译器/内核」两级组织 # 例如 GCC/ARM_CM4F、IAR/ARM_CM4F、Keil/ARM_CM4F # Source/portable/MemMang/ heap_1.c ~ heap_5.c - 把通用实现与对应 port 目录加进工程。port 目录必须与目标内核和编译器同时匹配:Cortex-M4 配 GCC 就选
GCC/ARM_CM4F,M0 选GCC/ARM_CM0(没有 FPU 的 M0 不要用 CM4F),IAR 就换成IAR/ARM_CM4F。 - 挑一个堆实现加进来。从
Source/portable/MemMang里选一个 heap_N.c 加入编译,其余四个不要编——它们提供同名符号,同时编会重复定义。 - 写 FreeRTOSConfig.h。这个文件由应用提供,不属于内核,内核靠它拿到全部配置项。它一般放在工程的 include 路径里,内容是按需打开的一堆宏。
- 处理三个中断向量的名字。Cortex-M 端口使用自己的 SVC、PendSV、SysTick 处理函数,启动文件里默认的
SVC_Handler、PendSV_Handler、SysTick_Handler会和内核里的vPortSVCHandler、xPortPendSVHandler、xPortSysTickHandler冲突。/* 办法一:在 FreeRTOSConfig.h 里做宏别名,不动启动文件 */ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler /* 办法二:把启动文件里的三个向量名改成 port 层的名字 */ - 提供钩子函数与堆。开了对应开关时至少要有
vApplicationStackOverflowHook、vApplicationMallocFailedHook,以及一份可用的堆:heap_1 到 heap_5 之一,或者自己实现pvPortMalloc与vPortFree。 - 启动调度器。main 里创建完任务与内核对象后调用
vTaskStartScheduler(),正常情况下它不会返回。int main(void) { board_init(); app_create_tasks(); /* xTaskCreate / xQueueCreate 等 */ vTaskStartScheduler(); /* 正常不返回 */ for (;;) { } /* 能走到这里,多半是堆不够,调度器没起来 */ }
目标板与工具链要求。Cortex-M0、M0+、M3、M4、M7、M33 等都有现成 port;带 TrustZone 的内核(如 M33)要选对应 port,非安全侧与安全侧用的不是同一份。工具链方面 GCC、IAR、Keil、Tasking 都有对应目录。中断优先级要按 Cortex-M 的约定配好:只有优先级数值大于等于 configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断,才允许调用 FromISR 系列 API。
常见报错:
| 现象 | 原因与处理 |
|---|---|
| SVC_Handler / PendSV_Handler 重复定义 | 启动文件与 port 层都定义了;用宏别名,或删掉启动文件里的实现 |
| undefined reference to vPortSVCHandler | port 目录没加进工程,或者选错了 port |
| 卡在 configASSERT 里,断言落在优先级相关代码上 | 有中断的抢占优先级数值小于 configMAX_SYSCALL_INTERRUPT_PRIORITY 却调用了 FromISR API;调整优先级或改走任务上下文 |
| xTaskCreate 返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY | configTOTAL_HEAP_SIZE 太小;加大,或改用静态创建接口 |
| 调度器起不来,直接掉回 main 的 for 循环 | 堆不足,空闲任务或定时器任务创建失败 |

