在嵌入式开发中,实时操作系统(RTOS)能有效简化多任务管理、提升系统响应速度,而 FreeRTOS 作为轻量、开源的 RTOS,被广泛应用于各类 MCU 平台。本文将以通用步骤为例,详细讲解 FreeRTOS 的移植过程,适合有一定嵌入式基础的开发者参考。

一、移植前的准备工作

移植 FreeRTOS 的核心是让其适配目标 MCU 的架构和硬件环境,因此前期准备需明确 “目标平台” 和 “工具链” 两大要素。

1. 硬件环境

  • 目标 MCU:需明确芯片架构(如 ARM Cortex-M3/M4、RISC-V、STM8 等),以 Cortex-M4 为例(本次使用的是GD32F407);
  • 开发板:包含目标 MCU 的最小系统板(需有电源、复位、调试接口);
  • 调试工具:J-Link、ST-Link 等(用于下载程序和调试)。

2. 软件环境

  • 集成开发环境(IDE):如Keil MDK;
  • 编译器:需与 IDE 匹配( Keil 自带的 ARMCC);
  • FreeRTOS 源码:从官网(https://www.freertos.org/)下载最新版本(建议选择 LTS 长期支持版);
  • 目标 MCU 的底层驱动:如 STM32 的 HAL 库或标准外设库(用于初始化时钟、GPIO 等硬件)。

二、FreeRTOS 源码结构解析

移植前需理清 FreeRTOS 的源码组成,核心文件可分为 “通用内核” 和 “平台相关” 两部分:

FreeRTOS/
├─ include/           // 通用头文件(内核API、数据结构等,所有平台共用)
├─ src/               // 通用内核源码(任务调度、队列、信号量等,所有平台共用)
└─ portable/          // 平台相关代码(需根据目标MCU修改)
   ├─ [Compiler]/     // 编译器相关(如ARMCC、GCC)
   └─ [Architecture]/ // 架构相关(如ARM_CM4F对应Cortex-M4带FPU)

关键:移植只需修改portable目录下的平台相关文件,通用内核代码无需改动。

三、移植核心步骤

步骤 1:下载好源码

然后咱们只需要选择这个FreeRTOS 这个里边的代码

步骤 2:添加 FreeRTOS 源码到工程

  1. 复制 FreeRTOS 源码到工程目录,建议新建FreeRTOS文件夹,包含includesrcportable
  2. 在 IDE 中添加文件:
    • 通用内核:添加src目录下所有.c文件(port.c除外,它属于平台相关);
    • 平台相关:根据 MCU 架构和编译器,从portable中选择对应文件(如 Cortex-M4 + Keil,需添加portable/ARMCC/ARM_CM4F/port.c);
    • 内存管理:从portable/MemMang中选择一个内存管理文件(新手推荐heap_4.c,支持动态内存分配且无碎片)。

把这个文件复制到工程文档下边然后在里边创建下面这三个文件夹

然后打开这个文件后将红框里边的内容放到新建立的source中

打开portable后删除所有的就留下下边的这几个,然后复制到咱们创建的portable中

同样的将文件夹下边的include里边的复制到新建的include文件夹下边

然后去demo里边找到我们使用系列的Cortex-M4的FreeRTOSConfig.h文件把他放到我们新建的include文件夹下边

步骤 3:配置头文件路径,添加到编译器中

在 IDE 中设置头文件搜索路径,确保编译器能找到:

  • FreeRTOS/include
  • 平台相关头文件路径(如portable/ARMCC/ARM_CM4F
  • 目标 MCU 的底层驱动头文件
  • 把这些内容添加进来

步骤 4:修改 FreeRTOSConfig.h 配置文件

这是移植的核心配置文件,需根据目标平台定制,主要配置项如下:

// 1. 系统时钟配置
#define configCPU_CLOCK_HZ              (SystemCoreClock)  // 系统时钟频率(从底层驱动获取)
#define configTICK_RATE_HZ              ((TickType_t)1000) // 时钟节拍频率(1ms一次滴答)

// 2. 任务配置
#define configMAX_PRIORITIES            (5)                // 最大任务优先级
#define configMINIMAL_STACK_SIZE        ((unsigned short)128) // 最小任务栈大小(字)

// 3. 内核功能开关
#define configUSE_PREEMPTION            1                  // 启用抢占式调度
#define configUSE_TICKLESS_IDLE         0                  // 关闭低功耗模式(初期调试用)
#define configUSE_QUEUE_SETS            0                  // 按需启用队列集

// 4. 中断配置(Cortex-M系列关键)
#define configPRIO_BITS                 4                  // 优先级位数(如STM32为4位)
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15         // 最低中断优先级
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

// 5. 钩子函数(调试用)
#define configUSE_IDLE_HOOK             0
#define configUSE_TICK_HOOK             0

// 6. 类型重定义(适配编译器)
#define portTickType                    TickType_t
#define portBASE_TYPE                   long

注意:中断优先级配置需与 MCU 的 NVIC 设置一致,FreeRTOS 的内核中断(如 PendSV、SVC)需设置为最低优先级。

步骤 5:实现底层接口(关键)

FreeRTOS 依赖两个核心硬件接口,需根据 MCU 架构实现:

  1. 时钟节拍(Tick)中断用于触发任务调度,通常通过 SysTick 定时器实现。在 Cortex-M 中,需在stm32f4xx_it.c(中断服务函数文件)中添加:

  2. 任务上下文切换由 PendSV(用于任务切换)和 SVC(用于任务创建)中断实现,Cortex-M 的port.c已封装好汇编代码,无需修改,但需确保中断向量表中正确映射这两个中断。

四、移植测试:创建第一个任务

移植完成后,编写测试代码验证是否成功:

#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx_hal.h"

// 任务1:LED1每500ms闪烁一次
void vTask1(void *pvParameters) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // 假设LED接PB0
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

// 任务2:LED2每1000ms闪烁一次
void vTask2(void *pvParameters) {
    while (1) {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1); // 假设LED接PB1
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

int main(void) {
    // 初始化硬件(时钟、GPIO等)
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    // 创建任务
    xTaskCreate(vTask1, "Task1", 128, NULL, 1, NULL);
    xTaskCreate(vTask2, "Task2", 128, NULL, 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 若调度器启动失败,程序会走到这里
    while (1) {}
}

五、常见问题与排查

  1. 程序无法运行,进入 HardFault

    • 检查栈大小:configMINIMAL_STACK_SIZE是否过小,任务栈不足会导致栈溢出;
    • 中断优先级:确保 FreeRTOS 内核中断(PendSV、SVC)优先级最低。
  2. 任务不切换

    • 检查 SysTick 配置:configCPU_CLOCK_HZ是否与实际系统时钟一致;
    • 确认vTaskStartScheduler()已调用,且无内存分配失败(heap_4.c需足够堆空间)。
  3. 调试时无法单步任务

    • 检查 IDE 的调试配置,确保 “Use microLIB” 已勾选,避免标准库与 FreeRTOS 冲突。

六、总结

FreeRTOS 移植的核心是 “适配硬件架构” 和 “正确配置内核参数”,关键步骤可概括为:

  1. 搭建工程验证硬件;
  2. 添加源码并配置路径;
  3. 定制FreeRTOSConfig.h
  4. 实现时钟节拍和上下文切换接口;
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