目录

RT-Thread 简介

移植前准备

标准库移植

文件裁剪

BSP

components

libcpu

其他

工程移植

内核文件

cpu移植层

设备驱动框架

libc 适配层

添加.h文件地址

应用层编写

应用层测试

驱动层添加

结语

RT-Thread 简介

RT-Thread 是一款由中国开发者主导的开源实时操作系统(RTOS),具有高可定制性、微内核架构和丰富的组件支持。它适用于嵌入式系统,广泛应用于物联网设备、智能硬件、工业控制、汽车电子等领域。

移植前准备

我们先准备一个干净的工程,做到能跑流水灯即可,本文示例展示移植rt-thread 是基于GD32F4系列芯片移植。

标准库移植

文件裁剪

下面这个是github上地址,上面拉最新版本的rt-thread

Releases · RT-Thread/rt-threadhttps://github.com/RT-Thread/rt-thread/releases

解压完之后发现有一点多个G,里面大部分文件我们是不要的,需要进行裁剪

下面介绍一下这些文件都是什么

目录/文件类型作用移植时是否需
src/目录内核源码需要
include/目录内核头文件需要
libcpu/目录CPU 移植层需要
components/目录组件层:设备框架(drivers/)、FinSH、libc 适配、网络、文件系统等按需
bsp/目录板级支持包,按芯片厂商分目录参考/按需
Kconfig文件menuconfig 的总配置入口,定义有哪些配置项可选可选(用 menuconfig 时需要)
tools/目录构建、配置、脚本工具可选
examples/目录官方示例代码,学习用,不参与编译不需要
documentation/目录官方文档源码不需要
.devcontainer/目录VS Code 远程开发容器配置不需要
.gitee/目录Gitee 平台的 issue 模板、CI 配置不需要
.github/目录GitHub 平台的 issue 模板、CI 配置不需要
.hooks/目录Git 钩子脚本不需要
.vscode/目录VS Code 工程配置(调试、任务等)不需要
.clang-format文件代码格式化规则不需要
.gitattributes文件Git 文件属性规则不需要
.gitignore文件Git 忽略规则不需要
AGENTS.md文件给 AI 编码助手看的说明文件不需要
ChangeLog.md文件版本变更日志不需要
LICENSE文件开源许可证(Apache-2.0)不需要
MAINTAINERS文件各模块维护者名单不需要
README.md文件项目说明(英文)不需要
README_de.md文件项目说明(德文)不需要
README_es.md文件项目说明(西班牙文)不需要

其实大部分都是我们不需要的,我们进行部分裁剪

最后留这五个文件就行了,但是这个时候点进去看是有一点多个g,我们还需要对这个进行裁剪

BSP

首先点开这个bsp层,里面都是各大厂商的进行适配的一些驱动吧,下面随便列举前几个介绍一下,他给的这个驱动层,也是非常方便,基本上都帮你封装好了后续自己使用的话添加他的驱动然后自己填个引脚就能用,当然如果自己写驱动也是可以的,目前我们只是移植他的系统,不用他的驱动也行。

acm32华大半导体 ACM32国产 MCU
airm2m合宙 AirM2M常用于 Cat.1 模组(如 Air724)
allwinner全志科技国产 SoC 厂商,常用于 Linux 级芯片
allwinner_tina全志 Tina Linux全志的 Linux 发行版
amebazRealtek Ameba ZRealtek 的 IoT 芯片
apm32极海半导体 APM32国产 MCU,兼容 STM32
apollo2Ambiq Apollo2超低功耗 MCU
asm9260tASM9260T国产 ARM9 芯片
at32雅特力科技 AT32国产 MCU,兼容 STM32

本文是基于gd32f4移植的,所以我们找到gd32,然后把其他的都删除就好了。

删除完,我们的文件瞬间就小了

components

下面也是简单介绍一下这些文件都是什么

