> 技术文档 > GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

版本:FreeRTOS Kernel V11.1.0,文末提供最终工程的下载链接。

一、准备

1. GD32 Keil工程

准备任意一个可以正常运行的GD32工程文件,这里使用的是自己建立的工程模板文件,一个点灯与HelloWorld工程:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

2. FreeRTOS源码

首先下载最新的源码:
Download: FreeRTOS Kernel
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
我们会得到一个压缩文件,然后解压出来备用,现在准备好了一个GD32 Keil工程和一个FreeRTOS源码:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

接下来我们开始移植。

二、FreeRTOS移植

1. 文件操作

对于移植使用来说,我们主要关注下面这几个FreeRTOS的关键文件,后面都会用到:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
首先在GD32工程文件中,找到合适的地方,新建“FreeRTOS”文件夹,并新建三个子文件夹“inc”、“src”、“port”用于存放上述文件:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
然后将“.\\FreeRTOS\\FreeRTOS-Kernel\\include”目录下所有文件拷贝到新建的“./FreeRTOS/inc”文件夹下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
为了简洁,我们删除非.h文件:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
然后把下面这几个C文件拷贝到src目录下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
然后将配置文件的模板文件拷贝到“/FreeRTOS”目录下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

在接口层,我们主要适配内存管理部分和IC硬件上的接口部分,这两个位于“.\\FreeRTOS-Kernel\\portable”下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
我们把整个“MemMang”目录直接复制到“port”目录下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

“MemMang”中是FreeRTOS提供的5个内存分配方案:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

“RVDS”是为编译器提供编译环境所需要的相关文件,我们也把他们拷贝到目录下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

我们需要根据自己的MCU类型去选择,例如我们使用的GD32F303x系列是ARM架构、Cortex-M4的核、不带MPU的MCU,就仅保留\"ARM_CM4F\"的文件夹:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
最终我们操作后的相关文件如下:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
接下来我们就要在编译器中将上述文件加载进来

2. 工程操作

打开工程文件,新建工程资源文件夹“FreeRTOS/Src”和“FreeRTOS/Port”,然后把对应的C文件加载进来:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
其中内存管理上我们选择“heap_4”:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
C文件添加完成后把头文件的路径包含进来:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
记得编译器使用V5:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
接下来就是代码操作部分,完成最后的接口适配工作

3. 代码操作

首先调整堆栈大小,打开启动文件”startup_gd32f30x_hd.s“,我使用的GD32F303VET6,64K+512K,堆栈设置为0x2000,大家根据自己的项目需要和MCU能力自由分配:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
首先先打开载入配置文件,可以在main.c文件中导入“FreeRTOS.h“,然后右键打开h文件:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
然后就可以看到引用的“FreeRTOSConfig.h”文件,还是右键打开:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
在“FreeRTOSConfig.h”文件中配置freeRTOS,官方模板文件中开启了很多的配置项,对于初学者,大部分我们并不太关心,由于新版本只有模板文件,我们可以直接从老版本中下载一个STM32的Demo配置文件,替换这个模板文件的内容:

/* * FreeRTOS V202212.00 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the \"Software\"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * https://www.FreeRTOS.org * https://github.com/FreeRTOS * */#ifndef FREERTOS_CONFIG_H#define FREERTOS_CONFIG_H/*----------------------------------------------------------- * Application specific definitions. * * These definitions should be adjusted for your particular hardware and * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE \'CONFIGURATION\' SECTION OF THE * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. * * See http://www.freertos.org/a00110.html *----------------------------------------------------------*/#define configUSE_PREEMPTION1#define configUSE_IDLE_HOOK0#define configUSE_TICK_HOOK0#define configCPU_CLOCK_HZ( ( unsigned long ) 72000000 )#define configTICK_RATE_HZ( ( TickType_t ) 1000 )#define configMAX_PRIORITIES( 5 )#define configMINIMAL_STACK_SIZE( ( unsigned short ) 128 )#define configTOTAL_HEAP_SIZE( ( size_t ) ( 17 * 1024 ) )#define configMAX_TASK_NAME_LEN( 16 )#define configUSE_TRACE_FACILITY0#define configUSE_16_BIT_TICKS0#define configIDLE_SHOULD_YIELD1/* Co-routine definitions. */#define configUSE_CO_ROUTINES 0#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )/* Set the following definitions to 1 to include the API function, or zeroto exclude the API function. */#define INCLUDE_vTaskPrioritySet1#define INCLUDE_uxTaskPriorityGet1#define INCLUDE_vTaskDelete1#define INCLUDE_vTaskCleanUpResources0#define INCLUDE_vTaskSuspend1#define INCLUDE_vTaskDelayUntil1#define INCLUDE_vTaskDelay1/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255(lowest) to 0 (1?) (highest). */#define configKERNEL_INTERRUPT_PRIORITY 255/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. *//* This is the value being used as per the ST library which permits 16priority values, 0 to 15. This must correspond to theconfigKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowestNVIC value of 255. */#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY15#endif /* FREERTOS_CONFIG_H */

