GD32F303 移植 FreeRTOS

示例工程代码库地址如下:

1. 准备工作

1.1 软件版本

类别 版本
FreeRTOS V10.4.3-LTS-Patch-2

1.2 源码下载

1.3 基础工程

3. FreeRTOS 移植

3.1 复制需要的内核文件

打开下载的 FreeRTOS 文件夹,复制内核源代码目录下的所有文件到工程目录下。
在这里插入图片描述
对 portable 目录下的文件进行删减,保留如下需要的目录:
在这里插入图片描述
其中

  • Keil 编译平台
  • MemMang 内存管理
  • RVDS 硬件相关(RealView Development Suite 开发套件)

由于 GD32F303 是 CM4F 内核,所以 RVDS 目录下保留如下目录:
在这里插入图片描述

3.2 添加文件到 Keil 工程

添加 FreeRTOS 内核源文件到工程
在这里插入图片描述
添加内核头文件引用路径,内核相关头文件存在多个目录下,需要添加多项。
在这里插入图片描述

3.3 添加 FreeRTOSConfig.h 内核配置文件

需要适配的主要参数如下:

参数 说明
configCPU_CLOCK_HZ 系统时钟频率,GD32F303 系统时钟频率为 120MHz,变量 SystemCoreClock 记录当前系统时钟频率,若修改系统时钟频率,此处不需要改动
configTICK_RATE_HZ 系统 tick 中断频率,用于同优先级任务的时间片处理速度
configMINIMAL_STACK_SIZE 最小任务栈空间,空闲任务使用该值来指定堆栈大小
configTOTAL_HEAP_SIZE 系统可用的 RAM 总量,根据 MCU RAM 资源进行调整

配置参数详细说明查看如下:

以下是博主配置好的 FreeRTOSConfig.h

/*
 * @Descripttion: 
 * @Author: Jerry
 * @Date: 2021-11-30 16:33:34
 * @LastEditTime: 2021-12-08 17:58:54
 * 
 * Copyright (C) 2021
 */
/*
 * FreeRTOS V202111.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.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */

#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
 *----------------------------------------------------------*/

/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined( __ICCARM__ ) || defined ( __CC_ARM ) || defined ( __GUNC__ )
	#include <stdint.h>
	extern uint32_t SystemCoreClock;
#endif
#include "stdio.h"
#include "log.h"

#define configUSE_PREEMPTION			1
#define configUSE_IDLE_HOOK				0
#define configUSE_TICK_HOOK				0
#define configCPU_CLOCK_HZ				( ( unsigned long ) SystemCoreClock )	
#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_FACILITY		0
#define configUSE_16_BIT_TICKS			0
#define configIDLE_SHOULD_YIELD			1
#define configCHECK_FOR_STACK_OVERFLOW 	1

/* 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 zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet			1
#define INCLUDE_uxTaskPriorityGet			1
#define INCLUDE_vTaskDelete					1
#define INCLUDE_vTaskCleanUpResources		0
#define INCLUDE_vTaskSuspend				1
#define INCLUDE_vTaskDelayUntil				1
#define INCLUDE_vTaskDelay					1
#define INCLUDE_xTaskGetCurrentTaskHandle	1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetSchedulerState		1

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
	/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4        /* 15 priority levels */
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! 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 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
	
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); OLOGF("<!!!OS Assert!!!> func = %s, line=%d\n", __func__, __LINE__); for( ;; ); }	
	
#endif /* FREERTOS_CONFIG_H */

3.4 配置任务调度相关的中断处理函数

配置三个中断处理函数句柄即可,即:

  • vPortSVCHandler
  • xPortPendSVHandler
  • xPortSysTickHandler

以上中断处理函数已经在 port.c 文件中实现,只要发生对应中断调用即可。

GD32F30x 相关中断处理源文件为:gd32f30x_it.c

gd32f30x_it.c 示例代码如下:

/*!
    \file  gd32f30x_it.c
    \brief interrupt service routines
*/

/*
    Copyright (C) 2017 GigaDevice

    2017-05-19, V1.0.0, demo for GD32F30x
*/

#include "gd32f30x_it.h"
#include "systick.h"

#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"

extern void xPortPendSVHandler( void );
extern void xPortSysTickHandler( void );
extern void vPortSVCHandler( void );

