【GD32】FreeRTOS实时操作系统移植(GD32F470ZGT6)

2024-08-25 17:12

本文主要是介绍【GD32】FreeRTOS实时操作系统移植(GD32F470ZGT6),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 简介

        在日常的应用开发项目中,常常需要单片机具有处理多种任务的需求,如果使用裸机开发那么肯定是不现实的,因为受限于IO与处理器的巨大速度差异,在裸机下处理器常常要等待当前IO操作完成才能进行下一个任务,效率大打折扣。

        因此使用实时操作系统成为首选,市面上比较火的的实时操作系统有很多,像这里要介绍的FreeRTOS就是其中之一。FreeRTOS可以说是非常老牌的实时操作系统了,发布至今已经有十几年了,但受欢迎程度至今依然非常高,可以说是初学者必学的第一个RTOS系统。

        FreeRTOS目前是被亚马逊收购了,收购后主要的改变就是加入了亚马逊的AWS物联网框架,不过我们只需要移植内核就够了。更多的文档可以在FreeRTOS官网上找到。

2. 移植

        移植的FreeRTOS版本为FreeRTOS 202406.01 LTS

2.1 添加文件

        下载源码后解压,进入“FreeRTOS-Kernel”这个文件夹,里面就是内核源码,把它复制到项目的根目录下。

        之后在Keil中添加对应的文件。首先是导入源码根目录的所有.c文件;然后进入portable ->MemMang这个文件夹,里面存放的是一些内存管理相关的代码,每一个文件代表了一种内存管理方式,所以并不是全部都要导入,一般来说导入heap_4.c,这个文件代表使用硬件堆内存进行内存管理,如果你使用的是外部RAM,那么应该导入heap_5.c,它可以允许外部RAM分配。最后,如果你的使用AC5编译器,那么下一步要导入RVDS -> ARM_CM4F中的.c文件;如果你使用的是AC6编译器,那么导入GCC -> ARM_CM4F中的.c文件

        所有导入的文件如下所示。

        当然还要添加头文件路径,我使用的是AC6编译器,所以路径添加如下。

        FreeRTOS提供了丰富的选项给用户进行内核的裁切,在examples -> template_configuration下的FreeRTOSConfig.h文件中。里面的配置有大几百项,都有详细的说明,只不过是全英文的,所以下面给一个我使用的精简版带中文注释的配置文件。

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H#include "gd32f4xx.h"#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)#include <stdint.h>extern uint32_t SystemCoreClock;
#endif/* 断言 */
#include <stdio.h>
#define vAssertCalled(char, int)                    printf("Error:%s,%d\r\n", char, int)
#define configASSERT(x) if((x)==0)                  vAssertCalled(__FILE__, __LINE__)#define configUSE_PREEMPTION                        1/* 使用时间片调度 */
#define configUSE_TIME_SLICING                      1		
/* 优化的任务调度算法 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION	    1                       
/* 低功耗内核定时器 */
#define configUSE_TICKLESS_IDLE                     0   
/* 处理器时钟频率 */
#define configCPU_CLOCK_HZ                          (SystemCoreClock)
/* 每秒TICK数 */
#define configTICK_RATE_HZ                          (( TickType_t )1000)
/* 最大优先级数 */
#define configMAX_PRIORITIES                        (32)
/* 最小任务栈空间 */
#define configMINIMAL_STACK_SIZE                    ((unsigned short)128)
/* 最大任务名长度 */
#define configMAX_TASK_NAME_LEN                     (16)
/* 定时器宽度 */
#define configTICK_TYPE_WIDTH_IN_BITS               TICK_TYPE_WIDTH_32_BITS
/* 空闲任务让度 */
#define configIDLE_SHOULD_YIELD                     0
/* 使用任务队列 */
#define configUSE_QUEUE_SETS                        0    
/* 使用任务通知 */
#define configUSE_TASK_NOTIFICATIONS                1   
/* 使用互斥量 */
#define configUSE_MUTEXES						    0    
/* 使用递归互斥量 */
#define configUSE_RECURSIVE_MUTEXES                 0   
/* 使用计数信号量 */
#define configUSE_COUNTING_SEMAPHORES               0
/* 使用应用任务标签 */
#define configUSE_APPLICATION_TASK_TAG              0/* 使用动态任务创建 */
#define configSUPPORT_DYNAMIC_ALLOCATION            1    
/* 使用静态任务创建 */
#define configSUPPORT_STATIC_ALLOCATION             0					
/* 堆空间大小 */
#define configTOTAL_HEAP_SIZE                       ((size_t)(36*1024))    /* 使用空闲钩子 */
#define configUSE_IDLE_HOOK                         0      
/* 使用tick钩子 */
#define configUSE_TICK_HOOK                         0           
/* 使用内存空间分配失败钩子 */
#define configUSE_MALLOC_FAILED_HOOK                0 
/* 堆溢出检查 */
#define configCHECK_FOR_STACK_OVERFLOW              0   /* 创建运行状态 */
#define configGENERATE_RUN_TIME_STATS               0             
/* 使用跟踪功能 */
#define configUSE_TRACE_FACILITY                    0
/* 使用状态格式化函数 */
#define configUSE_STATS_FORMATTING_FUNCTIONS        0#if ( configUSE_TRACE_FACILITY == 1 )
#include "trcRecorder.h"
#endif/* 使用协程 */                                                                        
#define configUSE_CO_ROUTINES                       0                 
/* 协程任务优先级 */
#define configMAX_CO_ROUTINE_PRIORITIES             ( 2 )                   /* 使用定时器 */
#define configUSE_TIMERS				            0                              
/* 定时器任务优先级 */
#define configTIMER_TASK_PRIORITY                   (configMAX_PRIORITIES-1)        
/* 定时器队列长度 */
#define configTIMER_QUEUE_LENGTH                    10                               
/* 定时器任务栈空间 */
#define configTIMER_TASK_STACK_DEPTH                (configMINIMAL_STACK_SIZE*2)    /* 获取任务状态函数 */
#define INCLUDE_xTaskGetSchedulerState              1
#define INCLUDE_eTaskGetState                       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_xTimerPendFunctionCall              0
/* 获取当前任务句柄函数 */
#define INCLUDE_xTaskGetCurrentTaskHandle           1
/*  */
#define INCLUDE_uxTaskGetStackHighWaterMark         0
/* 获取空闲任务句柄 */
#define INCLUDE_xTaskGetIdleTaskHandle              0/* 任务优先级宽度 */
#ifdef __NVIC_PRIO_BITS#define configPRIO_BITS                         __NVIC_PRIO_BITS
#else#define configPRIO_BITS                         4                  
#endif
/* 内核优先级数 */
#define configKERNEL_INTERRUPT_PRIORITY             ( 15 << (8 - configPRIO_BITS) )	/* 240 */
/* 系统优先级数 */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY        ( 5 << (8 - configPRIO_BITS) )  /* 80 *//* 系统中断移植 */
#define xPortPendSVHandler                          PendSV_Handler
#define vPortSVCHandler                             SVC_Handler#endif /* FREERTOS_CONFIG_H */