目录名全称作用
dfsDevice File System虚拟文件系统。对上提供 POSIX 风格的文件接口(open/read/write),对下支持挂载不同文件系统(FATFS、LittleFS、YAFFS 等)。
driversDevice Drivers通用设备驱动框架。包含 device.c、pin.c、i2c.c、spi.c、serial.c、adc.c、pwm.c 等,对上提供统一的 rt_device 接口。你之前用的 drivers/ 分组就来自这里。
falFlash Abstraction LayerFlash 抽象层。用来统一管理片内 Flash、片外 SPI Flash,配合分区表使用,是 OTA、文件系统的底层基础。
finshFinSH Shell命令行控制台。就是串口终端里那个 msh /> 命令行,可以输入命令查看系统状态、调用函数。
legacyLegacy旧版本兼容层。存放已废弃但为了兼容老代码保留的 API。
libcC Librarylibc 适配层。里面包含 compilers/(armlibc、newlib、musl 等)和 common/
lwpLight Weight Process轻量级进程。RT-Thread Smart 版本用的用户态进程支持,普通 MCU 移植用不到。
mmMemory Management内存管理。包含 MMU/MPU 相关支持,用于带内存管理单元的芯片。
mprotectMemory Protect内存保护。配合 MPU 使用的内存访问保护机制。
netNetwork网络协议栈。包含 lwIP、AT Socket、SAL(套接字抽象层)、netdev(网卡抽象层)等。
rustRustRust 语言支持。让 RT-Thread 可以用 Rust 写应用/组件。
utilitiesUtilities实用工具。包含 ulog(日志)、ulog_easyflash、utest(单元测试)、rt-link 等。
Kconfig配置文件menuconfig 的配置描述,定义 components 里各组件有哪些配置项。
SConscript构建脚本scons 构建系统用,不需要。

很明显我们只需要留

libcpu

老规矩

aarch64ARM 64 位Cortex-A53/A55 等,跑 Linux 级 SoC
arcSynopsys ARCARC 系列嵌入式内核
armARM 32 位Cortex-M / Cortex-A / ARM7/9 等
avr32Atmel AVR32已停产的 AVR32 架构
blackfinAnalog Devices BlackfinADI 的 DSP 架构
c-sky平头哥 C-SKY国产嵌入式内核
ia32Intel x86 32 位PC 平台仿真用
m16cRenesas M16C瑞萨 16 位 MCU
mipsMIPSMIPS 架构处理器
niosAltera Nios IIFPGA 软核
ppcPowerPC经典嵌入式/工控架构
risc-vRISC-V开源指令集,近年热门
rxRenesas RX瑞萨 RX 系列
sim仿真器在 PC 上模拟运行 RT-Thread,调试用
sparc-v8SPARC V8航天/工控领域
ti-dspTI DSP德州仪器数字信号处理器
unicore32国产 Unicore国产处理器
v850Renesas V850瑞萨 V850 系列
xilinxXilinxFPGA 里的 MicroBlaze 等软核
Kconfig配置文件menuconfig 里 CPU 相关的配置项
SConscript构建脚本scons 构建用,Keil 不需要

我们只保留arm

我们点开arm

目录名对应内核典型芯片/场景
cortex-m0Cortex-M0极低端 MCU,如 STM32F0
cortex-m3Cortex-M3STM32F1、GD32F1
cortex-m4Cortex-M4GD32F4、STM32F4,高新能芯片
cortex-m7Cortex-M7STM32F7/H7,高性能 MCU
cortex-m23Cortex-M23低端 ARMv8-M
cortex-m33Cortex-M33带 TrustZone 的 ARMv8-M
cortex-m85Cortex-M85最新高性能 Cortex-M
cortex-r4Cortex-R4实时控制,如车载
cortex-r52Cortex-R52实时安全,车规级
cortex-aCortex-A 系列跑 Linux 的应用处理器

剩下的一些都是特殊芯片型号了,还有一个公共目录

目录名作用
commonARM 各内核的公共代码,如 div0.c(除零异常处理)、showmem.c(内存 dump)等

我们把 Cortex-M4 和 common 里面的文件移出来,方便我们后续在keil中添加,我这边是直接移植到libcpu目录下面了

需要注意的是,如果使用AC5编译器,.S文件要导入context_rvds.S;如果使用AC6编译器,.S文件要导入context_gcc.S这个。 

其他

include 文件夹和 src 没有什么好裁剪的,到时候原封不动添加到我们工程就好了

总结一下才剪完就是

工程移植

内核文件

首先需要移植(添加的)的就是我们的内核文件,对应的就是文件里面的src文件夹,我们点开这个src文件

文件名类型作用是否必须加入 Keil
klibc/文件夹RT-Thread 自带的一套 libc 实现需要裁剪
utest/文件夹单元测试框架否
clock.c源文件软定时器管理(rt_timer_*)是
components.c源文件自动初始化 + $Sub$$main → entry() 启动流程是
cpu_mp.c源文件多核 SMP 的 CPU 实现选(多核)
cpu_up.c源文件单核的 CPU 实现选(单核选它)
defunct.c源文件回收已删除线程的资源是
idle.c源文件空闲线程是
ipc.c源文件线程间通信:信号量、互斥量、事件集、邮箱、消息队列是
irq.c源文件中断管理:rt_interrupt_enter/leave是
kservice.c源文件内核服务:rt_kprintf 等是
mem.c源文件动态内存堆管理(rt_malloc/rt_free)可选(三选一)
memheap.c源文件多内存堆管理可选(三选一)
mempool.c源文件静态内存池是
object.c源文件内核对象容器是
scheduler_comm.c源文件调度器公共代码是
scheduler_mp.c源文件抢占式调度(支持 SMP 多核)二选一
scheduler_up.c源文件非抢占式调度(单核)二选一
signal.c源文件POSIX 信号机制可选
slab.c源文件SLAB 内存分配器可选(三选一)
thread.c源文件线程管理是
timer.c源文件系统 tick 相关(rt_tick_increase 等)是
Kconfig文件menuconfig 配置描述否
SConscript文件scons 构建脚本否