/*!
    \brief      this function handles NMI exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void NMI_Handler(void)
{
    OLOGF("%s\n", __func__);
}

/*!
    \brief      this function handles HardFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void HardFault_Handler(void)
{
    /* if Hard Fault exception occurs, go to infinite loop */
    OLOGF("%s\n", __func__);
    while (1);
}

/*!
    \brief      this function handles MemManage exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void MemManage_Handler(void)
{
    OLOGF("%s\n", __func__);
    /* if Memory Manage exception occurs, go to infinite loop */
    while (1);
}

/*!
    \brief      this function handles BusFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void BusFault_Handler(void)
{
    OLOGF("%s\n", __func__);
    /* if Bus Fault exception occurs, go to infinite loop */
    while (1);
}

/*!
    \brief      this function handles UsageFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void UsageFault_Handler(void)
{
    OLOGF("%s\n", __func__);
    /* if Usage Fault exception occurs, go to infinite loop */
    while (1);
}

/*!
    \brief      this function handles SVC exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SVC_Handler(void)
{
    vPortSVCHandler();
}

/*!
    \brief      this function handles DebugMon exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DebugMon_Handler(void)
{
}

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void PendSV_Handler(void)
{
    xPortPendSVHandler();
}

/*!
    \brief      this function handles SysTick exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
    xPortSysTickHandler();

    delay_decrement();
}

3.5 Main 函数实现

移植了 FreeRTOS,main 函数就需要初始化系统,以及调用任务调度函数,其他复杂工作都交给每一个创建的任务去处理即可。

main.c

/*
 * @Descripttion: main
 * @Author: Jerry
 * @Date: 2021-11-30 14:08:10
 * @LastEditTime: 2021-12-31 17:06:39
 * 
 * Copyright © 2021 Jerry, All Rights Reserved
 */
#include "gd32f30x.h"
#include "gd32f303e_eval.h"
#include "delay.h"
#include "osal.h"
#include "system.h"
#include "uart_printf.h"

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{  
    delay_init();
    uart_printf_init();

    OS_Init();
    system_init();
    OS_StartScheduler();
    while(1) { OLOGI("!"); }//OS_StartScheduler 调用失败将返回,添加死循环更容易排查问题
}

4. 系统抽象层 OSAL

博主封装了一层 OSAL 系统抽象层,对 FreeRTOS 相关 API 进行了再封装,方便日后切换 RTOS,可减少代码修改量,应用层代码不需要进行接口修改,或者只需要少量修改即可完成 RTOS 切换工作。

osal.h

/*
 * @Descripttion: operating system abstract layer
 * @Author: Jerry
 * @Date: 2021-12-01 15:06:50
 * @LastEditTime: 2021-12-07 17:27:27
 * 
 * Copyright (C) 2021
 */
#ifndef _OSAL_H_
#define _OSAL_H_

#include "types.h"
#include "FreeRTOS.h"
#include "task.h"

typedef void *OsTaskHandle;
typedef void (*OsTask)(void *);
typedef TickType_t OS_TICKTYPE;

#if                         1
    #define OS_TASK_PRIO0   0
    #define OS_TASK_PRIO1   1
    #define OS_TASK_PRIO2   2
    #define OS_TASK_PRIO3   3
    #define OS_TASK_PRIO4   4
#endif

#define OS_TASK_MIN_STACK_SIZE      configMINIMAL_STACK_SIZE
#define OS_MAX_WAITTIME             portMAX_DELAY
#define OS_MS_TO_TICKS(xTimeInMs)   pdMS_TO_TICKS(xTimeInMs) 

/**
 * init os, must be called at begin of main
 */
void OS_Init(void);


/**
 * @brief get os version
 * @retval version string 
 */
const char* OS_GetVersion(void);

/**
 * create task
 *
 * @param   task                    	task function
 * @param   name                    	task name
 * @param   stackSize                   task stack size in WORDS (ex: task stack size 512 bytes = 128 WORDS)
 * @param   param                       task parameter
 * @param   pri                       	task priority, (min:OS_TASK_PRIO0, max:OS_TASK_PRIO3)
 * @param   taskHandle                  task handle
 *
 * @retval  0                       	task create failed
 * @retval  1                         	task create success
 */
