当前位置: 首页 > news >正文

STM32手动移植FreeRTOS

📦 准备工作

  1. 获取FreeRTOS源码:

    • 访问 FreeRTOS官网 或其 GitHub仓库 下载最新版内核源码。

    • 你也可以使用Git克隆(注意要包含子模块):git clone https://github.com/FreeRTOS/FreeRTOS.git --recurse-submodules

  2. 准备STM32基础工程:

    • 使用 STM32CubeMX 生成一个针对你芯片型号的裸机工程(例如一个简单的LED闪烁工程),配置好时钟树、调试接口(如SYS)和你需要的外设(如GPIO、USART等)。

    • 确保这个基础工程在你的开发板上能够编译并通过(例如,LED能闪烁)。

📁 文件组织与添加

在你的STM32工程目录下(通常与CoreDrivers等文件夹同级),创建一个用于存放FreeRTOS源码的文件夹,例如Middlewares/FreeRTOS。然后按照下表的指引将必要的文件复制到相应位置:

所需文件源路径 (基于FreeRTOS源码根目录)目标路径 (你的工程目录)作用描述
核心源文件(.c)FreeRTOS/Source/*.c (如 tasks.cqueue.clist.c等)Middlewares/FreeRTOS/SourceFreeRTOS内核的核心功能实现
核心头文件(.h)FreeRTOS/Source/include/*.hMiddlewares/FreeRTOS/Source/includeFreeRTOS内核的头文件,提供API和数据类型定义
移植层文件FreeRTOS/Source/portable/[Compiler]/[Architecture]/*Middlewares/FreeRTOS/Source/portable与编译器及CPU架构相关的移植代码(关键选择,见下文说明
内存管理实现FreeRTOS/Source/portable/MemMang/heap_x.c (选一个)Middlewares/FreeRTOS/Source/portable/MemMangFreeRTOS的动态内存管理方案(五选一,通常推荐heap_4.c
配置文件FreeRTOS/Demo/[Demo项目]/FreeRTOSConfig.h通常放在工程Inc目录或Middlewares/FreeRTOSFreeRTOS内核的配置文件(需根据你的芯片和需求修改

🔧 关键选择说明:

  • 移植层文件 ([Compiler]和[Architecture]):

    • [Compiler]: 根据你使用的开发环境选择。

      • Keil MDK: 选择 RVDS 目录。

      • IAR: 选择 IAR 目录。

      • GCC (如STM32CubeIDE, CLion): 选择 GCC 目录。

    • [Architecture]: 根据你STM32芯片的Cortex内核型号选择。

      • Cortex-M0ARM_CM0

      • Cortex-M3ARM_CM3

      • Cortex-M4 (无FPU): ARM_CM4F

      • Cortex-M7 (有FPU): ARM_CM7

      • *例如,STM32F103是Cortex-M3,STM32F407是Cortex-M4。*

  • 内存管理实现 (heap_x.c):
    FreeRTOS提供了5种内存管理方案,通常选择 heap_4.c支持内存分配与释放,并能有效减少碎片)。对于极其简单或从不释放内存的应用,也可考虑 heap_1.c

📝 操作步骤:

  1. 在你的工程目录下(例如Middlewares/FreeRTOS)创建相应的子文件夹:SourceSource/includeSource/portable

  2. 根据上表和你的芯片、编译器情况,将FreeRTOS源码包中对应的文件复制到刚刚创建的相应文件夹中。

  3. 从FreeRTOS源码包的Demo文件夹里,找一个与你芯片型号相近的Demo工程,将其中的FreeRTOSConfig.h文件复制到你的工程目录下(通常放在Inc目录下便于包含)。

⚙️ 工程配置与修改

1. 添加文件到IDE工程

  • 打开你的Keil MDK(或其他IDE)工程。

  • 在IDE中创建新的分组(Group),例如 "FreeRTOS_CORE", "FreeRTOS_PORTABLE"。

  • 将刚才复制到Middlewares/FreeRTOS/Source下的.c文件(如tasks.cqueue.c等)添加到 "FreeRTOS_CORE" 分组。

  • 将你选择的内存管理文件(如heap_4.c)和移植层文件(如port.c)添加到 "FreeRTOS_PORTABLE" 分组。

  • 不要添加其他未选择的内存管理文件和移植层文件。

2. 添加头文件路径

在IDE的工程设置("Options for Target" -> "C/C++" -> "Include Paths")中,添加以下头文件路径35:

  • ../Middlewares/FreeRTOS/Source/include

  • ../Middlewares/FreeRTOS/Source/portable/[Compiler]/[Architecture] (例如 ../Middlewares/FreeRTOS/Source/portable/RVDS/ARM_CM3)

  • 确保也包含了存放FreeRTOSConfig.h文件的路径(如../Inc)。

3. 修改FreeRTOSConfig.h

FreeRTOSConfig.h是FreeRTOS的核心配置文件,你需要根据你的芯片和项目需求进行修改。以下是一些最关键的配置项34:

配置宏说明与典型设置
configCPU_CLOCK_HZ设置为你STM32芯片的主时钟频率(Hz),例如STM32F103为72000000,STM32F407为168000000。可直接使用 SystemCoreClock
configTICK_RATE_HZ系统节拍频率。通常设置为1000Hz,表示1ms一个时钟节拍。
configTOTAL_HEAP_SIZEFreeRTOS动态内存堆的总大小。根据你计划创建的任务、队列等数量估算。如果不够,任务创建会失败。例如可先设置为(10 * 1024)(10KB),后续再调整。
configMAX_PRIORITIES系统支持的最大任务优先级数。设置一个够用的值即可,如5-8,不是越大越好。
configKERNEL_INTERRUPT_PRIORITY``configMAX_SYSCALL_INTERRUPT_PRIORITY中断优先级配置非常重要!需要根据你芯片的NVIC优先级位数(如STM32F1/F4是4位,即0-15)和你的应用来设置。设置错误可能导致系统不稳定或无法运行。务必仔细查阅FreeRTOS手册和芯片数据手册
configUSE_PREEMPTION设置为1启用抢占式调度器,这是最常用的模式。
configUSE_TIMERS``configTIMER_TASK_PRIORITY``configTIMER_QUEUE_LENGTH``configTIMER_TASK_STACK_DEPTH如果你要使用软件定时器,需要将这些配置使能并设置相关参数。

其他常用配置:你还可以根据需求使能或禁用互斥量(configUSE_MUTEXES)、递归互斥量(configUSE_RECURSIVE_MUTEXES)、事件组(configUSE_EVENT_GROUPS)、栈溢出检查(configCHECK_FOR_STACK_OVERFLOW)等功能。

4. 处理中断服务程序(ISR)

FreeRTOS需要接管SVCPendSVSysTick这三个中断246。

  • 打开你的工程中stm32fxxx_it.c文件(例如stm32f1xx_it.cstm32f4xx_it.c)。

  • 找到并注释掉或删除以下三个函数的具体实现:

    • SVC_Handler(void)

    • PendSV_Handler(void)

    • SysTick_Handler(void)

  • 原因:这些中断的服务程序已经在你之前添加的移植层文件(如port.c)中实现了。如果不注释掉,会导致函数重复定义。

注意SysTick的特殊情况:如果你的HAL库仍然使用SysTick作为时基源(HAL_InitTick()),你可能需要修改SysTick_Handler而不是简单地删除它。一种常见的做法是28:

c

#include "FreeRTOS.h"
#include "task.h"void SysTick_Handler(void)
{HAL_IncTick(); // 维持HAL库的时基if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {xPortSysTickHandler(); // 调用FreeRTOS的SysTick Handler}
}

确保在FreeRTOSConfig.h中启用了INCLUDE_xTaskGetSchedulerState宏。

5. 修改HAL库的时基源(强烈推荐)

STM32的HAL库默认使用SysTick作为其时基源(用于HAL_Delay()HAL_GetTick()等)。而FreeRTOS也使用SysTick作为其任务调度的时钟节拍。虽然通过一些技巧可以让两者共享SysTick,但更推荐的做法是将HAL库的时基源切换到另一个硬件定时器(如TIM1, TIM6等),以避免潜在冲突9。

  • 你可以在STM32CubeMX中重新配置:在SYS选项下,将Timebase SourceSysTick改为其他的硬件定时器(如TIM1)。

  • 或者直接修改代码:在main.cHAL_Init()调用之后,重新初始化一个定时器作为HAL库的时基源。

🧪 编写测试代码

完成以上步骤后,就可以编写简单的FreeRTOS任务来测试移植是否成功了。

  1. 包含头文件:在main.c中包含FreeRTOS头文件。

    #include "FreeRTOS.h"
    #include "task.h"
    #include "queue.h" // 如果需要使用队列等功能
  2. 创建任务函数:定义至少一个简单的任务函数。

    void vTaskLED(void *pvParameters) {for (;;) {HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 假设LED连接在PC13vTaskDelay(500); // 延迟500个时钟节拍,即500ms (假设configTICK_RATE_HZ=1000)}
    }
  3. 创建任务并启动调度器:在main()函数的初始化代码之后(while (1)之前)创建任务并启动FreeRTOS调度器。

    int main(void) {HAL_Init();SystemClock_Config();// ... 其他外设初始化代码// 创建任务xTaskCreate(vTaskLED, "LED_Task", 128, NULL, 2, NULL);// 启动FreeRTOS调度器,永远不会返回vTaskStartScheduler();for (;;) {} // 调度器启动后,不会执行到这里
    }

🔬 编译、下载与调试

  1. 编译工程:解决所有编译错误。常见的错误包括头文件路径不正确、函数未定义(可能是移植层文件没添加或路径错误)、重复定义(中断服务函数没注释掉)等。

  2. 下载到开发板并运行。

  3. 观察现象:如果一切正常,LED应该会以你设置的周期闪烁。

  4. 使用调试器:如果程序运行不正常,使用调试器进行单步调试,检查系统是否能成功创建任务、是否成功启动调度器、是否进入正确的硬件中断等。

⚠️ 常见问题排查

  • 编译错误 undefined reference to ...: 检查FreeRTOS的.c文件是否都已添加到工程组中,头文件路径是否设置正确。

  • 编译错误 redefinition of ...: 检查stm32fxxx_it.c中的SVC、PendSV、SysTick中断处理函数是否已注释掉。

  • 程序在启动调度器后卡死或进入HardFault:

    • 检查FreeRTOSConfig.h中的configCPU_CLOCK_HZ是否设置正确。

    • 检查FreeRTOSConfig.h中的中断优先级配置(configKERNEL_INTERRUPT_PRIORITYconfigMAX_SYSCALL_INTERRUPT_PRIORITY)是否正确。这是非常常见的错误来源

    • 检查堆大小configTOTAL_HEAP_SIZE是否足够创建初始任务。

    • 使用调试器检查是否成功进入SVC_Handler(用于启动第一个任务)。

  • SysTick中断冲突: 确保HAL库的时基源已切换至非SysTick的定时器,或者按照前述方法修改了SysTick_Handler函数。

http://www.dtcms.com/a/358062.html

相关文章:

  • 算法(②排序算法)
  • 吴恩达机器学习作业八:SVM支持向量机
  • react代码分割
  • 对于牛客网—语言学习篇—编程初学者入门训练—复合类型:二维数组较简单题目的解析
  • Redis(自写)
  • LeetCode第438题 - 找到字符串中所有字母异位词
  • C++ 面试高频考点 力扣 34. 在排序数组中查找元素的第一个和最后一个位置 二分查找左右端点 题解 每日一题
  • 为什么vue3会移除过滤器filter
  • JUC并发编程10 - 内存(02) - volatile
  • 生成对抗网络(GAN):深度学习领域的革命性突破
  • DriveDreamer4D
  • YOLOv11 训练参数全解析:一文掌握 epochs、batch、optimizer 调优技巧
  • MySQL-事务(下)-MySQL事务隔离级别与MVCC
  • 检索优化-混合检索
  • 捡捡java——2、基础07
  • 使用git bash ,出现Can‘t get terminal settings: The handle is invalid. 的解决方法与思路
  • 数字人分身系统源码搭建与定制开发:核心技术解析与实践路径
  • 基于 Spring Boot3 的ZKmall开源商城分层架构实践:打造高效可扩展的 Java 电商系统
  • Kubernetes Dashboard 和 Rancher 功能对比以及详细安装步骤
  • MySQL数据库迁移到KingbaseES完整指南
  • 计算机视觉与深度学习 | ORB-SLAM3算法原理与Matlab复现指南
  • WebStorm无法识别@下的文件,但是可以正常使用
  • Redis 缓存热身(Cache Warm-up):原理、方案与实践
  • Linux命令学习:make,make install,modprobe,lsmod
  • CNB刷新EO缓存和插件化
  • Spring Cache实现简化缓存功能开发
  • 2025年职业发展关键证书分析:提升专业能力的路径选择
  • 漏洞挖掘-信息收集教程
  • CVPR深度学习论文创新合集拆解:模型训练速度算提升
  • 【CUDA进阶】MMA分析Bank Conflict与Swizzle(下)