因为我平时在项目中用这个freerots用的比较多,用抢占式比较方便本文展示的就是移植这个抢占式的方法,非抢占式的话高优先级也就是比低优先级在上电的时候提前运行一下子而已,而且还要主动放弃cpu占有才行,对我来说非抢占式还不如直接用裸机+中断可以实现,这样还不用移植这个操作系统了,所以平时用的比较少,移植抢占式的话的区别在于

就是上面标注的这个二选一的文件了

然后signal.c文件它面向带 MMU、跑多进程的场景,我们的gd32单核 MCU 裸跑工程用不到。这里也不添加

三种内存管理方式,slab的话内存开销会大很多,基本上都是碎片化的,对于工程文件需要经常申请和销毁内存的需求来说可以选这个,有一个memheap这个是可以把我们的多段碎片化的内存利用起来然后重新让你看起来是一个大内存空间,这个适用于比如说这个我们raw扩容了和外部的一起用之类的,这里我选动态分配这个mem,这个比较常用。

还有一个 klibc 文件

文件名类型作用是否加入 Keil
utest/文件夹单元测试相关否
Kconfig文件menuconfig 配置描述否
kerrno.c源文件内核错误码(errno)实现加
kstdio.c源文件内核 rt_kprintf / rt_vsnprintf 相关实现加
kstring.c源文件内核字符串函数 rt_memset / rt_memcpy / rt_strlen加
rt_vsnprintf_std.c源文件标准版 rt_vsnprintf,支持完整格式化(含浮点)二选一
rt_vsnprintf_tiny.c源文件精简版 rt_vsnprintf,只支持基本格式二选一
rt_vsscanf.c源文件内核版 sscanf,解析字符串用加
SConscript文件scons 构建脚本否

我选择这个精简版rt_vsnprintf_tiny.c,基本上加上面说的那两个文件就行了,我有强迫症,裁剪完就是下面这样了

klibc文件

keil中的文件夹

cpu移植层

首先是这个libcpu/common 可以删除sconscript这个用不上,非抢占式的不用添加atomic_arm,c

在/libcpu/cortex-m4 下

可以把全部文件放到一起

设备驱动框架
driversDevice Drivers通用设备驱动框架:把各种外设(GPIO、UART、SPI、I2C、ADC、CAN、SD、LCD 等)抽象成统一的 rt_device 接口
libcC Library标准 C 库适配层:让 printf、malloc、open/read/write 这些标准函数能在 RT-Thread 上正常使用

这是刚刚裁剪的/components

点击/components/drivers,看到下面目录,先看前面几个有没有我们需要的

adcADC 设备框架用到 ADC 时加
ataATA 硬盘设备框架不需要
audio音频设备框架(IIS/SAI)不需要
block块设备框架(SD 卡、eMMC)用到 SD 卡时加
canCAN 总线设备框架用到 CAN 时加
clk时钟设备框架一般不需要
clock_time时钟/时间设备一般不需要
core设备框架核心(device.c 等)✅ 
dmaDMA 控制器框架用到 DMA 时加
dvfs动态电压频率调节不需要
ethernet以太网设备框架用到网口时加
firmware固件加载框架不需要
graphic图形设备框架(LCD/GPU)用到 LCD 时加
hwcache硬件缓存管理不需要
hwcrypto硬件加解密框架不需要
hwspinlock硬件自旋锁(多核用)不需要
i2cI2C 总线框架用到 I2C 时加
iio工业 IO 设备框架一般不需要
include驱动框架公共头文件✅ 
input输入设备框架(按键、触摸)用到时加
ipc设备层 IPC✅ 
ivshmem虚拟机共享内存不需要
ledLED 设备框架可选
mailbox邮箱设备框架(多核通信)不需要
mfd多功能设备框架(PMIC)不需要
misc杂项设备一般不需要
mtdNOR/NAND Flash 框架用到 Flash 时加

基本上我们只需要这三个文件,如果需要实现,想用他的驱动库的话,记得在bsp文件里面添加源码的驱动库,然后这里也需要添加对应的驱动文件。

