打印
[研电赛技术支持]

FreeRTOS移植教程(超详细)——基于GD32F303X系列MCU

[复制链接]
67|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-1 16:30 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、准备
1. GD32 Keil工程
准备任意一个可以正常运行的GD32工程文件,这里使用的是自己建立的工程模板文件,一个点灯与HelloWorld工程:



2. FreeRTOS源码
首先下载最新的源码:
Download: FreeRTOS Kernel



我们会得到一个压缩文件,然后解压出来备用,现在准备好了一个GD32 Keil工程和一个FreeRTOS源码:



接下来我们开始移植。

二、FreeRTOS移植
1. 文件操作
对于移植使用来说,我们主要关注下面这几个FreeRTOS的关键文件,后面都会用到:



首先在GD32工程文件中,找到合适的地方,新建“FreeRTOS”文件夹,并新建三个子文件夹“inc”、“src”、“port”用于存放上述文件:



然后将“.\FreeRTOS\FreeRTOS-Kernel\include”目录下所有文件拷贝到新建的“./FreeRTOS/inc”文件夹下:



为了简洁,我们删除非.h文件:



然后把下面这几个C文件拷贝到src目录下:



然后将配置文件的模板文件拷贝到“/FreeRTOS”目录下:



在接口层,我们主要适配内存管理部分和IC硬件上的接口部分,这两个位于“.\FreeRTOS-Kernel\portable”下:



我们把整个“MemMang”目录直接复制到“port”目录下:



“MemMang”中是FreeRTOS提供的5个内存分配方案:



“RVDS”是为编译器提供编译环境所需要的相关文件,我们也把他们拷贝到目录下:



我们需要根据自己的MCU类型去选择,例如我们使用的GD32F303x系列是ARM架构、Cortex-M4的核、不带MPU的MCU,就仅保留"ARM_CM4F"的文件夹:



最终我们操作后的相关文件如下:



接下来我们就要在编译器中将上述文件加载进来

2. 工程操作
打开工程文件,新建工程资源文件夹“FreeRTOS/Src”和“FreeRTOS/Port”,然后把对应的C文件加载进来:



其中内存管理上我们选择“heap_4”:



C文件添加完成后把头文件的路径包含进来:



记得编译器使用V5:



接下来就是代码操作部分,完成最后的接口适配工作

3. 代码操作
首先调整堆栈大小,打开启动文件”startup_gd32f30x_hd.s“,我使用的GD32F303VET6,64K+512K,堆栈设置为0x2000,大家根据自己的项目需要和MCU能力自由分配:



首先先打开载入配置文件,可以在main.c文件中导入“FreeRTOS.h“,然后右键打开h文件:



然后就可以看到引用的“FreeRTOSConfig.h”文件,还是右键打开:



在“FreeRTOSConfig.h”文件中配置freeRTOS,官方模板文件中开启了很多的配置项,对于初学者,大部分我们并不太关心,由于新版本只有模板文件,我们可以直接从老版本中下载一个STM32的Demo配置文件,替换这个模板文件的内容:

/*
* FreeRTOS V202212.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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/

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

#define configUSE_PREEMPTION                1
#define configUSE_IDLE_HOOK                        0
#define configUSE_TICK_HOOK                        0
#define configCPU_CLOCK_HZ                        ( ( unsigned long ) 72000000 )       
#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

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

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY                 255
/* !!!! 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         191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY        15

#endif /* FREERTOS_CONFIG_H */



下图的文件就是上面的代码内容,大家可以直接复制上面的代码或者自行下载例如10.4版本的源码,在下述路径找到配置文件:





更新配置文件后,首先调整系统时钟,在”FreeRTOSConfig.h“文件中添加如下代码:

#if defined(__ICCARM__)||defined(__CC_ARM)||defined(__GNUC__)
        #include <stdint.h>
        extern uint32_t SystemCoreClock;
#endif


然后配置“configCPU_CLOCK_HZ”为“SystemCoreClock”

#define configCPU_CLOCK_HZ                        (SystemCoreClock) //( unsigned long ) 72000000