u8 OS_TaskCreate(OsTask task, const char *name, u16 stackSize, void *param, u32 pri, OsTaskHandle *taskHandle);

/**
 * @brief get task prioirity
 * @param taskHandle    task handle
 * @retval: priority
 */
u32 OS_TaskGetPriority(OsTaskHandle taskHandle);

/**
 * @brief set task priority
 * @param taskHandle    task handle
 * @param prio          task priority
 */
void OS_TaskSetPriority(OsTaskHandle taskHandle, u32 prio);

/**
 * delete task
 *
 * @param   taskHandle                    	NULL: delete current task
 */
void OS_TaskDelete( OsTaskHandle taskHandle );

/**
 * get task's name
 *
 * @retval task's name
 */
const char * OS_TaskGetName(OsTaskHandle taskHandle);

/**
 * get task's free stack space
 *
 * @retval task free stack size in WORDS (ex: task stack size 512 bytes = 128 WORDS)
 */
u32 OS_TaskGetFreeStackSpace(OsTaskHandle taskHandle);

/**
 * start scheduler, must be called at end of main
 */
void OS_StartScheduler(void);

/**
 * delay ms
 *
 * @param   ms                    		ms count
 */
void OS_MsDelay(u32 ms);

/**
 * delay tick
 *
 * @param   ticks                    	tick count
 */
void OS_TickDelay(OS_TICKTYPE ticks);

/**
 * specifies the absolute (exact) time at which it wishes to unblock.
 *
 * @param pxPreviousWakeTime    previous wake time
 * @param ticks                 tick count
 */
void OS_TickDelayUntil(OS_TICKTYPE * const pxPreviousWakeTime, const OS_TICKTYPE ticks);

/**
 * @brief get current system tick count
 * @retval current tick count
 */
OS_TICKTYPE OS_GetTickCount(void);

/**
 * @brief OS application stack overflow hook
 * @param xTask         [in] task handle
 * @param pcTaskName    [in] task's name
 */
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName);

#define OS_EnterCritical()  vPortEnterCritical()
#define OS_ExitCritical()   vPortExitCritical()

#endif

osal.c

/*
 * @Descripttion: operating system abstract layer
 * @Author: Jerry
 * @Date: 2021-12-01 15:06:50
 * @LastEditTime: 2021-12-07 17:35:49
 * 
 * Copyright (C) 2021
 */
#include "types.h"
#include "osal.h"
#include "task.h"
#include "gd32f30x_misc.h"
#include "log.h"

/**
 * init os, must be called at begin of main
 */
void OS_Init(void)
{
    OLOGI("OS Version: %s\n", OS_GetVersion());
    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
}

/**
 * @brief get os version
 * @retval version string 
 */
const char* OS_GetVersion(void)
{
    return tskKERNEL_VERSION_NUMBER;
}

/**
 * create task
 *
 * @param   task                    	task function
 * @param   name                    	task name
 * @param   stackSize                   task stack size in WORDS (ex: task stack size 512 bytes = 128 WORDS)
 * @param   param                       task parameter
 * @param   pri                       	task priority, (min:OS_TASK_PRIO0, max:OS_TASK_PRIO3)
 * @param   taskHandle                  task handle
 *
 * @retval  0                       	task create failed
 * @retval  1                         	task create success
 */
u8 OS_TaskCreate(OsTask task, const char *name, u16 stackSize, void *param, u32 pri, OsTaskHandle *taskHandle)
{
    if(pdPASS == xTaskCreate(task, name, stackSize, param, pri, (TaskHandle_t *)taskHandle)) return 1;
    else return 0;
}

/**
 * @brief get task prioirity
 * @param taskHandle    task handle
 * @retval: priority
 */
u32 OS_TaskGetPriority(OsTaskHandle taskHandle)
{
    return uxTaskPriorityGet(taskHandle);
}

/**
 * @brief set task priority
 * @param taskHandle    task handle
 * @param prio          task priority
 */
void OS_TaskSetPriority(OsTaskHandle taskHandle, u32 prio)
{
    vTaskPrioritySet(taskHandle, prio);
}

/**
 * delete task
 *
 * @param   taskHandle                    	NULL: delete current task
 */
void OS_TaskDelete(OsTaskHandle taskHandle)
{
    vTaskDelete(taskHandle);
}