点开core核心文件

utest/单元测试相关❌ 
bus.c总线设备管理:把设备挂到总线上,实现总线-设备-驱动模型✅不加也能跑
device.c设备框架核心:rt_device_register/find/open/read/write/control✅ 
dm.c设备模型(Device Model)相关,配合设备树很少加
driver.c驱动注册相关✅ 不加也能跑
Kconfigmenuconfig 配置描述
mnt.c挂载点管理,配合文件系统
numa.cNUMA 架构支持(多核服务器用)
platform.c平台设备框架,配合设备树
platform_ofw.c平台设备 + Open Firmware 支持
power.c电源管理框架
power_domain.c电源域管理
SConscriptscons 构建脚本

我们这里把其他的文件删掉,只留一个device.c文件就行

然后点击ipc文件,这个文件几乎全部保留除了utest,然后completion刚刚前面选择的是什么,这里就选什么,我这里是抢占式单核选的是completion_comm.c + completion_up.c这里是选择一个单核加上一个公共文件

裁剪一下

整理一下

libc 适配层

点开/components/libc

这里我们只保留compilers

名称类型作用是否加入 Keil
compilers文件夹各编译器的 libc 适配,如 armlibc(Keil ARMCC 用)、newlib、musl 等✅ 按你用的编译器选一个
cplusplus文件夹C++ 支持,让 RT-Thread 能跑 C++ 代码(全局对象构造、new/delete 等)用 C++ 支持
posix文件夹POSIX 接口适配层,提供 pthread、mq_*、open/read/write 等类 Unix 接口移植 POSIX 程序才加
Kconfig文件menuconfig 配置描述❌
posix-info.txt文件POSIX 支持情况的说明文档❌ 
SConscript文件scons 构建脚本❌ 

点开这个compilers

名称类型作用是否加入 Keil
armlibc文件夹ARM Compiler(Keil MDK)专用的标准库适配✅ 
common文件夹所有 libc 共用的代码✅
dlib文件夹ARM Compiler 的 Dlib 库适配(老版本 Keil 默认库)用 Dlib 才加
musl文件夹musl libc 适配,功能全但较重❌ 
newlib文件夹newlib libc 适配,GCC / ARM GCC 用❌ 
picolibc文件夹picolibc(newlib 的精简版)适配❌ 
readme.md文件说明文档❌ 
SConscript文件scons 构建脚本❌ 

最后我们添加这个bsp层方便以后我们添加驱动

添加.h文件地址

建议地址:

在keil中的魔法棒里面c/c++中的define添加RT_USING_LIBC, __CLK_TCK=RT_TICK_PER_SECOND, __RTTHREAD__,__STDC_LIMIT_MACROS, RT_USING_ARMLIBC这组宏是**告诉编译器“当前是 RT-Thread 环境,并且用 ARM 标准库”,从而让 RT-Thread 的代码、libc 适配层和 ARM C 库能正确对接,避免 `rt_vsnprintf`、`malloc` 等符号链接失败**。

应用层编写

我们需要创立三个文件,board的.c.h文件,还有一个类似于在freerots中的freerotsconfig.h的全局配置文件rtconfig.h

board.c文件主要是rt-thread让你提供你的系统时钟,以及后续想添加的各类驱动的基本引脚啊类型配置

下面提供一个写好的作为参考,也可以参考官方的一些写法,在bsp层下面有,参考目录

rt-thread-5.3.0\bsp\gd32\arm\gd32450z-eval\board

#include <rthw.h>
#include <rtthread.h>
#include "gd32f4xx.h"

#ifndef RT_WEAK
#define RT_WEAK   __weak
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE (15 * 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

/* ===================== OS Tick 回调 ===================== */
/* 提前定义:中断服务函数中会调用它 */
void rt_os_tick_callback(void)
{
    rt_interrupt_enter();
    rt_tick_increase();
    rt_interrupt_leave();
}

/* ===================== OS Tick 配置(TODO 1) ===================== */
/* 使用 TIMER5 作为系统 tick 定时器,可按需改成其它基本定时器 */
#define TICK_TIMER              TIMER5
#define TICK_TIMER_CLK          RCU_TIMER5
#define TICK_TIMER_IRQ          TIMER5_DAC_IRQn
#define TICK_TIMER_IRQHandler   TIMER5_DAC_IRQHandler

static void tick_timer_init(void)
{
    timer_parameter_struct timer_initpara;
    uint32_t prescaler;

    rcu_periph_clock_enable(TICK_TIMER_CLK);

    /* 目标:计数频率 = 1MHz,则 period = 1000000 / RT_TICK_PER_SECOND - 1
     * 注意:SystemCoreClock 是内核时钟,定时器输入频率可能不同(APB1 x2)。
     * 若定时器输入频率不是 SystemCoreClock,请修改下面的除数。 */
    prescaler = (SystemCoreClock / 1000000U) - 1U;

    timer_deinit(TICK_TIMER);
    timer_initpara.prescaler         = prescaler;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = (1000000U / RT_TICK_PER_SECOND) - 1U;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TICK_TIMER, &timer_initpara);

    /* 使能更新中断 */
    timer_interrupt_enable(TICK_TIMER, TIMER_INT_UP);
    nvic_irq_enable(TICK_TIMER_IRQ, 0, 0);

    timer_enable(TICK_TIMER);
}