下图的文件就是上面的代码内容,大家可以直接复制上面的代码或者自行下载例如10.4版本的源码,在下述路径找到配置文件:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
更新配置文件后,首先调整系统时钟,在”FreeRTOSConfig.h“文件中添加如下代码:

#if defined(__ICCARM__)||defined(__CC_ARM)||defined(__GNUC__)#include extern uint32_t SystemCoreClock;#endif

然后配置“configCPU_CLOCK_HZ”为“SystemCoreClock”

#define configCPU_CLOCK_HZ(SystemCoreClock) //( unsigned long ) 72000000 

GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
上面文件先不要关闭,我们打开“port.c”文件,主要是适配这三个接口函数:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
我们在回到“FreeRTOSConfig.h”文件,在最后添加如下宏:

#define vPortSVCHandler SVC_Handler#define xPortPendSVHandler PendSV_Handler

GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
还有一个xPortSysTickHandler函数用于更新系统时基,我们把它放在系统滴答里,打开“gd32f30_it.c”文件,首先添加头文件与函数声明:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
滑到最后,注释掉原有的“SVC_Handler(){}和“PendSV_Handler(){}”函数,这两个已经被上面的宏定义替换了,然后在”SysTick_Handler“中添加

#if (INCLUDE_xTaskGetSchedulerState == 1 )if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED){#endif xPortSysTickHandler();#if (INCLUDE_xTaskGetSchedulerState == 1 )}#endif 

编译运行0警告0错误

三、Hello FreeRTOS

1. 创建任务

任务相关使用需要包含头文件”task.h“,然后创建两个任务,一个LED灯任务一个打印任务:

//【LED任务】//任务优先级#define LED_TASK_PRIO(tskIDLE_PRIORITY + 1)//任务堆栈大小#define LED_STK_SIZE 50 //任务句柄TaskHandle_t LEDTask_Handler;//任务函数void LED_Task(void *pvParameters);//【Debug任务】//任务优先级#define Debug_TASK_PRIO(tskIDLE_PRIORITY + 2)//任务堆栈大小#define Debug_STK_SIZE 512 //任务句柄TaskHandle_t Debug_Task_Handler;//任务函数void Debug_Task(void *pvParameters);

GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

然后定义一个任务创建函数:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

/*********************************************************************************************************** 函 数 名: RTOS_Init* 功能说明: RTOS初始化,用于创建任务* 形 参:无* 返 回 值: 无**********************************************************************************************************/void RTOS_Init(void){taskENTER_CRITICAL();  //进入临界区//创建LED任务xTaskCreate((TaskFunction_t )LED_Task, (const char* )\"LED_task\", (uint16_t )LED_STK_SIZE, (void* )NULL,(UBaseType_t )LED_TASK_PRIO,(TaskHandle_t* )&LEDTask_Handler); //创建Debug任务xTaskCreate((TaskFunction_t )Debug_Task, (const char* )\"Debug_task\", (uint16_t )Debug_STK_SIZE, (void* )NULL,(UBaseType_t )Debug_TASK_PRIO,(TaskHandle_t* )&Debug_Task_Handler); taskEXIT_CRITICAL(); //退出临界区vTaskStartScheduler(); //开启任务调度}

实现两个任务函数:

/*********************************************************************************************************** 函 数 名: LED_Task* 功能说明: LED任务* 形 参: 无* 返 回 值: 无**********************************************************************************************************/void LED_Task(void *pvParameters){ while(1) { LED_BlinkOnOff(); vTaskDelay(500); }} /*********************************************************************************************************** 函 数 名: Debug_Task* 功能说明: Debug任务* 形 参: 无* 返 回 值: 无**********************************************************************************************************/void Debug_Task(void *pvParameters){ while(1) { printf(\"Hello FreeRTOS\\r\\n\"); vTaskDelay(500); }} 

在主函数中完成调用:

int main(void){ /* configure systick */ systick_config();System_Init();RTOS_Init();}

GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos

2. 编译下载

编译下载即可看到串口打印信息以及LED周期闪烁:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos
最后附一张资源占用情况:
GD32+FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU_gd32 freertos


接下来大家就可以嗨皮的学习FreeRTOS的各类组件了,如果大家需要上述工程文件,公众号私信【1023】即可获取本文使用的Demo工程文件。