2.2 代码移植

        导入文件后,还需要对原来的代码进行一些调整。

        首先,以前我们需要自己实现SysTick定时,但FreeRTOS内部已经帮我们实现了,所以SysTick的中断需改写成下面。

extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{	#if (INCLUDE_xTaskGetSchedulerState  == 1 )if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED){#endif  /* INCLUDE_xTaskGetSchedulerState */  xPortSysTickHandler();#if (INCLUDE_xTaskGetSchedulerState  == 1 )}#endif  /* INCLUDE_xTaskGetSchedulerState */
}

        另外,实时操作系统的运行是依靠PendSV和SVC这两个中断的,FreeRTOS内部有对应的代码实现,因此我们需要在之前的文件中注释掉这两个中断的实现。

        做完这些步骤以后,项目正常来说就能编译成功了。

2.3 测试例程

        简单写一个点灯例程测试FreeRTOS的运行。

static void led_init(void)
{rcu_periph_clock_enable(RCU_GPIOE);gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
}static void led_task(void* args)
{led_init();for(;;){gpio_bit_set(GPIOE, GPIO_PIN_3);printf("LED OFF\n");vTaskDelay(1000 / portTICK_PERIOD_MS);gpio_bit_reset(GPIOE, GPIO_PIN_3);printf("LED ON\n");vTaskDelay(1000 / portTICK_PERIOD_MS);}
}int main(void)
{	nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);DEBUG_Init();xTaskCreate(led_task, "InitTask", 1024, NULL, 5, NULL);vTaskStartScheduler();while(1);
}

        首先把中断组设成4位抢占位,这个非常重要,不然在调用含ISP结尾的API时可能会出问题。

        调xTaskCreate创建任务,第一个参数是任务函数指针;第二个参数是任务的名字;第三个参数是任务栈空间,如果任务的调用深度越深和里面定义的变量越多,那么这个就要对应的设大点,不然会导致栈溢出;第四个参数是用户数据指针,如果要传数据给任务就可以设置;第五个参数是任务的优先级,数字越大优先级越高,这个跟单片机的优先级逻辑是相反的;第六个参数是任务句柄,如果不需要获取任务的句柄那么可以传空指针。

        调vTaskStartScheduler启动任务调度。

        一般来说,在led_task任务函数里面,先初始化LED灯,然后在死循环里面每隔一秒改变一次灯的状态,使用vTaskDelay函数进行延时,里面的数要除portTICK_PERIOD_MS这个宏转成毫秒值