/* 定时器中断服务函数 */
void TICK_TIMER_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TICK_TIMER, TIMER_INT_FLAG_UP) != RESET)
    {
        timer_interrupt_flag_clear(TICK_TIMER, TIMER_INT_FLAG_UP);
        rt_os_tick_callback();
    }
}

/**
 * This function will initial your board.
 */
void rt_hw_board_init(void)
{
    tick_timer_init();
#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
}

然后关于rt_config.h文件可以去看官方的目录下面一般也有,参考目录

\rt-thread-5.3.0\bsp\gd32\arm\gd32450z-eval

下面贴一个中文注释过的

/* RT-Thread 配置文件(自动生成,请勿手工编辑) */

#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__

/* ---------- 内核基本配置 ---------- */
#define RT_NAME_MAX 12                  /* 对象名最大长度 */
#define RT_CPUS_NR 1                    /* CPU 核心数(单核) */
#define RT_ALIGN_SIZE 8                 /* 字节对齐大小 */
#define RT_THREAD_PRIORITY_32           /* 使用 32 级优先级 */
#define RT_THREAD_PRIORITY_MAX 32       /* 优先级最大值 */
#define RT_TICK_PER_SECOND 1000         /* 每秒 1000 个 tick(1ms) */

/* ---------- 调试与钩子 ---------- */
#define RT_USING_OVERFLOW_CHECK         /* 线程栈溢出检查 */
#define RT_USING_HOOK                   /* 启用钩子函数 */
#define RT_HOOK_USING_FUNC_PTR          /* 钩子用函数指针实现 */
#define RT_USING_IDLE_HOOK              /* 启用空闲钩子 */
#define RT_IDLE_HOOK_LIST_SIZE 4        /* 空闲钩子最大数量 */
#define IDLE_THREAD_STACK_SIZE 256      /* 空闲线程栈大小 */

/* ---------- 软件定时器 ---------- */
#define RT_USING_TIMER_SOFT             /* 启用软件定时器线程 */
#define RT_TIMER_THREAD_PRIO 4          /* 定时器线程优先级 */
#define RT_TIMER_THREAD_STACK_SIZE 512  /* 定时器线程栈大小 */

/* ---------- 调试输出 ---------- */
#define RT_USING_DEBUG                  /* 启用调试 */
#define RT_DEBUGING_ASSERT              /* 启用断言 */
#define RT_DEBUGING_COLOR               /* 调试输出带颜色 */
#define RT_DEBUGING_CONTEXT             /* 调试输出带上下文 */

/* ---------- 线程间通信(IPC) ---------- */
#define RT_USING_SEMAPHORE              /* 信号量 */
#define RT_USING_MUTEX                  /* 互斥量 */
#define RT_USING_EVENT                  /* 事件集 */
#define RT_USING_MAILBOX                /* 邮箱 */
#define RT_USING_MESSAGEQUEUE           /* 消息队列 */

/* ---------- 内存管理 ---------- */
#define RT_USING_MEMPOOL                /* 静态内存池 */
#define RT_USING_SMALL_MEM              /* 小内存管理算法 */
#define RT_USING_SMALL_MEM_AS_HEAP      /* 小内存算法作为堆 */
#define RT_USING_HEAP                   /* 启用动态堆 */

/* ---------- 设备与控制台 ---------- */
#define RT_USING_DEVICE                 /* 启用设备框架 */
#define RT_USING_CONSOLE                /* 启用控制台 */
#define RT_CONSOLEBUF_SIZE 128          /* 控制台缓冲区大小 */
#define RT_CONSOLE_DEVICE_NAME "uart0"  /* 控制台设备名 */
#define RT_USING_CONSOLE_OUTPUT_CTL     /* 控制台输出控制 */
#define RT_VER_NUM 0x50300              /* RT-Thread 版本号(5.3.0) */
#define RT_BACKTRACE_LEVEL_MAX_NR 32    /* 回溯最大层数 */

