GD32F103*固件库移植FreeRTOS详细教程与解析
GD32F103*移植μCOS-Ⅲ详细教程与解析,欢迎指正
文章目录
- GD32F103*固件库移植FreeRTOS详细教程与解析
- 前言
- 一、移植前的准备
- 二、移植步骤
- 1.文件结构
- 2.添加代码
- 3.编译与配置
 
- 三、注意事项
- 总结
前言
FreeRTOS是一个可以基于ROM运行的、可裁剪的、抢占式、实时多任务内核,具有高度可移植性,特点:公开源代码、可移植性、可固化、可裁剪、多任务、占先式,特别适合于微处理器和控制器,适合很多商业操作系统性能相当的实时操作系统(RTOS)。在使用GD32F103单片机项目使用过FreeRTOS,这里作为一个基础教学版简单记录一下移植过程,最终成果后续上传更新,欢迎指正!
一、移植前的准备
<1>、硬件平台:可运行软件程序的GD32单片机(本项目使用GD32F103CBT6硬件平台)
 <2>、软件平台:可直接下载运行的单片机基础工程,本例程是基于使用标准库GD32F10x_Firmware_Library_V2.2.4固件库编写,点击此处可直接获取本试验基础工程
 <3>、源码获取:FreeRTOS源码(本例程使用FreeRTOS源码版本为:FreeRTOS9.0.0)
 <4>、J-link或ST-link等下载器
 <5>、源码简介:在上篇FreeRTOS简介中已经介绍:https://blog.csdn.net/Yin_w/article/details/134771124
二、移植步骤
1.文件结构
1.在基础工程同目录下新建FreeRTOS文件夹用来保存FreeRTOS源码
 
 2.将源码\FreeRTOS\portable目录除以下文件夹以外的文件夹可以删除
 
 3.打开Keil工程,在基础工程目录下新建FreeRTOS_Core、FreeRTOS_Protable文件分组,然后严格按照以下步骤去添加文件。
 
■FreeRTOS_Core分组:将\FreeRTOSv9.0.0\FreeRTOS\Source目录下*.c文件添加到此分组中
■FreeRTOS_Protable分组:FreeRTOS_PORTABLE 分组中的port.c 是 RVDS 文件夹下的 ARM_CM3 中的文件,因为GD32F103是 Cortex-M43内核,因此要选择 ARM_CM3 中的 port.c 文件。heap_4.c 是 MemMang 文件夹中的,这5 个 c 文件是五种不同的内存管理方法,我们选取heap_4这种方式。
 
 4.添加头文件路径,Target-C/C++下,添加如下头文件路径
 
 5.新建四个文件名字分别是system_cfg.c和system_cfg.h,FreeRTOS_main.c和FreeRTOS_main.h都保存到main.c所在目录下。system_cfg.c和system_cfg.h文件主要是包含一些全局的自定义配置。FreeRTOS_main.c和FreeRTOS_main.h主要是OS的任务启动、调度函数等,这样划分的主要目的是使得系统main函数和OS的main函数分开,结构会很清晰明朗,系统启动会进入系统main函数初始化各个外设组件和软件模块,然后再进入OS的main中进行任务调度,以下会详细说明各个文件的作用和内容。
 
 6.如图将system_cfg.c和FreeRTOS_main文件添加到user组件下方。
 
