资讯详情

资讯详情

GD32移植FreeRTOS实战:从裸机到RTOS的完整指南

1. 为什么要把FreeRTOS搬到GD32上1.1 从裸机到RTOS的真实痛点很多做MCU开发的朋友一开始都是在GD32或者STM32这类Cortex-M内核的单片机上跑裸机程序。裸机开发的好处是简单直接一个while(1)大循环加上几个中断小项目跑得挺欢。但项目一旦复杂起来比如要同时处理串口协议解析、按键扫描、LCD刷新、传感器采集、数据存储这几件事裸机就开始捉襟见肘了。你不得不用各种状态机和延时来拼凑代码越写越乱一个地方改动了另一个地方就出问题。我印象特别深的一次做一个带LCD显示的工业控制器主循环里要刷屏、要读编码器、要跑Modbus从站、还要做PID运算。裸机方案下刷屏的时候编码器脉冲就丢了PID周期也不稳定。后来上了FreeRTOS把每个任务拆开给不同的优先级问题一下就清晰了。这也是为什么越来越多的GD32项目开始引入FreeRTOS——它帮你把并发的复杂度从应用层转移到了内核层你只需要关心任务之间的逻辑关系。GD32作为国产Cortex-M3/M4的主力芯片和STM32在寄存器层面高度相似但又有自己的外设差异。把FreeRTOS移植到GD32上本质上就是让FreeRTOS的调度器、任务切换、系统节拍这些核心机制能够在GD32的硬件上正确跑起来。听起来好像只是改几个宏定义但实际操作中从时钟配置到中断优先级从堆栈对齐到SysTick接管每一步都有坑。1.2 移植前你需要准备什么先说硬件和软件环境。硬件方面一块GD32F303或者GD32F103的开发板是最常见的起点这两款芯片在社区里资料最多踩坑的人也最多遇到问题好查。调试器用J-Link或者GD-Link都行J-Link的兼容性更好一些尤其是在Keil下面用SWD模式调试的时候。软件方面Keil MDK是大多数人的首选版本建议用Keil 5.36以上太老的版本对GD32的器件支持包兼容性不好。你需要安装GigaDevice的器件支持包这个在Keil的Pack Installer里可以直接下载或者去官网下载离线包手动安装。FreeRTOS的源码直接从官网或者GitHub拉最新稳定版就行我一般用FreeRTOSv202112.00这个版本稳定且资料多。注意不要用Keil自带的FreeRTOS中间件版本那个版本往往比较老而且和官方源码在目录结构上有差异后期排查问题的时候容易混淆。另外你需要一个能正常编译的GD32裸机工程模板。这个模板应该包含启动文件、系统时钟配置、GPIO驱动这些基础内容。如果你还没有建议先用GD32的官方固件库建立一个标准工程确保LED能闪、串口能打印然后再往上加FreeRTOS。这个顺序很重要不要一上来就把FreeRTOS塞进去出了问题你分不清是裸机工程本身有问题还是移植有问题。1.3 移植工作的整体思路移植FreeRTOS到GD32核心工作可以拆成三块第一块是文件结构的组织把FreeRTOS的源码文件正确地加入到Keil工程里第二块是配置文件的编写也就是FreeRTOSConfig.h这个文件决定了FreeRTOS在你这颗芯片上怎么跑第三块是硬件相关的接口适配主要是SysTick中断、PendSV中断和SVC中断这三个它们是FreeRTOS任务切换的硬件基础。这三块里面第一块是体力活第二块是脑力活第三块是技术活。很多人移植失败问题往往出在第二块和第三块。FreeRTOSConfig.h里的每一个宏定义都有它的作用配错了轻则功能异常重则直接HardFault。而三个中断的优先级配置如果和GD32的中断优先级分组不匹配任务切换就会出问题。我个人的习惯是先把FreeRTOS的源码文件按照功能分组放到工程目录里然后在Keil里建对应的Group这样结构清晰后期升级FreeRTOS版本的时候也方便替换。配置文件单独放在一个User目录下和GD32的固件库配置放在一起便于统一管理。2. FreeRTOS源码文件组织与Keil工程配置2.1 源码目录的合理划分FreeRTOS的源码包解压出来之后文件很多但真正需要加入到工程里的其实就那么几个。我的做法是在工程根目录下建一个FreeRTOS文件夹里面再分三个子目录Source、Portable和Config。Source目录放FreeRTOS的核心源码包括tasks.c、queue.c、list.c、timers.c、event_groups.c、stream_buffer.c、croutine.c这几个文件。其中tasks.c和queue.c是必须的timers.c如果你要用软件定时器就得加event_groups.c和stream_buffer.c看你的项目需求croutine.c是协程功能一般用不到可以不加。Portable目录放和编译器、芯片架构相关的文件。对于Keil MDK加上Cortex-M3/M4的组合你需要的是Portable/RVDS/ARM_CM3或者ARM_CM4F这个目录下的port.c和portmacro.h。注意ARM_CM4F是带浮点单元的版本如果你用的是GD32F303这类带FPU的芯片并且任务里要用浮点运算就选CM4F如果是GD32F103这类没有FPU的就选CM3。选错了编译能过但运行的时候浮点上下文保存会出问题。Config目录放FreeRTOSConfig.h这个文件不是源码包里现成的需要你自己写或者从Demo里改。我建议从FreeRTOS源码包里Demo/CORTEX_STM32F103_Keil这个目录下找一个接近的配置作为起点然后根据GD32的实际情况修改。内存管理方面FreeRTOS提供了heap_1到heap_5五种方案。heap_1最简单只能分配不能释放heap_2支持释放但不合并相邻空闲块heap_4支持释放和合并是最常用的heap_5支持多块不连续内存区域。对于GD32项目我一般直接用heap_4兼顾了功能和 simplicity。对应的文件是Portable/MemMang/heap_4.c。2.2 Keil工程里的分组与路径设置在Keil里我通常会建三个GroupFreeRTOS_Core、FreeRTOS_Port和FreeRTOS_Config。FreeRTOS_Core里放tasks.c、queue.c、list.c、timers.c这些核心文件FreeRTOS_Port里放port.c和heap_4.cFreeRTOS_Config里放FreeRTOSConfig.h。这里有一个容易忽略的点头文件的包含路径。你需要在Keil的Options for Target - C/C - Include Paths里把FreeRTOS/Source/include、FreeRTOS/Portable/RVDS/ARM_CM3或CM4F、FreeRTOS/Config这三个路径都加进去。少了任何一个编译的时候都会报找不到头文件的错误。还有一个细节FreeRTOS的源码文件里会包含一些FreeRTOS.h、task.h这样的头文件这些头文件又依赖于FreeRTOSConfig.h。所以FreeRTOSConfig.h所在的路径必须在包含路径里而且这个文件的名字不能改必须是FreeRTOSConfig.h因为源码里是硬编码引用的。实操心得在Keil里添加文件的时候建议用“Add Existing Files to Group”的方式把文件从工程目录里添加进来而不是直接复制到Keil的默认目录。这样工程目录结构清晰换电脑或者分享给同事的时候直接把整个工程文件夹打包就行不会出现路径丢失的问题。2.3 编译选项的调整GD32和STM32一样都是Cortex-M内核所以编译选项上基本一致。在Keil的Target选项中需要确认几点一是芯片型号选对比如GD32F303ZE二是ROM和RAM的起始地址和大小要和芯片手册一致三是如果用了FPU要在C/C选项卡里把Floating Point Hardware设为Single Precision。另外FreeRTOS的port.c里有一些内嵌汇编Keil的编译器对这些汇编的语法支持是没问题的但如果你开了很高的优化等级有时候会出现一些奇怪的问题。我一般调试阶段用-O0发布的时候用-O2-O3不太建议FreeRTOS的某些临界区代码在-O3下可能会被优化出问题。还有一个重要的编译选项是__MICROLIB。如果你在Target里勾了Use MicroLIB那么printf重定向会简单很多但MicroLIB和FreeRTOS本身没有冲突。不过要注意MicroLIB不支持某些标准库功能如果你的项目里用了这些功能就不要勾。3. FreeRTOSConfig.h配置文件的逐项拆解3.1 基础调度相关配置FreeRTOSConfig.h是整个移植过程中最需要仔细对待的文件。我把它里面的配置项分成几类第一类是基础调度相关的。configUSE_PREEMPTION这个宏决定是抢占式调度还是协作式调度。抢占式调度下高优先级任务就绪时会立刻抢占低优先级任务协作式调度下任务必须主动让出CPU才会切换。绝大多数项目都用抢占式设为1。configUSE_TIME_SLICING是时间片轮转当多个任务优先级相同时每个任务轮流执行一个tick。这个一般也设为1除非你有特殊需求。configCPU_CLOCK_HZ这个宏要填GD32的系统时钟频率。比如GD32F303跑到120MHz这里就填120000000。这个值必须和实际的系统时钟一致否则FreeRTOS的延时和超时都会不准。configTICK_RATE_HZ是系统节拍频率一般设为1000也就是1ms一个tick。这个值决定了FreeRTOS的时间精度。设得太高中断开销大设得太低延时精度差。1000Hz是个比较平衡的选择。configMAX_PRIORITIES是最大任务优先级数FreeRTOS里优先级数值越大优先级越高。这个值根据你的项目需要来设一般设个8到16就够了。设得太大浪费RAM因为每个优先级都要维护一个就绪列表。configMINIMAL_STACK_SIZE是空闲任务的堆栈大小单位是字word不是字节。在Cortex-M3上一个字是4字节。这个值一般设128也就是512字节。如果你的空闲任务里挂了钩子函数可能要适当加大。3.2 内存管理与钩子函数配置configTOTAL_HEAP_SIZE是FreeRTOS堆的总大小单位是字节。这个值取决于你创建多少个任务、队列、信号量。每个任务需要一块任务控制块TCB和一块堆栈空间。TCB大概占100字节左右堆栈大小取决于任务里用了多少局部变量和函数调用深度。我一般会先给一个保守的值比如20KB然后运行起来之后调用xPortGetFreeHeapSize()看看还剩多少再调整。如果堆不够创建任务的时候会返回失败或者直接进HardFault。configUSE_IDLE_HOOK和configUSE_TICK_HOOK分别是空闲任务钩子和节拍钩子。空闲钩子适合放一些低优先级的后台处理比如喂狗节拍钩子适合做系统级的定时统计。这两个钩子函数如果启用了你必须自己实现vApplicationIdleHook()和vApplicationTickHook()否则链接会报错。configUSE_MALLOC_FAILED_HOOK是内存分配失败钩子建议启用。当pvPortMalloc返回NULL的时候会调用vApplicationMallocFailedHook()你可以在这里打印信息或者点亮错误灯方便定位问题。configCHECK_FOR_STACK_OVERFLOW是堆栈溢出检测这个强烈建议启用。它有两个检测模式模式1在任务切换时检查堆栈指针是否越界模式2在任务切换时检查堆栈末尾的标记值是否被改写。模式2更可靠但开销稍大。启用之后如果检测到溢出会调用vApplicationStackOverflowHook()你可以在里面打印出问题的任务名。3.3 中断优先级与硬件相关配置configKERNEL_INTERRUPT_PRIORITY和configMAX_SYSCALL_INTERRUPT_PRIORITY这两个宏是移植中最容易出错的地方。Cortex-M3/M4的中断优先级寄存器是8位的但GD32一般只实现了高4位低4位是0。FreeRTOS的配置宏需要把优先级值左移到高4位。比如configKERNEL_INTERRUPT_PRIORITY一般设为15最低优先级左移4位就是0xF0。configMAX_SYSCALL_INTERRUPT_PRIORITY一般设为5左移4位就是0x50。这个configMAX_SYSCALL_INTERRUPT_PRIORITY的含义是优先级数值高于这个值也就是优先级更低的中断可以安全地调用FreeRTOS的API函数优先级数值低于这个值优先级更高的中断不能调用FreeRTOS的API因为它们不会被FreeRTOS的临界区屏蔽。在GD32的中断优先级分组里一般用NVIC_PriorityGroup_4也就是所有位都用于抢占优先级没有子优先级。这样配置最简单也最不容易出错。configLIBRARY_LOWEST_INTERRUPT_PRIORITY和configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY这两个宏是库函数层面的值分别对应上面的两个宏但不需要左移。它们主要用于NVIC_SetPriority()这样的库函数调用。注意GD32的中断优先级数值越小优先级越高这和FreeRTOS的任务优先级正好相反。任务优先级是数值越大越高。这个差异在配置中断的时候一定要搞清楚否则会出现中断嵌套混乱的问题。4. 硬件接口适配SysTick、PendSV与SVC4.1 SysTick中断的接管FreeRTOS需要一个周期性的系统节拍来驱动任务调度和延时。在Cortex-M上这个节拍通常由SysTick定时器产生。SysTick是内核外设GD32和STM32的SysTick寄存器完全兼容。在裸机工程里SysTick一般被用来做延时函数比如delay_ms()。移植FreeRTOS的时候你需要把SysTick的配置从裸机代码里移除交给FreeRTOS来管理。具体来说FreeRTOS的port.c里已经实现了xPortSysTickHandler()你只需要在启动文件或者中断向量表里把SysTick_Handler指向这个函数就行。在Keil的启动文件startup_gd32f30x.s里SysTick_Handler是一个弱符号你可以自己在C文件里重新定义。我一般会在FreeRTOSConfig.h里加上这样一行#define xPortSysTickHandler SysTick_Handler然后在port.c里xPortSysTickHandler就是实际的中断服务函数。这样启动文件里的弱符号会被覆盖SysTick中断就会进入FreeRTOS的处理流程。SysTick的 reload 值由FreeRTOS根据configCPU_CLOCK_HZ和configTICK_RATE_HZ自动计算你不需要手动设置。计算方式是reload configCPU_CLOCK_HZ / configTICK_RATE_HZ - 1。比如120MHz的时钟1000Hz的节拍reload就是119999。4.2 PendSV与SVC的优先级设置PendSV和SVC是Cortex-M内核的两个异常FreeRTOS用它们来实现任务切换。PendSV是可挂起的异常FreeRTOS在需要切换任务的时候会把PendSV挂起等所有高优先级中断处理完之后再进入PendSV处理任务切换。SVC是系统服务调用FreeRTOS在启动第一个任务的时候会用到。这两个异常的优先级设置非常关键。PendSV的优先级必须设为最低也就是数值最大。SVC的优先级一般也设为最低或者比PendSV稍高一点。在FreeRTOS的port.c里vPortSVCHandler和xPortPendSVHandler这两个函数已经实现了异常处理逻辑你只需要在启动文件里把SVC_Handler和PendSV_Handler指向它们。在FreeRTOSConfig.h里configKERNEL_INTERRUPT_PRIORITY这个宏就是用来设置PendSV和SysTick的优先级的。前面说了它一般设为15左移4位也就是0xF0。这个值会被写入到NVIC的PendSV和SysTick优先级寄存器里。实操心得如果你在GD32上用了其他中断比如串口中断、定时器中断并且这些中断里要调用FreeRTOS的API比如xQueueSendFromISR那么这些中断的优先级必须不高于configMAX_SYSCALL_INTERRUPT_PRIORITY。否则会出现中断里调用API导致系统崩溃的问题。我一般把要用FreeRTOS API的中断优先级设为6或7留出足够的余量。4.3 启动第一个任务的流程FreeRTOS启动调度器的函数是vTaskStartScheduler()。这个函数会创建空闲任务和定时器任务如果启用了软件定时器然后配置SysTick最后调用xPortStartScheduler()。xPortStartScheduler()里会设置PendSV和SysTick的优先级然后触发SVC异常。SVC异常的处理函数vPortSVCHandler()会从就绪列表里找到最高优先级的任务恢复它的上下文然后跳转到任务的入口函数。这个过程涉及到一堆汇编代码你不需要完全看懂但要知道它的作用。在GD32上这个流程和STM32完全一样因为都是Cortex-M内核。唯一需要注意的是GD32的启动文件里SVC_Handler和PendSV_Handler的名字可能和STM32略有不同你要根据实际的启动文件来调整。启动第一个任务之后FreeRTOS就进入了正常的调度循环。SysTick每隔1ms触发一次检查是否有任务需要唤醒或者切换。如果有更高优先级的任务就绪PendSV会被挂起等SysTick处理完之后执行任务切换。5. 常见问题排查与实战避坑指南5.1 编译链接阶段的典型错误移植过程中编译链接阶段的错误是最容易解决的因为编译器会直接告诉你哪里有问题。最常见的几个错误我整理了一下错误信息原因解决方法undefined symbol xPortSysTickHandler没有把SysTick_Handler映射到FreeRTOS的处理函数在FreeRTOSConfig.h里加#define xPortSysTickHandler SysTick_Handlerundefined symbol vApplicationIdleHook启用了空闲钩子但没有实现实现vApplicationIdleHook()函数或者把configUSE_IDLE_HOOK设为0undefined symbol vApplicationStackOverflowHook启用了堆栈溢出检测但没有实现钩子实现钩子函数或者关闭configCHECK_FOR_STACK_OVERFLOWcannot open source input file FreeRTOS.h头文件包含路径没设对在Keil的Include Paths里加上FreeRTOS/Source/includeL6406E: No space in execution regions堆或者栈太大超出了RAM减小configTOTAL_HEAP_SIZE或者任务堆栈大小还有一个比较隐蔽的错误是重复定义。比如你的裸机工程里已经有一个SysTick_HandlerFreeRTOS的port.c里也有一个链接的时候就会报重复定义。解决办法是把裸机工程里的SysTick_Handler删掉或者改名。5.2 运行阶段的HardFault排查HardFault是移植过程中最让人头疼的问题因为它的现象往往是程序跑飞了但不知道飞到哪里去了。我总结了一套排查HardFault的流程基本上能覆盖大部分情况。第一步在HardFault_Handler里加一个死循环然后在这个死循环里打个断点。程序跑飞之后会停在这里。然后你看Call Stack窗口看看是从哪个函数跳过来的。如果Call Stack是空的那就看LR寄存器的值找到跳转前的地址。第二步检查堆栈溢出。如果某个任务的堆栈太小任务切换的时候就会踩到别的内存区域导致HardFault。启用configCHECK_FOR_STACK_OVERFLOW之后如果是因为堆栈溢出导致的会先进入vApplicationStackOverflowHook()你可以在里面打印任务名。第三步检查中断优先级。如果在一个优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断里调用了FreeRTOS的API会导致临界区失效进而引发HardFault。这种情况的典型现象是程序在运行一段时间后随机崩溃而且崩溃的位置不固定。第四步检查堆是否够用。如果configTOTAL_HEAP_SIZE设得太小创建任务或者队列的时候会返回NULL如果你没有检查返回值就直接使用就会访问空指针导致HardFault。我一般会在创建任务之后检查一下返回值如果是NULL就打印错误信息。避坑技巧在GD32上如果用了FPU并且任务里做了浮点运算一定要确保port.c用的是ARM_CM4F版本而不是ARM_CM3版本。用错了版本浮点寄存器的上下文不会被保存任务切换之后浮点运算结果就会错乱严重的时候直接HardFault。5.3 任务调度异常的调试方法有时候程序没有HardFault但任务调度不正常比如某个任务一直不执行或者延时不准。这类问题一般和配置有关。如果某个任务一直不执行先检查它的优先级是不是太低被其他高优先级任务一直抢占。FreeRTOS是抢占式调度如果有一个高优先级任务一直在跑不让出CPU低优先级任务就永远得不到执行。解决办法是在高优先级任务里加vTaskDelay()或者taskYIELD()让出CPU。如果延时不准检查configCPU_CLOCK_HZ和configTICK_RATE_HZ是否和实际一致。另外如果SysTick的中断优先级设得太低被其他中断频繁打断也会导致节拍丢失延时变长。如果任务切换的时候串口打印乱码可能是任务堆栈太小导致局部变量被覆盖。可以试着把任务堆栈加大一倍看看问题是否消失。还有一个常见问题是在中断里调用了非FromISR版本的API。比如在串口中断里调用了xQueueSend()而不是xQueueSendFromISR()这会导致中断里的操作破坏了就绪列表的一致性进而引发调度异常。这个问题的现象是程序在中断频繁触发的时候随机崩溃。5.4 内存优化与堆栈大小的确定FreeRTOS的RAM占用主要来自三块内核对象TCB、就绪列表、队列等、任务堆栈、FreeRTOS堆。在GD32F103这类RAM只有20KB的芯片上内存优化就很重要了。任务堆栈大小的确定我一般用两种方法。一种是静态估算看任务里最大的函数调用深度加上局部变量的大小再留50%的余量。另一种是动态测量先把堆栈设大一点然后调用uxTaskGetStackHighWaterMark()看看历史最小剩余量再根据这个值来调整。比如一个任务堆栈设了512字2KB运行一段时间后HighWaterMark返回400说明历史最多用了112字那么堆栈可以减到256字左右留一倍余量。configTOTAL_HEAP_SIZE的确定可以用xPortGetFreeHeapSize()来监控。在系统稳定运行之后看看还剩多少堆如果剩余很多可以适当减小如果剩余很少就要加大或者检查是否有内存泄漏。实操心得在GD32F103这种小RAM芯片上建议把configUSE_TIMERS设为0不用软件定时器这样可以省掉定时器任务的堆栈和队列。软件定时器的功能可以用硬件定时器加任务通知来替代更省资源。6. 移植完成后的验证与功能扩展6.1 基础功能验证清单移植完成之后不要急着往上加应用代码先做一轮基础功能验证。我一般会写一个简单的测试程序创建三个任务一个任务每秒翻转一次LED一个任务每500ms通过串口打印一条信息一个任务每2秒通过串口打印堆的使用情况。这三个任务跑起来之后观察LED的闪烁频率是否准确串口打印的时间间隔是否稳定堆的使用情况是否有异常变化。如果这些都正常说明FreeRTOS的调度、延时、内存管理都工作正常。然后测试任务间的通信。创建一个队列一个任务往队列里发数据另一个任务从队列里收数据验证队列的发送和接收是否正常。再测试一下信号量一个任务释放信号量另一个任务获取信号量验证同步机制是否正常。最后测试中断和任务的交互。在串口中断里用xQueueSendFromISR往队列里发数据在任务里接收验证中断安全的API是否正常工作。6.2 从移植到实战的进阶路线基础验证通过之后就可以开始把FreeRTOS用到实际项目里了。我的建议是先从简单的多任务架构开始比如把原来的裸机大循环拆成几个独立的任务每个任务负责一个功能模块任务之间用队列或者信号量通信。然后逐步引入更高级的功能。比如用事件组来管理多个任务的同步用任务通知来替代二值信号量以提高效率用流缓冲区来处理串口的不定长数据。如果项目里有LCD显示可以考虑移植LVGL。LVGL本身是单线程的但可以把它放在一个独立的任务里通过消息队列接收其他任务的显示请求。这样显示刷新不会阻塞其他任务界面也会更流畅。如果项目里有网络通信GD32加上LWIP协议栈可以把网络处理放在一个高优先级任务里协议解析放在另一个任务里通过队列传递数据包。这样网络收发的实时性会好很多。6.3 性能调优的几个方向FreeRTOS在GD32上跑起来之后如果觉得性能不够可以从几个方向调优。一是调整configTICK_RATE_HZ。如果项目对延时精度要求不高可以把节拍从1000Hz降到100Hz这样SysTick中断的开销会小很多CPU有更多时间跑任务。二是优化任务优先级分配。把实时性要求高的任务设为高优先级把后台处理任务设为低优先级。避免多个任务设成同一优先级因为同优先级任务会时间片轮转增加切换开销。三是减少临界区的长度。FreeRTOS的API函数里有些会进入临界区关中断。如果临界区太长会影响中断响应。所以在任务里调用API的时候尽量把能放在临界区外面的操作放在外面。四是使用任务通知替代信号量。任务通知是FreeRTOS里最高效的任务间通信方式它不需要创建额外的内核对象直接操作任务的TCB。在只需要一对一同步的场景下任务通知比信号量快很多。五是合理使用DMA。GD32的外设支持DMA比如串口收发、SPI传输、ADC采样都可以用DMA。把数据搬运的工作交给DMACPU只需要处理DMA完成中断这样可以大大减轻任务的负担。6.4 从GD32F103到GD32F303的移植差异如果你已经在GD32F103上移植好了FreeRTOS想换到GD32F303大部分代码是可以直接复用的但有几个地方需要注意。首先是时钟频率不同。GD32F103最高72MHzGD32F303最高120MHz。configCPU_CLOCK_HZ要相应修改否则延时和节拍都会不准。其次是FPU。GD32F303带浮点单元如果你要用浮点运算需要把port.c从ARM_CM3换成ARM_CM4F并且在Keil里开启FPU支持。GD32F103没有FPU只能用软件浮点。然后是中断向量表。GD32F303的中断源比GD32F103多启动文件也不同。移植的时候要确认SVC_Handler、PendSV_Handler、SysTick_Handler这三个异常处理函数的映射是否正确。最后是RAM大小。GD32F303的RAM一般比GD32F103大configTOTAL_HEAP_SIZE可以适当加大任务堆栈也可以给得更充裕。我在实际项目里从GD32F103换到GD32F303的时候基本上只改了时钟配置和FPU相关的几个宏其他代码一行没动半天就完成了迁移。这也是FreeRTOS这种成熟RTOS的好处硬件相关的代码被隔离在port层换芯片的时候只需要改port层和配置文件。最后再分享一个小技巧如果你在Keil里调试FreeRTOS的时候想看每个任务的运行状态和堆栈使用情况可以安装一个FreeRTOS的Keil插件或者用SEGGER的SystemView。SystemView可以图形化地显示任务的切换时序、中断的触发情况、队列的收发记录对于分析系统的实时性非常有帮助。我每次做性能优化的时候都会先用SystemView跑一遍看看哪里是瓶颈然后再有针对性地调整。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →