GD32F103*固件库移植FreeRTOS详细教程与解析

GD32F103*移植μCOS-Ⅲ详细教程与解析,欢迎指正



前言

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
#endif


extern 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”,打开相关宏


总结

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