/* ---------- 硬件原子操作 ---------- */
#define RT_USING_HW_ATOMIC              /* 启用硬件原子操作 */
#define ARCH_USING_HW_ATOMIC_8          /* 8 位原子操作 */
#define ARCH_USING_HW_ATOMIC_16         /* 16 位原子操作 */
#define RT_USING_CPU_FFS                /* 使用 CPU 的 find-first-set 指令 */
#define ARCH_ARM                        /* 架构:ARM */
#define ARCH_ARM_CORTEX_M               /* 内核:Cortex-M */
#define ARCH_ARM_CORTEX_M4              /* 具体型号:Cortex-M4 */

/* ---------- 组件与主线程 ---------- */
#define RT_USING_COMPONENTS_INIT        /* 启用组件自动初始化 */
#define RT_USING_USER_MAIN              /* 使用用户 main */
#define RT_MAIN_THREAD_STACK_SIZE 2048  /* main 线程栈大小 */
#define RT_MAIN_THREAD_PRIORITY 10      /* main 线程优先级 */

/* ---------- FinSH / MSH 命令行 ---------- */
#define RT_USING_MSH                    /* 启用 MSH 命令行 */
#define RT_USING_FINSH                  /* 启用 FinSH */
#define FINSH_USING_MSH                 /* 使用 MSH 模式 */
#define FINSH_THREAD_NAME "tshell"      /* FinSH 线程名 */
#define FINSH_THREAD_PRIORITY 20        /* FinSH 线程优先级 */
#define FINSH_THREAD_STACK_SIZE 4096    /* FinSH 线程栈大小 */
#define FINSH_USING_HISTORY             /* 启用历史命令 */
#define FINSH_HISTORY_LINES 5           /* 历史命令条数 */
#define FINSH_USING_SYMTAB              /* 启用符号表 */
#define FINSH_CMD_SIZE 80               /* 单条命令最大长度 */
#define MSH_USING_BUILT_IN_COMMANDS     /* 启用内置命令 */
#define FINSH_USING_DESCRIPTION         /* 命令带描述 */
#define FINSH_ARG_MAX 10                /* 最大参数个数 */
#define FINSH_USING_OPTION_COMPLETION   /* 启用参数补全 */

/* ---------- DFS 虚拟文件系统 ---------- */
#define RT_USING_DFS                    /* 启用文件系统 */
#define DFS_USING_POSIX                 /* 使用 POSIX 接口 */
#define DFS_USING_WORKDIR               /* 启用工作目录 */
#define DFS_FD_MAX 16                   /* 最大文件描述符数 */
#define RT_USING_DFS_V1                 /* DFS 版本 1 */
#define DFS_FILESYSTEMS_MAX 4           /* 最大文件系统数 */
#define DFS_FILESYSTEM_TYPES_MAX 4      /* 最大文件系统类型数 */

/* ---------- 设备驱动 ---------- */
#define RT_USING_DEVICE_IPC             /* 设备 IPC */
#define RT_UNAMED_PIPE_NUMBER 64        /* 匿名管道数量 */
#define RT_USING_SERIAL                 /* 启用串口设备 */
#define RT_USING_SERIAL_V1              /* 串口驱动 V1 */
#define RT_SERIAL_USING_DMA             /* 串口使用 DMA */
#define RT_SERIAL_RB_BUFSZ 64           /* 串口环形缓冲大小 */
#define RT_USING_PIN                    /* 启用 PIN 设备 */

/* ---------- libc 时区 ---------- */
#define RT_LIBC_USING_LIGHT_TZ_DST      /* 启用轻量时区 */
#define RT_LIBC_TZ_DEFAULT_HOUR 8       /* 默认时区:东八区 */
#define RT_LIBC_TZ_DEFAULT_MIN 0
#define RT_LIBC_TZ_DEFAULT_SEC 0

/* ---------- GD32 软件包 ---------- */
#define PKG_USING_GD32_ARM_CMSIS_DRIVER                 /* 使用 GD32 CMSIS 驱动包 */
#define PKG_USING_GD32_ARM_CMSIS_DRIVER_LATEST_VERSION  /* 使用最新版本 */
#define PKG_USING_GD32_ARM_SERIES_DRIVER                /* 使用 GD32 系列驱动包 */
#define PKG_USING_GD32_ARM_SERIES_DRIVER_LATEST_VERSION /* 使用最新版本 */

/* ---------- 芯片与 BSP 硬件配置 ---------- */
#define SOC_FAMILY_GD32                 /* 芯片家族:GD32 */
#define SOC_SERIES_GD32F4xx             /* 芯片系列:GD32F4xx */
#define SOC_GD32F450ZK                  /* 具体型号:GD32F450ZK */

