文章目录[隐藏]
示例工程代码库地址如下:
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
暂无评论