2.添加代码
1.system_cfg.c主要是系统配置需要的文件,本例程中主要配置主要都在system_cfg.h文件中,这里的内容是我自己写的,不必完全参考,其他内容也可自己补充
/******************************************************************************************************* @file          system_cfg.c* @author        Awen_* @version       V1.0* @date          2023-04-13* @brief         system Initialization configuration* @license* @modifyRecord:*                V1.0  XXX  XXXX-XX-XX Modify...*                V2.0  XXX  XXXX-XX-XX Modify...***************************************************************************************************** @attention  :*                Hardware Testing Platform:兆易创新(GigaDevice)  GD32F103RE*                Software Support Package :GD32F10x_Firmware_Library_V2.2.4* *****************************************************************************************************/#ifndef __SYS_H
#define __SYS_H#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <gd32f10x.h>
#include <systick.h>
#include "gd32f10x_libopt.h"#define SYSTEM_SUPPORT_OS		     1	  //定义系统文件夹是否支持OS
#define SYSTEM_SUPPORT_DEBUG     	 1   //是否支持串口打印调试/*
*********************************************************************************************************
*                                     如果使用FreeRTOS_main,则包括下面的头文件即可
*********************************************************************************************************
*/
#ifdef SYSTEM_SUPPORT_OS#include "FreeRTOS_main.h"					//FreeRTOS_main 使用
#endif/*
*********************************************************************************************************
*                                     如果使用FreeRTOS_main,则包括下面的头文件即可
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                                 定义返回值类型  
*********************************************************************************************************
*/typedef uint8_t  ReturnType_u8;
typedef uint16_t ReturnType_u16;
typedef uint32_t ReturnType_u32;typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t  u8;/*
*********************************************************************************************************
*                                                  获取数组长度宏  
*********************************************************************************************************
*/
#define ARRAYNUM(arr_name)     (uint32_t)(sizeof(arr_name) / sizeof(*(arr_name)))
/*
*********************************************************************************************************
*                                   如果使用串口Debug,则定义SYSTEM_SUPPORT_DEBUG 1
*********************************************************************************************************
*/
#ifdef SYSTEM_SUPPORT_DEBUG#define Debug  			printf
#else#define Debug(...)  do{ }while(0)
#endif/*
*********************************************************************************************************
*                                                  定义空指针类型
*********************************************************************************************************
*/
#define NULL_PTR  ((void*)0)/*
*********************************************************************************************************
*                                                  定义错误代号
*********************************************************************************************************
*/
#ifndef E_OK#define E_OK  0U
#endif#ifndef E_NOT_OK#define E_NOT_OK  1U
#endifextern void FWDG_Init(void);#endif
2.system_cfg.c主要是系统配置需要的文件,本例程中主要配置主要都在system_cfg.h文件中,所以system_cfg.c文件中的内容之包含system_cfg.h头文件,其他内容可先空着方便后续补充。
代码如下(示例):
/******************************************************************************************************* @file          system_cfg.c* @author        Awen_* @version       V1.0* @date          2023-04-13* @brief         system config file* @license* @modifyRecord:*                V1.0  XXX  XXXX-XX-XX Modify...*                V2.0  XXX  XXXX-XX-XX Modify...***************************************************************************************************** @attention  :*                Hardware Testing Platform:兆易创新(GigaDevice)  GD32F103RE*                Software Support Package :GD32F10x_Firmware_Library_V2.2.4*                *****************************************************************************************************/
#define FWDG_TIMEOUT_3000MS   (3750u) #include "system_cfg.h"void FWDG_Init(void)
{/* configure FWDGT counter clock: 40KHz(IRC40K) / 32 = 0.625 KHz */fwdgt_config(FWDG_TIMEOUT_3000MS,FWDGT_PSC_DIV32);/* after 3 seconds to generate a reset */fwdgt_enable();
}
3.FreeRTOS_main.h文件主要作为FreeRTOS_main.c的头文件,FreeRTOS_main(void)函数作为FreeRTOS系统的入口,可在FreeRTOS_main.c中实现,以供main函数调用,也可自己添加一些OS的配置
/******************************************************************************************************* @file        FreeRTOS.h* @author      Awen_* @version     V2.0* @date        2023-06-13* @brief       FreeRTOS 实验* @license     Copyright (c) 2020-2032, ***************************************************************************************************** @attention*******************************************************************************************************/
#ifndef __FreeRTOS_MAIN_H
#define __FreeRTOS_MAIN_H//#include "system_cfg.h"
//#include "usart_Func.h"
/*uC/OS-III*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"extern void FreeRTOS_main(void);#endif
4.FreeRTOS_main.c文件就是OS的主场,FreeRTOS_main(void)的实现,系统启动,创建任务,任务函数都是在这里实现,此处给出一个简单的例程,不必深究内容,大意就是创建了三个优先级不同的任务,分别闪灯和usart0输出点内容。这里可直节复制粘贴即可,先不必深究内容。
/******************************************************************************************************* @file          IoHwAb.c* @author        Awen_* @version       V1.0* @date          2023-04-13* @brief         Hardware IO Initialization configuration* @license* @modifyRecord:*                V1.0  XXX  XXXX-XX-XX Modify...*                V2.0  XXX  XXXX-XX-XX Modify...***************************************************************************************************** @attention  :*                Hardware Testing Platform:兆易创新(GigaDevice)  GD32F103RE*                Software Support Package :GD32F10x_Firmware_Library_V2.2.4* *****************************************************************************************************//*
*****************************************************************************************************
*                                                Header Flie
*****************************************************************************************************
*/#include "FreeRTOS_main.h"
/*Peripheral Header file*/
#include "IOHard_cfg.h"
#include "usart_cfg.h"
#include "usart_Func.h"/*
*****************************************************************************************************
*                                               FreeRTOS_main配置
*****************************************************************************************************
*//* Start Task */
#define START_TASK_PRIO                 5
#define START_TASK_STACK_SIZE           256
TaskHandle_t StartTask_Handler;			    //任务句柄
void 	start_task(void *pvParameters); 	//任务函数/*Task1*/
#define TASK1_PRIO                      2
#define TASK1_STACK_SIZE                256
TaskHandle_t Task1_Handler;	            //任务句柄
void 	Task1_Func(void *p_agc);	        //任务函数/*Task2*/
#define TASK2_PRIO                      3
#define TASK2_STACK_SIZE                256
TaskHandle_t Task2_Handler;	            //任务句柄
void 	Task2_Func(void *p_agc);	        //任务函数/*** @brief       FreeRTOS main.c 入口函数* @param       无         * @retval      无*/
void FreeRTOS_main(void)
{systick_config();                                             //开启xTaskCreate(  (TaskFunction_t )start_task,                    //任务函数(const char*    )"start_task",                  //任务名称(uint16_t       )START_TASK_STACK_SIZE,         //任务堆栈大小(void*          )NULL,                          //传递给任务函数的参数(UBaseType_t    )START_TASK_PRIO,               //任务优先级(TaskHandle_t*  )&StartTask_Handler);           //任务句柄/*开始任务调度*/vTaskStartScheduler();
}void start_task(void *p_arg)
{/*创建优先级任务1*/taskENTER_CRITICAL();        		   xTaskCreate(  (TaskFunction_t )Task1_Func,                  //任务函数(const char*    )"Task1_Func",                //任务名称(uint16_t       )TASK1_STACK_SIZE,            //任务堆栈大小(void*          )NULL,                        //传递给任务函数的参数(UBaseType_t    )TASK1_PRIO,                  //任务优先级(TaskHandle_t*  )&Task1_Handler);             //任务句柄xTaskCreate(  (TaskFunction_t )Task2_Func,                  //任务函数(const char*    )"Task2_Func",                //任务名称(uint16_t       )TASK2_STACK_SIZE,            //任务堆栈大小(void*          )NULL,                        //传递给任务函数的参数(UBaseType_t    )TASK2_PRIO,                  //任务优先级(TaskHandle_t*  )&Task2_Handler);             //任务句柄//删除开始任务                  vTaskDelete(StartTask_Handler);//退出临界区                  taskEXIT_CRITICAL();            }uint8_t counter = 0;/*高优先级任务*/
void Task1_Func(void *p_arg)
{
//   OS_ERR  err;while (1){counter++;//Error            vTaskDelay(1000);}       
}/*低优先级任务*/
void Task2_Func(void *p_arg)
{while(1){     fwdgt_counter_reload();vTaskDelay(500);}
}3.编译与配置
至此主要文件添加完毕,可以编译工程,头文件路径添加完成以后编译一下,看看有没有什么错误,结果会发现提示打不开
 “FreeRTOSConfig.h”这个文件:
1.这是因为缺少 FreeRTOSConfig.h 文件,这个文件在哪里找呢?你可以自己创建,也可以找找 FreeRTOS 的官方移植工程中会不会有这个文件,打开FreeRTOS 针对 Cortex-M3 的移植工程文件复制一个FreeRTOSConfig.h 文件过来,针对gd32F103我做了如下修改,可以新建一个FreeRTOSConfig.h文件,然后直接复制粘贴以下内容。
/** FreeRTOS Kernel V10.2.1* Copyright (C) 2019 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.** http://www.FreeRTOS.org* http://aws.amazon.com/freertos** 1 tab == 4 spaces!*/#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H#include "systick.h"
//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)#include <stdint.h>#include <stdio.h>extern uint32_t SystemCoreClock;
#endif//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)/***************************************************************************************************************/
/*                                        FreeRTOS基础配置配置选项                                              */
/***************************************************************************************************************/
#define configUSE_PREEMPTION					         	1                       //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING					        	1						//1使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION				1                       //1启用特殊方法来选择下一个要运行的任务#define configUSE_TICKLESS_IDLE					            0                       //1启用低功耗tickless模式
#define configUSE_QUEUE_SETS					            1                       //为1时启用队列
#define configCPU_CLOCK_HZ						           (SystemCoreClock)        //CPU频率
#define configTICK_RATE_HZ						           (1000)                   //时钟节拍频率,这里设置为1000,周期就是1ms
#define configMAX_PRIORITIES					           (32)                     //可使用的最大优先级
#define configMINIMAL_STACK_SIZE				           ((unsigned short)130)    //空闲任务使用的堆栈大小
#define configMAX_TASK_NAME_LEN					           (16)                     //任务名字字符串长度#define configUSE_16_BIT_TICKS					            0                       //系统节拍计数器变量数据类型,//1表示为16位无符号整形,0表示为32位无符号整形
#define configIDLE_SHOULD_YIELD					            1                       //为1时空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configUSE_TASK_NOTIFICATIONS                        1                       //为1时开启任务通知功能,默认开启
#define configUSE_MUTEXES						            1                       //为1时使用互斥信号量
#define configQUEUE_REGISTRY_SIZE				            8                       //不为0时表示启用队列记录,具体的值是可以//记录的队列和信号量最大数目。
#define configCHECK_FOR_STACK_OVERFLOW			            0                       //大于0时启用堆栈溢出检测功能,如果使用此功能//用户必须提供一个栈溢出钩子函数,如果使用的话//此值可以为1或者2,因为有两种栈溢出检测方法。
#define configUSE_RECURSIVE_MUTEXES				            1                       //为1时使用递归互斥信号量
#define configUSE_MALLOC_FAILED_HOOK			            0                       //1使用内存申请失败钩子函数
#define configUSE_APPLICATION_TASK_TAG			            0                       
#define configUSE_COUNTING_SEMAPHORES			            1                       //为1时使用计数信号量/***************************************************************************************************************/
/*                                FreeRTOS与内存申请有关配置选项                                                */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION                    1                       //支持动态内存申请
#define configTOTAL_HEAP_SIZE					            ((size_t)(10*1024))     //系统所有总的堆大小/***************************************************************************************************************/
/*                                FreeRTOS与钩子函数有关的配置选项                                              */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK						            0                       //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK						            0                       //1,使用时间片钩子;0,不使用/***************************************************************************************************************/
/*                                FreeRTOS与运行时间和任务状态收集有关的配置选项                                 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS	                    0                       //为1时启用运行时间统计功能
#define configUSE_TRACE_FACILITY				            1                       //为1启用可视化跟踪调试
#define configUSE_STATS_FORMATTING_FUNCTIONS	            1                       //与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数/***************************************************************************************************************/
/*                                FreeRTOS与协程有关的配置选项                                                  */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES 			                    0                       //为1时启用协程,启用协程以后必须添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES                    (2)                      //协程的有效优先级数目/***************************************************************************************************************/
/*                                FreeRTOS与软件定时器有关的配置选项                                            */
/***************************************************************************************************************/
#define configUSE_TIMERS				                    1                               //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY		                    (configMAX_PRIORITIES-1)        //软件定时器优先级
#define configTIMER_QUEUE_LENGTH		                    5                               //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH	                    (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小/***************************************************************************************************************/
/*                                FreeRTOS可选函数配置选项                                                      */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState                      1                       
#define INCLUDE_vTaskPrioritySet		                    1
#define INCLUDE_uxTaskPriorityGet		                    1
#define INCLUDE_vTaskDelete				                    1
#define INCLUDE_vTaskCleanUpResources	                    1
#define INCLUDE_vTaskSuspend			                    1
#define INCLUDE_vTaskDelayUntil			                    1
#define INCLUDE_vTaskDelay				                    1
#define INCLUDE_eTaskGetState			                    1
#define INCLUDE_xTimerPendFunctionCall	                    1/***************************************************************************************************************/
/*                                FreeRTOS与中断有关的配置选项                                                  */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS#define configPRIO_BITS       		                    __NVIC_PRIO_BITS
#else#define configPRIO_BITS       		                    4                  
#endif#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			    15	                    //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	    5                       //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY 		            (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	            (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )/***************************************************************************************************************/
/*                                FreeRTOS与中断服务函数有关的配置选项                                          */
/***************************************************************************************************************/#define xPortPendSVHandler 	  PendSV_Handler
//#define xPortSysTickHandler 	SysTick_Handler
#define vPortSVCHandler 	    SVC_Handler#endif /* FREERTOS_CONFIG_H */
2.再编译一次,发现还是有错误:
 
这是因为 port.c 和 stm32f4xx_it.c 这两个文件中有重复定义的函数:PendSV_Handler()、SVC_Handler()和 Systick_Handler(),这里屏蔽掉 stm32f4xx_it.c 中的 PendSV_Handler()、SVC_Handler()两个函数。然后在stm32f4xx_it.c 添加如下代码:
#if SYSTEM_SUPPORT_OS#include "FreeRTOS.h"#include "task.h"//extern void xPortPendSVHandler( void );extern void xPortSysTickHandler( void );//extern void vPortSVCHandler( void );
#endif
再对void SysTick_Handler(void)做如下修改:
void SysTick_Handler(void){/*OS开始跑了,才执行正常的调度处理*/if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)//系统已经运行{xPortSysTickHandler();}      } 
再返回FreeRTOSConfig.h文件,拉到文件最底下做如下修改:
/***************************************************************************************************************/
/*                                FreeRTOS与中断服务函数有关的配置选项                                          */
/***************************************************************************************************************/#define xPortPendSVHandler 	  PendSV_Handler
//#define xPortSysTickHandler 	SysTick_Handler
#define vPortSVCHandler 	    SVC_Handler#endif /* FREERTOS_CONFIG_H */3.配置并启动滴答定时器,打开systick.c文件,对void systick_config(void)做以下修改,如果提示未定义则添加#include “FreeRTOS.h”
 #include "task.h"包含头文件
/*!\brief      configure systick\param[in]  none\param[out] none\retval     none
*/
void systick_config(void)
{/* setup systick timer for 1000Hz interrupts*/if (SysTick_Config(rcu_clock_freq_get(CK_SYS) / configTICK_RATE_HZ)){/* capture error */while (1){}}/* configure the systick handler priority */NVIC_SetPriority(SysTick_IRQn, 0x00U);
}至此编译完成,无错误显示
三、注意事项
1.宏configTICK_RATE_HZ,对OS系统时基进行配置,一般配置为1000,表示为系统以1ms为一个节拍作为系统时基
 2.需要使用相关功能,则打开对“FreeRTOSConfig.h”,打开相关宏