/* ---------- 片上外设驱动 ---------- */
#define BSP_USING_GPIO                  /* 启用 GPIO */
#define BSP_USING_UART                  /* 启用 UART */
#define BSP_USING_SERIAL_V1             /* 串口 V1 */
#define BSP_USING_UART0                 /* 启用 UART0 */
#define BSP_UART0_TX_PIN "PA9"          /* UART0 TX 引脚:PA9 */
#define BSP_UART0_RX_PIN "PA10"         /* UART0 RX 引脚:PA10 */
#define BSP_UART0_AFIO "AF1"            /* UART0 复用功能:AF1 */
#define BSP_USING_GD_DBG                /* 启用 GD32 调试 */

#endif /* RT_CONFIG_H__ */

这种也是参考了,后续会更新如何通过配置工具配置这个rt-thread,配置工具下载地址参考:
rt-thread.org/download.html#download-rt-thread-env-toolhttps://www.rt-thread.org/download.html#download-rt-thread-env-tool下面给的是我自己裁剪过的,直接用就好了

#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__

/* ---------- 内核基本配置 ---------- */
#define RT_NAME_MAX 8                   /* 对象名最大长度 */
#define RT_CPUS_NR 1                    /* CPU 核心数(单核) */
#define RT_ALIGN_SIZE 8                 /* 字节对齐大小 */
#define RT_THREAD_PRIORITY_32           /* 使用 32 级优先级 */
#define RT_THREAD_PRIORITY_MAX 32       /* 优先级最大值 */
#define RT_TICK_PER_SECOND 1000         /* 每秒 1000 个 tick(1ms) */

/* ---------- 调试与钩子 ---------- */
#define RT_USING_OVERFLOW_CHECK         /* 线程栈溢出检查 */
#define RT_USING_HOOK                   /* 启用钩子函数 */
#define RT_HOOK_USING_FUNC_PTR          /* 钩子用函数指针实现 */
#define RT_USING_IDLE_HOOK              /* 启用空闲钩子 */
#define RT_IDLE_HOOK_LIST_SIZE 4        /* 空闲钩子最大数量 */
#define IDLE_THREAD_STACK_SIZE 256      /* 空闲线程栈大小 */

/* ---------- 软件定时器 ---------- */
#define RT_USING_TIMER_SOFT             /* 启用软件定时器线程 */
#define RT_TIMER_THREAD_PRIO 4          /* 定时器线程优先级 */
#define RT_TIMER_THREAD_STACK_SIZE 512  /* 定时器线程栈大小 */

/* ---------- 内核服务优化 ---------- */
#define RT_KSERVICE_USING_STDLIB        /* 内核服务使用标准库实现 */

/* ---------- 调试输出 ---------- */
#define RT_USING_DEBUG                  /* 启用调试 */
#define RT_DEBUGING_COLOR               /* 调试输出带颜色 */
#define RT_DEBUGING_CONTEXT             /* 调试输出带上下文 */

/* ---------- 线程间通信(IPC) ---------- */
#define RT_USING_SEMAPHORE              /* 信号量 */
#define RT_USING_MUTEX                  /* 互斥量 */
#define RT_USING_EVENT                  /* 事件集 */
#define RT_USING_MAILBOX                /* 邮箱 */
#define RT_USING_MESSAGEQUEUE           /* 消息队列 */

/* ---------- 内存管理 ---------- */
#define RT_USING_MEMPOOL                /* 静态内存池 */
#define RT_USING_SMALL_MEM              /* 小内存管理算法 */
#define RT_USING_SMALL_MEM_AS_HEAP      /* 小内存算法作为堆 */
#define RT_USING_HEAP                   /* 启用动态堆 */

/* ---------- 设备与控制台 ---------- */
#define RT_USING_DEVICE                 /* 启用设备框架 */
#define RT_USING_CONSOLE                /* 启用控制台 */
#define RT_CONSOLEBUF_SIZE 128          /* 控制台缓冲区大小 */

#define RT_VER_NUM 0x50300              //
#define RT_BACKTRACE_LEVEL_MAX_NR 32    /* 回溯最大层数 */

/* ---------- 硬件原子操作---------- */
#define RT_USING_HW_ATOMIC              /* 启用硬件原子操作 */
#define ARCH_USING_HW_ATOMIC_8          /* 8 位原子操作 */
#define ARCH_USING_HW_ATOMIC_16         /* 16 位原子操作 */
#define RT_USING_CPU_FFS                /* 使用 CPU 的 find-first-set 指令 */
#define ARCH_ARM                        /* 架构:ARM */
#define ARCH_ARM_CORTEX_M               /* 内核:Cortex-M */
#define ARCH_ARM_CORTEX_M4              /* 具体型号:Cortex-M4 */