2.4 运行效果

        下载后应该能看到板子上的灯闪烁,串口打印如下。

这篇关于【GD32】FreeRTOS实时操作系统移植(GD32F470ZGT6)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106154

相关文章

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

FreeRTOS学习笔记(六)队列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、队列的基本内容1.1 队列的引入1.2 FreeRTOS 队列的功能与作用1.3 队列的结构体1.4 队列的使用流程 二、相关API详解2.1 xQueueCreate2.2 xQueueSend2.3 xQueueReceive2.4 xQueueSendFromISR2.5 xQueueRecei

FreeRTOS学习笔记(二)任务基础篇

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、 任务的基本内容1.1 任务的基本特点1.2 任务的状态1.3 任务控制块——任务的“身份证” 二、 任务的实现2.1 定义任务函数2.2 创建任务2.3 启动任务调度器2.4 任务的运行与切换2.4.1 利用延时函数2.4.2 利用中断 2.5 任务的通信与同步2.6 任务的删除2.7 任务的通知2

FreeRTOS学习笔记(四)Freertos的中断管理及临界保护

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、Cortex-M 中断管理1.1 中断优先级分组1.2 相关寄存器1.3 相关宏定义1.4 FreeRTOS 开关中断 二、临界段及其保护2.1 taskENTER_CRITICAL( ) 和 taskEXIT_CRITICAL( )2.2 taskENTER_CRITICAL_FROM_ISR( )

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

龙芯+FreeRTOS+LVGL实战笔记(新)——05部署主按钮

本专栏是笔者另一个专栏《龙芯+RT-Thread+LVGL实战笔记》的姊妹篇,主要的区别在于实时操作系统的不同,章节的安排和任务的推进保持一致,并对源码做了改进和优化,各位可以先到本人主页下去浏览另一专栏的博客列表(目前已撰写36篇,图1所示),再决定是否订阅。此外,也可以前往本人在B站的视频合集(图2所示)观看所有演示视频,合集首个视频链接为: 借助RT-Thread和LVGL

libmad音频解码库-Linux交叉编译移植

下载并解压libmad-0.15.1b.tar.gz 下载链接:https://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz $tar -xvf libmad-0.15.1b.tar.gz$cd libmad-0.15.1b 1、先执行下面的命令:这条命令是为了适配高版本的gcc,因为高版本的gcc已经将-fforce-mem去除了:

arm linux lua移植

lua: lua home 1.下载lua源码 lua下载 lua-5.3.4.tar.gz 2.解压: tar xvf lua-5.3.4.tar.gz 3.修改makefile and luaconf.h $修改 lua-5.3.4/Makefile #INSTALL_TOP= /usr/local INSTALL_TOP= $(shell pwd)/out #修改安装目录(当前目录/o

FreeRTOS学习笔记—④RTOS通信管理篇/同步互斥与通信(正在更新中)

二、RTOS的核心功能   RTOS的核心功能块主要分为任务管理、内核管理、时间管理以及通信管理4部分,框架图如下所示:   (1)任务管理:负责管理和调度任务的执行,确保系统中的任务能够按照预期运行。   (2)内核管理:负责系统核心功能的管理,包括内存、中断、异常处理和系统启动等。   (3)时间管理:负责所有与时间相关的操作,包括系统时钟、定时器、任务延迟和周期性任务的执行。   (4)通