1、GD32 使用MDK移植RT_Thread Nano版本

在这里插入图片描述
本文参考 RT

一、准备工作


1.1 准备一个GD32F30x系列的开发板


1.2 获取 GD32F30x 固件库

  • 兆易创新官网下载GD32F30x 标准固件库(如 GD32F30x_Firmware_Library_V3.0.1)

在这里插入图片描述


1.3 安装 RT-Thread Nano Pack

RT-Thread Nano 已集成在 Keil MDK 中,支持两种安装方式:
方法一:Keil IDE 内安装

  1. 打开 Keil MDK,点击工具栏Pack Installer
  2. 在左侧导航栏展开 Generic→RealThread::RT-Thread
  3. 在右侧 Action 栏点击 Install,选择最新版本(如 3.1.5)完成安装
    在这里插入图片描述

方法二:手动安装

  1. 从RT-Thread 官网下载 Nano 离线安装包
  2. 双击安装包,按提示完成安装

二、创建基础裸机工程


2.1 工程结构搭建

  1. 在本地新建文件夹(如GD32F30x_RT_Nano),并创建以下子目录

    • Application:存放主程序(main.c)
  2. 解压GD32F30x_Firmware_Library固件库

    • 将GD32F30x_Basic_Project目录下的文件,全部复制到工程文件夹中
      在这里插入图片描述
    • 将D:\GD32F30x_RT_Nano\MDK_ARM\Keil5_project内的Project工程打开,得到一个基础工程
      在这里插入图片描述

三、移植RT_Thread Nano

有两种办法将RT_Thread Nano的源码添加到工程
方法一、使用MDK中的Manage Run-Time Environment工具进行添加
在这里插入图片描述
点击OK后,工程如下
在这里插入图片描述

1. kernel(内核核心)

核心功能

  • 提供 RTOS 最基础的任务管理能力,是 RT-Thread 运行的“心脏”。
    • 实现多任务调度:支持线程(任务)创建、删除、优先级抢占、时间片轮转,让程序能“并行”执行多个逻辑(如同时处理传感器采集 + 串口通信 + LED 控制)。
    • 处理时钟节拍(Tick):通过 SysTick 等定时器维护系统心跳,驱动任务延时、超时判断(比如 rt_thread_mdelay() 依赖 Tick 推进)。
    • 管理线程上下文:用汇编 + C 代码实现任务切换时的寄存器保存/恢复(如 Cortex-M 架构的 PendSV_Handler 接管),保证任务切换无缝衔接。
  • 包含基础同步/通信机制:信号量(rt_sem_take/release)、互斥锁(rt_mutex)、消息队列(rt_mq)等,解决多任务间的数据共享、竞争问题。

2. shell(命令行交互)

核心功能

  • 为系统提供命令行调试/控制接口,让开发者能在运行时通过串口、调试终端等输入指令,实时操作系统、查询状态。
    • 支持自定义命令:你可以注册自己的函数为命令(如 led_on sensor_read),输入指令就能直接调用函数,快速调试功能。
    • 实现参数解析:自动处理命令行输入的参数(如 sensor_read 10,可解析出“读取 10 次传感器”的逻辑)。
    • 基础系统命令:默认可能包含 list_thread(查看线程状态)、list_sem(查看信号量)、version(查询 RT-Thread 版本)等,方便快速排查问题(比如线程是否卡死、资源是否耗尽)。

3. device(设备框架,RT-Thread 特色)

核心功能

  • 为硬件外设提供统一抽象层,让驱动开发、应用调用更简洁、标准化。
    • 实现设备注册与管理:把 UART、ADC、PWM 等外设“注册”为统一的“设备对象”,用 rt_device_open rt_device_read rt_device_write 等通用接口操作(比如不管是 GD32 的串口还是 STM32 的串口,都能用 rt_device_write 发数据)。
    • 支持设备驱动分层:底层做硬件寄存器操作(如 GD32 串口初始化、中断收发),上层通过设备框架对外提供通用 API,解耦硬件差异。
    • 适配多种设备类型:字符设备(串口、ADC)、块设备(虚拟文件系统存储)、网络设备(以太网、WiFi 适配)等,让应用层能以统一方式访问不同硬件。

方法二、手动添加源码
该方法较为繁琐,但是可以将源码放入工程文件夹中,方便在其他电脑上运行
1、在工程的Firmware文件夹下创建一个文件夹如RT_Thread_Nano
在这里插入图片描述
2、从Keil 5的安装位置找到RT_Thread的源码,如E:\Keil_v5\ARM\PACK\RealThread\RT-Thread,可以右键点击Keil5的图标打开文件所在位置,将RT-Thread文件夹下的3.1.5文件夹复制到RT_Thread_Nano中,并将3.1.5中的只读属性去掉。
在这里插入图片描述
3、在Manage Project Items 中新增一个Groups,如RT_Thread_Nano
在这里插入图片描述
4、添加源码,可以参考方法一的文件进行添加
分别在这些位置,

  1. D:\GD32F30x_RT_Nano\Firmware\RT_Thread_Nano\3.1.5\bsp_template
  2. D:\GD32F30x_RT_Nano\Firmware\RT_Thread_Nano\3.1.5\src
  3. D:\GD32F30x_RT_Nano\Firmware\RT_Thread_Nano\3.1.5\libcpu\arm\cortex-m3(这个需要根据你的芯片架构进行更改)
    在这里插入图片描述
    5、添加路径
    在这里插入图片描述