/* ---------- 组件与主线程 ---------- */
#define RT_USING_COMPONENTS_INIT        /* 启用组件自动初始化 */
#define RT_USING_USER_MAIN              /* 使用用户 main */
#define RT_MAIN_THREAD_STACK_SIZE 2048  /* main 线程栈大小 */
#define RT_MAIN_THREAD_PRIORITY 10      /* main 线程优先级 */

/* ---------- 设备驱动 ---------- */
#define RT_USING_DEVICE_IPC             /* 设备 IPC */
#define RT_UNAMED_PIPE_NUMBER 64        /* 匿名管道数量 */
#define RT_USING_SERIAL                 /* 启用串口设备 */
#define RT_USING_SERIAL_V1              /* 串口驱动 V1 */
#define RT_SERIAL_USING_DMA             /* 串口使用 DMA */
#define RT_SERIAL_RB_BUFSZ 64           /* 串口环形缓冲大小 */
#define RT_USING_PIN                    /* 启用 PIN 设备 */

/* ---------- libc 时区 ---------- */
#define RT_LIBC_USING_LIGHT_TZ_DST      /* 启用轻量时区 */
#define RT_LIBC_TZ_DEFAULT_HOUR 8       /* 默认时区:东八区 */
#define RT_LIBC_TZ_DEFAULT_MIN 0
#define RT_LIBC_TZ_DEFAULT_SEC 0

/* ---------- 内核源码标记 ---------- */
#define __RT_KERNEL_SOURCE__            /* 标记为内核源码 */
#define __RT_IPC_SOURCE__               /* 标记为 IPC 源码 */

/* ---------- 芯片与 BSP 硬件配置 ---------- */
#define SOC_SERIES_GD32F4xx             /* 芯片系列:GD32F4xx */
#define SOC_GD32450V                



#endif /* RT_CONFIG_H__ */

应用层测试

#include "main.h" 
#include <rtthread.h>
#include "SEGGER_RTT.h"

void Led_Init(void)
{ 
	rcu_periph_clock_enable(RCU_GPIOD);
    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_14);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    gpio_bit_set(GPIOD, GPIO_PIN_14);
}
static void led_thread_entry(void *parameter)
{
	Led_Init();
    while (1)
    {
		gpio_bit_set(GPIOD, GPIO_PIN_14);
        rt_thread_mdelay(125);
		gpio_bit_reset(GPIOD, GPIO_PIN_14);
		rt_thread_mdelay(125);
		SEGGER_RTT_printf(0,"opening\n");
    }
}
static void rtt_thread_entry(void *parameter)
{
    while (1)
    {
		SEGGER_RTT_printf(0,"Ready\n");
        rt_thread_mdelay(125);
    }
}
int main(void)
{
    rt_thread_t tid_led,tid_rtt;
	
	SEGGER_RTT_Init();
    SEGGER_RTT_printf(0,"\nReady\n");

    tid_led = rt_thread_create("led",
                           led_thread_entry,
                           RT_NULL,
                           512,
                           20,
                           10);
    tid_rtt = rt_thread_create("rtt",
                           rtt_thread_entry,
                           RT_NULL,
                           512,
                           20,
                           10);
    if (tid_led != RT_NULL)
        rt_thread_startup(tid_led);
    if (tid_rtt != RT_NULL)
        rt_thread_startup(tid_rtt);

    return 0;  
}

这个rtt测试打印也是没有什么问题,移植到这里就算成功了 。

驱动层添加

添加bsp文件 drv_gpio.c 参考路径 \rt-thread-5.3.0\bsp\gd32\arm\libraries\gd32_drivers

添加.h文件

恢复一下刚刚的pin文件

添加

如何使用这个驱动,以刚刚的gpio 的led为例子

void Led_Init(void)
{ 
	rcu_periph_clock_enable(RCU_GPIOD);
    gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_14);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    gpio_bit_set(GPIOD, GPIO_PIN_14);
}

这是原来的led配置

然后添加了头文件#include <rtdevice.h>之后改成

#define LED_PIN    62
void Led_Init(void)
{ 
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
}

这个62要去drv_gpio.c里面看,可以查看到我们的对应编号,上面初始化只需要一句话就行了,如果点进去看,发现这个函数已经帮我初始化时钟之类的都配置好了。

static void led_thread_entry(void *parameter)
{
	Led_Init();
    while (1)
    {
		rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(125);
		rt_pin_write(LED_PIN, PIN_LOW);
		rt_thread_mdelay(125);
		SEGGER_RTT_printf(0,"opening\n");
    }
}

简单的置高置低电平

结语

保持好奇,持续学习,一起努力。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