/**
 * get task's name
 *
 * @retval task's name string
 */
const char * OS_TaskGetName(OsTaskHandle taskHandle)
{
    return pcTaskGetTaskName(taskHandle);
}

/**
 * get task's free stack space
 *
 * @retval task free stack size in WORDS (ex: task stack size 512 bytes = 128 WORDS)
 */
u32 OS_TaskGetFreeStackSpace(OsTaskHandle taskHandle)
{
    return uxTaskGetStackHighWaterMark(taskHandle);
}

/**
 * start scheduler, must be called at end of main
 */
void OS_StartScheduler(void)
{
    vTaskStartScheduler();
}

/* Delay: */
/**
 * delay ms
 *
 * @param   ms                    		ms count
 */
void OS_MsDelay(u32 ms)
{
    const TickType_t xDelay = ms / portTICK_PERIOD_MS;
    vTaskDelay(xDelay);
}

/**
 * delay tick
 *
 * @param   ticks                    	tick count
 */
void OS_TickDelay(OS_TICKTYPE ticks)
{
    vTaskDelay(ticks);
}

/**
 * specifies the absolute (exact) time at which it wishes to unblock.
 *
 * @param pxPreviousWakeTime    previous wake time
 * @param ticks                 tick count
 */
void OS_TickDelayUntil(OS_TICKTYPE * const pxPreviousWakeTime, const OS_TICKTYPE ticks)
{
    vTaskDelayUntil(pxPreviousWakeTime, ticks);
}

/**
 * @brief get current system tick count
 * @retval current tick count
 */
OS_TICKTYPE OS_GetTickCount(void)
{
    return xTaskGetTickCount();
}

/**
 * @brief OS application stack overflow hook
 * @param xTask         [in] task handle
 * @param pcTaskName    [in] task's name
 */
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName )
{
    OLOGF("<!!!OS stack overflow!!!> task: %s\n", pcTaskName);
}

5. FreeRTOS 使用

实现定时 1s 输出任务相关属性值,包括任务名、堆栈剩余空间、任务优先级等;

test_task.c

/*
 * @Descripttion: test task
 * @Author: Jerry
 * @Date: 2022-01-04 15:12:40
 * @LastEditTime: 2022-01-05 11:02:11
 * 
 * Copyright © 2021 Jerry, All Rights Reserved
 */
#include "stdio.h"
#include "osal.h"
#include "systick.h"
#include "gd32f303e_eval.h"

/*******************************************************************/
/***       			    Local Function                           ***/
/*******************************************************************/
static void test_task(void *para)
{
    while(1)
    {
        LOGD("task: %s, freestack: %d, proi: %d\n", OS_TaskGetName(NULL), OS_TaskGetFreeStackSpace(NULL), OS_TaskGetPriority(NULL));

        OS_MsDelay(1000);
    }
}

/******************************************************************/
/***                    Exported Functions                      ***/
/******************************************************************/
/**
 * @brief init test task.
 */
void test_task_init(void)
{
    OS_TaskCreate(test_task, "test_task", 256, NULL, OS_TASK_PRIO1, NULL);
}

编译下载运行到开发板,串口输出如下内容:
在这里插入图片描述

6. 总结

至此,FreeRTOS 的移植工作就完成了,可以添加任务实现自己的功能了。

但博主在测试过程中,发现裸机使用浮点型运算一切正常,移植 FreeRTOS 之后,创建任务,在任务体中使用浮点型运算,立马会报出 HardFault 异常,整个系统崩溃了…

预知后事如何,且听下回分解!请点击查看

版权声明:本文为CSDN博主「Jerry.yl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/QQ1452008/article/details/119147620

生成海报
点赞 0

Jerry.yl

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

GD32F303 移植 FreeRTOS

示例工程代码库地址如下: GiteeGit 1. 准备工作 1.1 软件版本 类别版本FreeRTOSV10.4.3-LTS-Patch-2 1.2 源码下载 FreeRTOS 下载链接 1.3 基础工程 GD32F

freertos临界段保护

中断的基础知识 嵌套: 嵌套向量中断控制器 NVIC(Nested Vectored Interrupt Controller与内核是紧耦合的。提供如下的功能:可嵌套中断支持、向量中断支持、动态优先级调整支持、中