【STM32】RTT-Studio中HAL库开发教程十二:FreeRTOS移植

【STM32】RTT-Studio中HAL库开发教程十二:FreeRTOS移植 文章目录一、移植前准备1.基础准备工程2.下载 FreeRTOS 源码二、添加 FreeRTOS 源码到工程1.创建文件夹并复制源码2.添加配置文件三、在 RTT 中配置工程1.添加FreeRTOS文件夹2.添加头文件路径四、添加 FreeRTOSConfig.h 配置文件1.获取配置文件2.关键配置项说明五、修改中断相关文件1.注释掉重复的中断函数2.修改 SysTick_Handler六、编写测试代码验证移植1.创建测试任务七、常见问题及解决方法八、总结一、移植前准备1.基础准备工程首先需要一个可以正常运行的STM32基础工程打印工程可以是标准库版本或 HAL 库版本。推荐使用 HAL 库版本因为 STM32CubeMX 对 FreeRTOS 的支持更好。可以使Keil生成的工程也可以是其他软件生成的工程本实验采用的是RTT-Thread Studio软件生成的工程可以实现基本的数据打印功能。2.下载 FreeRTOS 源码从 FreeRTOS官网下载源码包推荐使用FreeRTOS 202406.05 LTS版本或更高版本这个版本稳定性最好与 CubeMX 兼容性佳 本实验采用的是FreeRTOS 202404.00 LTSLatest版本点击下载即可。解压后源码目录结构如下我们只需要用到FreeRTOS -- FreeRTOS-Kernel里面的文件即可其他的文件属于扩展包有需要可以自行移植。二、添加 FreeRTOS 源码到工程1.创建文件夹并复制源码在基础工程目录下创建FreeRTOS文件夹或直接命名为 FreeRTOS创建三个文件夹inc、port、src然后将以下内容复制进去 内核源码将 FreeRTOS-Kernel/ 目录下的所有 .c 文件tasks.c、queue.c、list.c、timers.c 等复制过来到src文件夹里面头文件 将FreeRTOS-Kernel/目录下的include里面的文件全部移植到inc文件夹里面移植文件将 Source/portable/ 文件夹复制但只需保留以下三个子目录1编译器如果采用V5版本需要选择RVDS/ —— Keil 编译器需要的移植文件ARM_CM4F 是 STM32F4 所需的如果采用GCC编译器版本需要选择GCC/2内存管理算法MemMang/文件里面包含heap_1~heap_5一般采用heap_43如果是使用Keil的话需要加入Keil/文件夹“MemMang”中是FreeRTOS提供的5个内存分配方案heap_1主要用于小型专一嵌入式系统。内核在任何实时任务执行之前先分配内存一次分配永久使用并不再改变,可靠性较高。heap_2采用最佳适配算法适用于需要频繁创建和删除需要分配固定栈内存的任务。heap_3过暂时挂起FreeRTOS的调度来实现malloc()和free()的线程安全。heap_4采用首次适应算法来分配内存。heap4将相邻未分配的内存结合成为整个大内存来减少碎片内存。heap_5以对任意位置的空间进行分配在使用之前需要通过vPortDefineHeapRegions()函数进行初始化之后才可以使用pvPortMalloc()进行内存分配。2.添加配置文件在新建的FreeRTOS文件夹中将位于FreeRTOS-Kernel\examples\template_configuration里面的配置文件FreeRTOSConfig.h文件复制到新建的文件夹中及完成FreeRTOS的整个源码的移植过程。三、在 RTT 中配置工程1.添加FreeRTOS文件夹在RTT中导入新建的工程即可在工程可以看到该文件夹。文件夹里面的内容如下文件名称功能介绍tasks.c任务管理queue.c队列管理list.c链表管理timers.c软件定时器event_groups.c事件组可选croutine.c协程可选一般不使用2.添加头文件路径点击魔法棒按钮 → C/C → Include Paths添加以下路径 .\FreeRTOS\FreeRTOS.\FreeRTOS\FreeRTOS\inc.\FreeRTOS\FreeRTOS\port\GCC\ARM_CM4F四、添加 FreeRTOSConfig.h 配置文件1.获取配置文件FreeRTOSConfig.h 是 FreeRTOS 的核心配置文件用于系统裁剪和功能配置 。获取方式方法一从官方 Demo 中复制路径 FreeRTOS/Demo/CORTEX_M4F_STM32F407ZG-SK/方法二自行编写参考下文配置2.关键配置项说明以下是一个适用于 STM32F4 的典型配置 #ifndefFREERTOS_CONFIG_H#defineFREERTOS_CONFIG_H#includestm32f4xx.h// 根据实际 MCU 型号选择// 调度器配置#defineconfigUSE_PREEMPTION1// 1:抢占式调度#defineconfigUSE_TIME_SLICING1// 1:时间片轮转#defineconfigUSE_PORT_OPTIMISED_TASK_SELECTION1// 1:优化任务选择// 系统时钟配置#defineconfigCPU_CLOCK_HZ(SystemCoreClock)// CPU 主频#defineconfigTICK_RATE_HZ((TickType_t)1000)// 系统节拍 1ms// 任务相关配置#defineconfigMAX_PRIORITIES(32)// 最大优先级数#defineconfigMINIMAL_STACK_SIZE((unsignedshort)128)// 空闲任务栈大小#defineconfigMAX_TASK_NAME_LEN(16)// 任务名最大长度// 内存配置#defineconfigTOTAL_HEAP_SIZE((size_t)(36*1024))// 堆大小#defineconfigSUPPORT_DYNAMIC_ALLOCATION1// 支持动态内存申请#defineconfigSUPPORT_STATIC_ALLOCATION0// 静态内存申请// 钩子函数配置暂不启用#defineconfigUSE_IDLE_HOOK0#defineconfigUSE_TICK_HOOK0#defineconfigUSE_MALLOC_FAILED_HOOK0#defineconfigCHECK_FOR_STACK_OVERFLOW0// 可选功能#defineINCLUDE_vTaskDelay1#defineINCLUDE_vTaskDelayUntil1#defineINCLUDE_vTaskDelete1#defineINCLUDE_vTaskSuspend1#endif/* FREERTOS_CONFIG_H */完整的中文配置说明如下/* FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation AND MODIFIED BY the FreeRTOS exception. *************************************************************************** ! NOTE: The modification to the GPL is included to allow you to ! ! distribute a combined work that includes FreeRTOS without being ! ! obliged to provide the source code for proprietary components ! ! outside of the FreeRTOS kernel. ! *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html *************************************************************************** * * * FreeRTOS provides completely free yet professionally developed, * * robust, strictly quality controlled, supported, and cross * * platform software that is more than just the market leader, it * * is the industrys de facto standard. * * * * Help yourself get started quickly while simultaneously helping * * to support the FreeRTOS project by purchasing a FreeRTOS * * tutorial book, reference manual, or both: * * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading the FAQ page My application does not run, what could be wrong?. Have you defined configASSERT()? http://www.FreeRTOS.org/support - In return for receiving this top quality embedded software for free we request you assist our global community by participating in the support forum. http://www.FreeRTOS.org/training - Investing in training allows your team to be as productive as possible as early as possible. Now you can receive FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers Ltd, and the worlds leading authority on the worlds leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOSTrace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. Come and try FreeRTOSTCP, our new open source TCP/IP stack for FreeRTOS. http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and mission critical applications that require provable dependability. */#ifndefFREERTOS_CONFIG_H#defineFREERTOS_CONFIG_H#includestm32f4xx.h//针对不同的编译器调用不同的stdint.h文件#ifdefined(__ICCARM__)||defined(__CC_ARM)||defined(__GNUC__)#includestdint.hexternuint32_tSystemCoreClock;#endif/* *INDENT-OFF 断言* */#defineconfigASSERT(x)\if((x)0)\{\taskDISABLE_INTERRUPTS();\for(;;)\;\}/* *INDENT-ON* *//************************************************************************ * FreeRTOS基础配置配置选项 *********************************************************************//* 置1RTOS使用抢占式调度器置0RTOS使用协作式调度器时间片 * * 注在多任务管理机制上操作系统可以分为抢占式和协作式两种。 * 协作式操作系统是任务主动释放CPU后切换到下一个任务。 * 任务切换的时机完全取决于正在运行的任务。 */#defineconfigUSE_PREEMPTION1//1使能时间片调度(默认式使能的)#defineconfigUSE_TIME_SLICING1/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务 * 通用方法和特定于硬件的方法以下简称“特殊方法”。 * * 通用方法 * 1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者硬件不支持这种特殊方法。 * 2.可以用于所有FreeRTOS支持的硬件 * 3.完全用C实现效率略低于特殊方法。 * 4.不强制要求限制最大可用优先级数目 * 特殊方法 * 1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。 * 2.依赖一个或多个特定架构的汇编指令一般是类似计算前导零[CLZ]指令。 * 3.比通用方法更高效 * 4.一般强制限定最大可用优先级数目为32 * 一般是硬件计算前导零指令如果所使用的MCU没有这些硬件指令的话此宏应该设置为0 */#defineconfigUSE_PORT_OPTIMISED_TASK_SELECTION1/* 置1使能低功耗tickless模式置0保持系统节拍tick中断一直运行 * 假设开启低功耗的话可能会导致下载出现问题因为程序在睡眠中,可用以下办法解决 * * 下载方法 * 1.将开发版正常连接好 * 2.按住复位按键点击下载瞬间松开复位按键 * * 1.通过跳线帽将 BOOT 0 接高电平(3.3V) * 2.重新上电下载 * * 1.使用FlyMcu擦除一下芯片然后进行下载 * STMISP - 清除芯片(z) */#defineconfigUSE_TICKLESS_IDLE0/* * 写入实际的CPU内核时钟频率也就是CPU指令执行频率通常称为Fclk * Fclk为供给CPU内核的时钟信号我们所说的cpu主频为 XX MHz * 就是指的这个时钟信号相应的1/Fclk即为cpu时钟周期 */#defineconfigCPU_CLOCK_HZ(SystemCoreClock)//RTOS系统节拍中断的频率。即一秒中断的次数每次中断RTOS都会进行任务调度#defineconfigTICK_RATE_HZ((TickType_t)1000)//可使用的最大优先级#defineconfigMAX_PRIORITIES(32)//空闲任务使用的堆栈大小#defineconfigMINIMAL_STACK_SIZE((unsignedshort)128)//任务名字字符串长度#defineconfigMAX_TASK_NAME_LEN(16)//系统节拍计数器变量数据类型1表示为16位无符号整形0表示为32位无符号整形#defineconfigUSE_16_BIT_TICKS0//空闲任务放弃CPU使用权给其他同优先级的用户任务#defineconfigIDLE_SHOULD_YIELD1//启用队列#defineconfigUSE_QUEUE_SETS0//开启任务通知功能默认开启#defineconfigUSE_TASK_NOTIFICATIONS1//使用互斥信号量#defineconfigUSE_MUTEXES0//使用递归互斥信号量#defineconfigUSE_RECURSIVE_MUTEXES0//为1时使用计数信号量#defineconfigUSE_COUNTING_SEMAPHORES0/* 设置可以注册的信号量和消息队列个数 */#defineconfigQUEUE_REGISTRY_SIZE10#defineconfigUSE_APPLICATION_TASK_TAG0/***************************************************************** FreeRTOS与内存申请有关配置选项 *****************************************************************///支持动态内存申请#defineconfigSUPPORT_DYNAMIC_ALLOCATION1//支持静态内存#defineconfigSUPPORT_STATIC_ALLOCATION0//系统所有总的堆大小#defineconfigTOTAL_HEAP_SIZE((size_t)(36*1024))/*************************************************************** FreeRTOS与钩子函数有关的配置选项 **************************************************************//* 置1使用空闲钩子Idle Hook类似于回调函数置0忽略空闲钩子 * * 空闲任务钩子是一个函数这个函数由用户来实现 * FreeRTOS规定了函数的名字和参数void vApplicationIdleHook(void ) * 这个函数在每个空闲任务周期都会被调用 * 对于已经删除的RTOS任务空闲任务可以释放分配给它们的堆栈内存。 * 因此必须保证空闲任务可以被CPU执行 * 使用空闲钩子函数设置CPU进入省电模式是很常见的 * 不可以调用会引起空闲任务阻塞的API函数 */#defineconfigUSE_IDLE_HOOK0/* 置1使用时间片钩子Tick Hook置0忽略时间片钩子 * * * 时间片钩子是一个函数这个函数由用户来实现 * FreeRTOS规定了函数的名字和参数void vApplicationTickHook(void ) * 时间片中断可以周期性的调用 * 函数必须非常短小不能大量使用堆栈 * 不能调用以”FromISR 或 FROM_ISR”结尾的API函数 *//*xTaskIncrementTick函数是在xPortSysTickHandler中断函数中被调用的。因此vApplicationTickHook()函数执行的时间必须很短才行*/#defineconfigUSE_TICK_HOOK0//使用内存申请失败钩子函数#defineconfigUSE_MALLOC_FAILED_HOOK0/* * 大于0时启用堆栈溢出检测功能如果使用此功能 * 用户必须提供一个栈溢出钩子函数如果使用的话 * 此值可以为1或者2因为有两种栈溢出检测方法 */#defineconfigCHECK_FOR_STACK_OVERFLOW0/******************************************************************** FreeRTOS与运行时间和任务状态收集有关的配置选项 **********************************************************************///启用运行时间统计功能#defineconfigGENERATE_RUN_TIME_STATS0//启用可视化跟踪调试#defineconfigUSE_TRACE_FACILITY1/* 与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数 * prvWriteNameToBuffer() * vTaskList(), * vTaskGetRunTimeStats() */#defineconfigUSE_STATS_FORMATTING_FUNCTIONS1/******************************************************************** FreeRTOS与协程有关的配置选项 *********************************************************************///启用协程启用协程以后必须添加文件croutine.c#defineconfigUSE_CO_ROUTINES0//协程的有效优先级数目#defineconfigMAX_CO_ROUTINE_PRIORITIES(2)/*********************************************************************** FreeRTOS与软件定时器有关的配置选项 **********************************************************************///启用软件定时器#defineconfigUSE_TIMERS0//软件定时器优先级#defineconfigTIMER_TASK_PRIORITY(configMAX_PRIORITIES-1)//软件定时器队列长度#defineconfigTIMER_QUEUE_LENGTH10//软件定时器任务堆栈大小#defineconfigTIMER_TASK_STACK_DEPTH(configMINIMAL_STACK_SIZE*2)/************************************************************ FreeRTOS可选函数配置选项 ************************************************************/#defineINCLUDE_xTaskGetSchedulerState1#defineINCLUDE_vTaskPrioritySet1#defineINCLUDE_uxTaskPriorityGet1#defineINCLUDE_vTaskDelete1#defineINCLUDE_vTaskCleanUpResources1#defineINCLUDE_vTaskSuspend1#defineINCLUDE_vTaskDelayUntil1#defineINCLUDE_vTaskDelay1#defineINCLUDE_eTaskGetState1#defineINCLUDE_xTimerPendFunctionCall0//#define INCLUDE_xTaskGetCurrentTaskHandle 1//#define INCLUDE_uxTaskGetStackHighWaterMark 0//#define INCLUDE_xTaskGetIdleTaskHandle 0/****************************************************************** FreeRTOS与中断有关的配置选项 ******************************************************************/#ifdef__NVIC_PRIO_BITS#defineconfigPRIO_BITS__NVIC_PRIO_BITS#else#defineconfigPRIO_BITS4#endif//中断最低优先级#defineconfigLIBRARY_LOWEST_INTERRUPT_PRIORITY15//系统可管理的最高中断优先级#defineconfigLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY5#defineconfigKERNEL_INTERRUPT_PRIORITY(configLIBRARY_LOWEST_INTERRUPT_PRIORITY(8-configPRIO_BITS))/* 240 */#defineconfigMAX_SYSCALL_INTERRUPT_PRIORITY(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(8-configPRIO_BITS))/**************************************************************** FreeRTOS与中断服务函数有关的配置选项 ****************************************************************/#definexPortPendSVHandlerPendSV_Handler#definevPortSVCHandlerSVC_Handler/* 以下为使用Percepio Tracealyzer需要的东西不需要时将 configUSE_TRACE_FACILITY 定义为 0 */#if(configUSE_TRACE_FACILITY1)#defineINCLUDE_xTaskGetCurrentTaskHandle1// 启用一个可选函数该函数被 Trace源码使用默认该值为0 表示不用#endif#endif/* FREERTOS_CONFIG_H */五、修改中断相关文件1.注释掉重复的中断函数FreeRTOS 已经实现了 SVC_Handler、PendSV_Handler 和 SysTick_Handler因此需要将 stm32f4xx_it.c 中这三个中断函数注释掉 // 注释掉或通过条件编译跳过这三个函数// void SVC_Handler(void) { … }// void PendSV_Handler(void) { … }// void SysTick_Handler(void) { … }2.修改 SysTick_Handler如果使用 HAL 库SysTick 中断需要同时服务于 HAL 和 FreeRTOS。修改后的 SysTick_Handler 如下 #includeFreeRTOS.h#includetask.hexternvoidxPortSysTickHandler(void);voidSysTick_Handler(void){// HAL_IncTick();#if(INCLUDE_xTaskGetSchedulerState1)if(xTaskGetSchedulerState()!taskSCHEDULER_NOT_STARTED){#endifxPortSysTickHandler();#if(INCLUDE_xTaskGetSchedulerState1)}#endif}六、编写测试代码验证移植1.创建测试任务创建一个freertos_demo.c文件编写简单的 LED 闪烁任务 也可以先常见一个任务这个任务主要是用来初始化所有的固件以及创建所有的信号量以及各种任务再使用完成之后将任务进行销毁。#includestdio.h#includeboard.h#includeFreeRTOS.h#includetask.h/* 任务函数结构体 */typedefstruct__task_t{TaskFunction_t pxTaskCode;constchar*constpcName;constconfigSTACK_DEPTH_TYPE usStackDepth;void*constpvParameters;UBaseType_t uxPriority;TaskHandle_t*constpxCreatedTask;}task_t;/* 任务句柄 */TaskHandle_t app_task_init_handleNULL;TaskHandle_t app_task_tes_handleNULL;TaskHandle_t app_task_led_handleNULL;/** * Description : Test */voidtesTask(void*pvParameters){while(1){printf(Hello FreeRTOS\r\n);vTaskDelay(1000);}}/** * Description : LED */voidLedTask(void*pvParameters){while(1){printf(Task Runing...\r\n);vTaskDelay(100);}}/* 任务列表 */staticconsttask_ttask_tbl[]{{tesTask,tesTask,256,NULL,5,app_task_tes_handle},{LedTask,LedTask,256,NULL,5,app_task_led_handle},};/** * brief 集中初始化任务 * param pvParameters:创建任务时传递的参数 * retval 无 */staticvoidapp_task_init(void*pvParameters){taskENTER_CRITICAL();//进入临界区inti0;while(task_tbl[i].pxTaskCode){xTaskCreate(task_tbl[i].pxTaskCode,/* 任务入口函数 */task_tbl[i].pcName,/* 任务名字 */task_tbl[i].usStackDepth,/* 任务栈大小 */task_tbl[i].pvParameters,/* 任务入口函数参数 */task_tbl[i].uxPriority,/* 任务的优先级 */task_tbl[i].pxCreatedTask);/* 任务控制块指针 */i;}taskEXIT_CRITICAL();// 退出临界区vTaskDelete(NULL);// 删除任务自身printf([app_task_init] nerver run here\r\n);}intmain(void){/* 创建 app_task_init任务 */xTaskCreate((TaskFunction_t)app_task_init,/* 任务入口函数 */(constchar*)app_task_init,/* 任务名字 */(uint16_t)512,/* 任务栈大小 */(void*)NULL,/* 任务入口函数参数 */(UBaseType_t)5,/* 任务的优先级 */(TaskHandle_t*)app_task_init_handle);/* 任务控制块指针 *//* 开启任务调度 */vTaskStartScheduler();while(1);return0;}七、常见问题及解决方法错误信息原因解决方法Error: L6200E: Symbol xxx multiply defined中断函数重复定义注释掉 stm32f4xx_it.c 中的 SVC_Handler、PendSV_Handler、SysTick_HandlerError: L6218E: Undefined symbol vApplicationIdleHook钩子函数未定义但已启用在 FreeRTOSConfig.h 中将 configUSE_IDLE_HOOK 等设为 0error: A1586E: Bad operand types__NVIC_PRIO_BITS 宏问题将 4U 改为 4Error: L6218E: Undefined symbol SystemCoreClock系统时钟变量未定义在 FreeRTOSConfig.h 中添加 extern uint32_t SystemCoreClock;任务不运行 / HardFault任务栈太小增大 configMINIMAL_STACK_SIZE 或任务栈大小八、总结移植 FreeRTOS 到 STM32 的流程可以总结为以下几步下载链接准备基础工程 —— 确保有一个可运行的 STM32F4 工程获取源码 —— 从官网下载 FreeRTOS 源码包添加源文件 —— 将内核源码和移植文件添加到工程配置头文件路径 —— 让编译器能找到所有头文件添加配置文件 —— FreeRTOSConfig.h 用于系统裁剪修改中断文件 —— 解决中断冲突问题适配底层驱动 —— 修改 SYSTEM 文件夹如使用正点原子模板编写测试代码 —— 创建简单任务验证移植完成以上步骤后一个可以运行的 FreeRTOS 工程就移植好了。可以在此基础上继续学习任务创建、信号量、队列等 FreeRTOS 的核心功能。