FreeRTOS GD32单片机移植流程详述

FreeRTOS移植

准备工作

基础工程

移植之前需要先准备一个 基本的可用的 GD32工程模板,用于后续的移植,如下所示:

一个可用的工程模板

该工程为通过串口 每隔 100ms 输出一个 Running 的工程模板

下载 FreeRTOS源码

FreeRTOS下载途径有很多, 可以通过 FreeRTOS官网Github 下载到 FreeRTOS 内核源码,其目录结构如下:

.
|-- CMakeLists.txt
|-- GitHub-FreeRTOS-Kernel-Home.url
|-- History.txt
|-- LICENSE.md
|-- MISRA.md
|-- Quick_Start_Guide.url
|-- README.md
|-- croutine.c
|-- cspell.config.yaml
|-- event_groups.c
|-- include
|-- list.c
|-- manifest.yml
|-- portable
|-- queue.c
|-- sample_configuration
|-- stream_buffer.c
|-- tasks.c
`-- timers.c

其中,后续工程需要移植的主要包括:

  • *.c 文件: FreeRTOS 的内核源文件
  • include 目录: 包含 FreeRTOS 源码相关头文件
  • portable 目录: 包含 FreeRTOS 的一些组件和不同架构 CPU 的支持

另外还需要下载 Demo(Github可以下载到), 通过 Demo 目录中的内容来辅助移植

开始移植

添加代码

首先在工程中新建两个文件夹, 我这里分别命名为

  • FreeRTOS: 包括 FreeRTOS 内核的源码
  • FreeRTOS_Port: 包括 FreeRTOS 与 GD32 工程相关的接口文件

如下所示:

添加FreeRTOS Group
随后在 模板工程所在目录下添加一个名为 ThirdParty 的目录, 用于存放第三方源码, 如下所示:

添加 ThirdParty 放置 FreeRTOS源码
将 FreeRTOS 中的源文件添加到工程中的 FreeRTOS 中, 如下所示:

添加源码
另外还要添加 portable 目录下 接口 相关的文件, 先浏览 keil 目录, 发现只有个文件名为 See-also-the-RVDS-directory

那就跳转到 RVDS 目录下, 可以看到 FreeRTOS 不同 ARM 内核架构的支持,我移植的板子主控芯片为 GD32F103VCT6,属于 Cortex-M3 内核

添加Cortex-M3内核相关文件
因此将该目录下的 port.cportmacro.h 添加进工程中,我将其添加到了 FreeRTOS_Port 中, 此时还需要添加一个 FreeRTOS 内存管理 用到的源文件, 在 protable/MemMang 目录下,我选择添加 heap4.c,其中各个文件的具体区别可自行搜索, 代码添加完成后如下所示:

代码添加完成
添加完成后需要将 FreeRTOS 源码目录下的 include 目录添加进编译配置中,如下所示:

添加头文件目录

我使用的主控芯片前面提到过是 GD32F103VCT6, 系统时钟默认配置为 108MHz, 因此将该数值更改为 108000000

此时再执行编译, 发现可以编译通过, 无报错无警告 😃

测试

添加简单的线程测试, 我这里选用了两个简单的测试线程, 分别为

  • LED 闪烁线程
  • 串口 LOG 打印线程

实现如下:

// LED 线程
#include "gd32f10x_rcu.h"
#include "gd32f10x_gpio.h"

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

#include "freertos_task_led.h"

void freertos_task_led(void *args)
{
	/* 初始化 LED */
	rcu_periph_clock_enable(RCU_GPIOE);
	gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
	for(;;) {
		gpio_bit_set(GPIOE, GPIO_PIN_2);
		vTaskDelay(500);
		gpio_bit_reset(GPIOE, GPIO_PIN_2);
		vTaskDelay(500);
	}
}

每隔半秒翻转一次LED的状态

#include "gd32f10x_rcu.h"
#include "gd32f10x_gpio.h"

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

#include "generic_log.h"

#include "freertos_task_log.h"

void freertos_task_log(void *args)
{
	/* 初始化 LED */
	rcu_periph_clock_enable(RCU_GPIOE);
	gpio_init(GPIOE, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
	
	for(;;) {
		LOG("Task LOG Running");
		vTaskDelay(1000);
	}
}

每隔 1s 通过串口发送一个 Task LOG Running 的字符串, 创建任务函数如下:


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

#include "freertos_task_led.h"
#include "freertos_task_log.h"

#include "freertos_task.h"

TaskHandle_t freertos_task_led_handle;
TaskHandle_t freertos_task_log_handle;

void freertos_task_init(void)
{
	xTaskCreate(freertos_task_led, "task_led", 64, NULL, 5, &freertos_task_led_handle);
	xTaskCreate(freertos_task_log, "task_log", 64, NULL, 5, &freertos_task_log_handle);
	
	vTaskStartScheduler();
}

创建了两个任务, 并开启 RTOS 调度, 此时编译可正常通过, 再 main 函数调用 freertos_task_init, 如下所示:

添加进程代码

编译无报错,无警报,烧录进入板子后可以发现串口没有打印,该闪烁的 LED 也没有一点动静, 这是因为还没有将主控的 Tick 与 RTOS 的调度器对接, 这里需要更改 启动文件 startup_gd32f10x_hd.s, 将中断向量表中的以下三个处理函数更改为 FreeRTOS 中的处理函数, 如下所示:

原函数名更改之后的函数名
SVC_HandlervPortSVCHandler
PendSV_HandlerxPortPendSVHandler
SysTick_HandlerxPortSysTickHandler

这三个函数出自前面移植时添加的源文件 port.c 中, 在该源文件中有所定义

此时再编译, 无错误无警报, 烧录后 串口打印, LED也在正常闪烁, FreeRTOS 移植成功

参考文章

在这里感谢以上伙伴的文章分享!

工程链接

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值