上面文件先不要关闭,我们打开“port.c”文件,主要是适配这三个接口函数:



我们在回到“FreeRTOSConfig.h”文件,在最后添加如下宏:

#define vPortSVCHandler                 SVC_Handler
#define xPortPendSVHandler         PendSV_Handler



还有一个xPortSysTickHandler函数用于更新系统时基,我们把它放在系统滴答里,打开“gd32f30_it.c”文件,首先添加头文件与函数声明:



滑到最后,注释掉原有的“SVC_Handler(){}和“PendSV_Handler(){}”函数,这两个已经被上面的宏定义替换了,然后在”SysTick_Handler“中添加

                #if (INCLUDE_xTaskGetSchedulerState  == 1 )
                        if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
                        {
                #endif   
                                xPortSysTickHandler();
                #if (INCLUDE_xTaskGetSchedulerState  == 1 )
                        }
                #endif  


编译运行0警告0错误

三、Hello FreeRTOS
1. 创建任务
任务相关使用需要包含头文件”task.h“,然后创建两个任务,一个LED灯任务一个打印任务:

//【LED任务】
//任务优先级
#define LED_TASK_PRIO                                (tskIDLE_PRIORITY + 1)
//任务堆栈大小       
#define LED_STK_SIZE                 50  
//任务句柄
TaskHandle_t LEDTask_Handler;
//任务函数
void LED_Task(void *pvParameters);

//【Debug任务】
//任务优先级
#define Debug_TASK_PRIO                (tskIDLE_PRIORITY + 2)
//任务堆栈大小       
#define Debug_STK_SIZE                 512  
//任务句柄
TaskHandle_t Debug_Task_Handler;
//任务函数
void Debug_Task(void *pvParameters);




然后定义一个任务创建函数:



/**********************************************************************************************************
* 函 数 名: RTOS_Init
* 功能说明: RTOS初始化,用于创建任务
* 形 参:无
* 返 回 值: 无
**********************************************************************************************************/
void RTOS_Init(void)
{
        taskENTER_CRITICAL();           //进入临界区
        //创建LED任务
        xTaskCreate((TaskFunction_t )LED_Task,            
                                                        (const char*    )"LED_task",          
                                                        (uint16_t       )LED_STK_SIZE,
                                                        (void*          )NULL,                               
                                                        (UBaseType_t    )LED_TASK_PRIO,       
                                                        (TaskHandle_t*  )&LEDTask_Handler);
                                       
        //创建Debug任务
        xTaskCreate((TaskFunction_t )Debug_Task,            
                                                        (const char*    )"Debug_task",          
                                                        (uint16_t       )Debug_STK_SIZE,
                                                        (void*          )NULL,                               
                                                        (UBaseType_t    )Debug_TASK_PRIO,       
                                                        (TaskHandle_t*  )&Debug_Task_Handler);
                                                       
        taskEXIT_CRITICAL();            //退出临界区       
        vTaskStartScheduler();          //开启任务调度
}





实现两个任务函数:

/**********************************************************************************************************
* 函 数 名: LED_Task
* 功能说明: LED任务
* 形          参: 无
* 返 回 值: 无
**********************************************************************************************************/
void LED_Task(void *pvParameters)
{
    while(1)
    {
      LED_BlinkOnOff();
      vTaskDelay(500);
    }
}
/**********************************************************************************************************
* 函 数 名: Debug_Task
* 功能说明: Debug任务
* 形          参: 无
* 返 回 值: 无
**********************************************************************************************************/
void Debug_Task(void *pvParameters)
{
    while(1)
    {
      printf("Hello FreeRTOS\r\n");
      vTaskDelay(500);
    }
}


在主函数中完成调用:

int main(void)
{
    /* configure systick */
    systick_config();
                System_Init();
                RTOS_Init();
}




2. 编译下载
编译下载即可看到串口打印信息以及LED周期闪烁:



最后附一张资源占用情况:



————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_43351158/article/details/143298282

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1867

主题

15482

帖子

11

粉丝