四、修改源码文件

1. board.c

  1. 需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置 (为操作系统提供心跳 / 节拍)
  2. 如果需要RT_USING_CONSOLE,即rt_kprintf串口信息打印,还需要实现static int uart_init(void)以及void rt_hw_console_output(const char *str),该功能在rtconfig.h上开启或关闭
    在这里插入图片描述3. 系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。
    开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用,如下所示
    在这里插入图片描述
/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-05-24                  the first version
 */

#include <rthw.h>
#include <rtthread.h>
#include "gd32f30x.h"
#include "systick.h"
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
/*
 * Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP
 * the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes
 */
#define RT_HEAP_SIZE (2*1024)
static rt_uint8_t rt_heap[RT_HEAP_SIZE];

RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif

void rt_os_tick_callback(void)
{
    rt_interrupt_enter();
    
    rt_tick_increase();

    rt_interrupt_leave();
}

/* cortex-m 架构使用 SysTick_Handler() */
void SysTick_Handler()
{
    rt_os_tick_callback();
}

/**
 * This function will initial your board.
 */
void rt_hw_board_init(void)
{
    /* 使能滴答定时器作为RT-Thread系统时钟 */
    SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

#ifdef RT_USING_CONSOLE
#include "gd32f30x_usart.h"
#ifdef RT_USING_CONSOLE

/* 初始化USART2 */
static int uart_init(void)
{
    /* 使能GPIO和UART时钟 */
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_USART2);
    
    /* 配置USART2 Tx (PB10)为复用推挽输出 */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    /* 配置USRT2 Rx (PB11)为浮空输入 */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
    
    /* 配置USART2参数 */
    usart_deinit(USART2);
    usart_baudrate_set(USART2, 115200U);
    usart_word_length_set(USART2, USART_WL_8BIT);
    usart_stop_bit_set(USART2, USART_STB_1BIT);
    usart_parity_config(USART2, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART2, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART2, USART_CTS_DISABLE);
    usart_receive_config(USART2, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);
    
    /* 使能USART2 */
    usart_enable(USART2);
    
    return 0;
}
INIT_BOARD_EXPORT(uart_init);

/* 控制台输出函数 */
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0;
//    rt_base_t level;
    
 //   level = rt_hw_interrupt_disable();
    
    while (str[i] != '\0')
    {
        if (str[i] == '\n')
        {
					  usart_data_transmit(USART2, (uint8_t)'\r');
            while (RESET == usart_flag_get(USART2, USART_FLAG_TBE));
            
        }
        usart_data_transmit(USART2, (uint8_t)str[i]);
        while (RESET == usart_flag_get(USART2, USART_FLAG_TBE));       
        i++;
    }
    
    while (RESET == usart_flag_get(USART2, USART_FLAG_TC));
    
 //   rt_hw_interrupt_enable(level);
}
#endif /* RT_USING_CONSOLE */

#endif




2、gd32f30x_it.c

  1. 将几个中断服务函数增加 __weak 弱定义,有的编译器可能不支持,可以替换为RT_WEAK
  2. HardFault_Handler、PendSV_Handler、SysTick_Handler这些函数都被RT_Thread接管了,所以要么删除要么弱定义,
/*!
    \file    gd32f30x_it.c
    \brief   interrupt service routines

   \version 2024-12-20, V3.0.1, firmware for GD32F30x
*/

/*
    Copyright (c) 2024, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

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

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

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

/*!
    \brief      this function handles MemManage exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void MemManage_Handler(void)
{
    /* 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)
{
    /* 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)
{
    /* 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)
{
}

/*!
    \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
*/
__weak  void PendSV_Handler(void)
{
}

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

3、main.c

在components.c文件中,完成了RT-Thread 操作系统的核心启动与初始化组件,负责系统组件按序初始化、创建并启动 main 线程,以及适配不同编译器完成系统启动流程

  1. 当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。
#include "gd32f30x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include <rtthread.h>
// 初始化 PC13 引脚
void pc13_led_init(void)
{
    /* 使能 GPIOC 时钟 */
    rcu_periph_clock_enable(RCU_GPIOC);

    /* 配置 PC13 为推挽输出模式 */
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
}

int main(void)
{
	//时钟源配置 在启动文件中完成
	 pc13_led_init();
	while (1)
	{
        // 点亮 LED
        gpio_bit_reset(GPIOC, GPIO_PIN_13);
        // 延时一段时间
        rt_thread_mdelay(100);

        // 熄灭 LED
        gpio_bit_set(GPIOC, GPIO_PIN_13);
        // 延时一段时间
        rt_thread_mdelay(100);
	}
}

至此,移植工作结束,编译通过后即可烧录运行查看是否正常。

五、工程可能出现的问题

1、rt_thread_mdelay的延时不正常

  1. 检查启动文件是否选择正确
    在这里插入图片描述
    2.检查晶振选择是否正确,在system_gd32f30x.c中
    .在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值