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