【GD32】RT-Thread实时操作系统移植(GD32F470ZGT6)

news2024/9/20 16:46:45

1. 简介

        最近几年可以发现国产的实时操作系统越来越受欢迎了,本篇要移植的就是当中的翘楚——RT-Thread。

        RT-Thread诞生于2006年,是国内以开源中立、社区化发展起来的一款高可靠实时操作系统 ,由睿赛德科技负责开发维护和运营 。并且在上一年度的市场欢迎程度中位列第一,第一次超过了老牌的FreeRTOS系统。

        相比于FreeRTOS,它的优势是强大的第三方和官方软件库,这意味着在项目开发中可以大大减少软件库移植的时间,提高了开发效率。不过根据我以往的项目经验,这些库还是有不少bug存在的,所以RT-Thread社区对于库的维护和更新还是要更加努力才行。

        RT-Thread库的代码风格、软件逻辑可以说是完全模仿Linux的,如果各位本身就有Linux系统的开发经验,那么RT-Thread可以说是轻松上手,甚至可以通过学习RT-Thread来反向学习Linux系统的原理(我就是这样的),毕竟Linux的官方文档确实一言难尽。对于新手,官网提供了比较完善的开发文档,我个人认为算是非常详尽的了。

2. 移植

        RT-Thread为了尽可能地兼容多的单片机,它分为标准版、nano版和smart版。标准版就是给系统资源比较充足的单片机移植的,可以使用社区里面的所有库;nano版是给资源较少的单片机移植的,只能使用部分的官方库;smart版是给物联网设备移植,这个分支比较少用。

        本篇我们移植的是标准版,目前最新的发行版本是5.1.0,在Github上面可以下载RT-Thread源码。

2.1 导入文件

        下载源码后解压,RT-Thread要导入的文件还是非常多的,先讲一下源代码里面关键文件夹的代码内容。

        bsp目录主要存放各个芯片、开发板的外设驱动。

        components目录主要存放一些系统部件,如HAL层驱动、C库支持、shell命令行支持等等。

        documentation目录主要存放一些说明文档。

        examples目录主要存放一些例程。 

        include目录主要是内核的头文件。

        libcpu目录主要存放是是不同处理器底层的驱动。

        src目录存放的是内核的源文件。

        tools目录主要存放的是一些Python的工具脚本。

        要导入的文件大致就是: 

        1. src目录的大部分文件;

        2. libcpu目录中Arm Cortex-M4相关的文件,参考路径libcpu\arm\cortex-m4;

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

        3. bsp目录中GD32F470相关的外设驱动,参考路径bsp\gd32\arm\libraries\gd32_drivers;

        4. components目录中外设HAL层驱动相关文件,参考路径components\drivers;

        5. components目录中C库相关文件,参考路径components\libc\compilers;

         要导入的头文件路径也比较多,参考下面:

        其他设置要注意的是,不要勾选“Use MicroLIB”这一个选项。

        另外就是,因为RT-Thread内核已经写好了所需的所有底层驱动,所以标准固件库里面导入的像systick、gd32f4xx_it类似的文件就不需要了。

 2.2 配置文件

        RT-Thread的配置文件应该是我见过最复杂的,不算第三方库至少也有上千个配置项,然后你要根据自己的配置项导入对应的源文件,导错的话就会编译不过。一般来说,官方会推荐使用RT-Thread Studio开发或使用Kconfig工具进行配置。不过这里只是进行简单移植即可,能成功跑起来就行,更深入的可以以后再慢慢学。

        对于第一次进行移植的可以参考源码项目里面的例程,下面是我根据例程精简过的配置文件。

#ifndef RT_CONFIG_H__
#define RT_CONFIG_H__

/* Automatically generated file; DO NOT EDIT. */
/* RT-Thread Configuration */

/* RT-Thread Kernel */

#define RT_NAME_MAX 8
#define RT_CPUS_NR 1
#define RT_ALIGN_SIZE 8
#define RT_THREAD_PRIORITY_32
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND 1000
#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

/* kservice optimization */

#define RT_KSERVICE_USING_STDLIB
#define RT_USING_DEBUG
#define RT_DEBUGING_COLOR
#define RT_DEBUGING_CONTEXT

/* Inter-Thread communication */

#define RT_USING_SEMAPHORE
#define RT_USING_MUTEX
#define RT_USING_EVENT
#define RT_USING_MAILBOX
#define RT_USING_MESSAGEQUEUE

/* Memory Management */

#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_VER_NUM 0x50100
#define RT_BACKTRACE_LEVEL_MAX_NR 32

/* RT-Thread Components */

#define RT_USING_COMPONENTS_INIT
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 2048
#define RT_MAIN_THREAD_PRIORITY 10

/* Device Drivers */

#define RT_USING_DEVICE_IPC
#define RT_UNAMED_PIPE_NUMBER 64
#define RT_USING_SERIAL
#define RT_USING_SERIAL_V1
#define RT_SERIAL_USING_DMA
#define RT_SERIAL_RB_BUFSZ 64
#define RT_USING_PIN

/* Using USB */


/* C/C++ and POSIX layer */

/* ISO-ANSI C layer */

/* Timezone and Daylight Saving Time */

#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

/* POSIX (Portable Operating System Interface) layer */


/* Interprocess Communication (IPC) */


/* Socket is in the 'Network' category */


/* Network */


/* Memory protection */


/* Utilities */


/* RT-Thread Utestcases */


/* RT-Thread online packages */

/* IoT - internet of things */


/* Wi-Fi */

/* Marvell WiFi */


/* Wiced WiFi */


/* CYW43012 WiFi */


/* BL808 WiFi */


/* CYW43439 WiFi */


/* IoT Cloud */


/* security packages */


/* language packages */

/* JSON: JavaScript Object Notation, a lightweight data-interchange format */


/* XML: Extensible Markup Language */


/* multimedia packages */

/* LVGL: powerful and easy-to-use embedded GUI library */


/* u8g2: a monochrome graphic library */


/* tools packages */


/* system packages */

/* enhanced kernel services */


/* acceleration: Assembly language or algorithmic acceleration packages */


/* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */


/* Micrium: Micrium software products porting for RT-Thread */


/* peripheral libraries and drivers */

/* HAL & SDK Drivers */

/* STM32 HAL & SDK Drivers */


/* Kendryte SDK */


/* sensors drivers */


/* touch drivers */


/* AI packages */


/* Signal Processing and Control Algorithm Packages */


/* miscellaneous packages */

/* project laboratory */

/* samples: kernel and components samples */


/* entertainment: terminal games and other interesting software packages */


/* Arduino libraries */


/* Projects and Demos */


/* Sensors */


/* Display */


/* Timing */


/* Data Processing */


/* Data Storage */

/* Communication */


/* Device Control */


/* Other */


/* Signal IO */


/* Uncategorized */
#define __RT_KERNEL_SOURCE__
#define __RT_IPC_SOURCE__

/* Hardware Drivers Config */

#define SOC_SERIES_GD32F4xx
#define SOC_GD32470Z

/* Onboard Peripheral Drivers */

/* On-chip Peripheral Drivers */

#define BSP_USING_GPIO
#define BSP_USING_UART
#define BSP_USING_UART0

/* Board extended module Drivers */


#endif

        除此之外,还需要添加一些全局宏定义——“RT_USING_LIBC, __CLK_TCK=RT_TICK_PER_SECOND, __RTTHREAD__,__STDC_LIMIT_MACROS, RT_USING_ARMLIBC”

        至此,进行编译的话应该就能成功了。如果编译不成功的话,可以尝试通过错误打印查找原因,大部分都是因为文件导少了导多了、某个配置项没设置之类的。或者参考官方的例程,我的开发板例程在路径bsp\gd32\arm\gd32470z-lckfb下。

2.3  测试程序

        我们也是简单写一个跑马灯程序,看看RT-Thread有没有移植成功。

#include "gd32f4xx.h"
#include "rtthread.h"
#include "rtdevice.h"
#include "board.h"

#define DBG_TAG    "main"
#define DBG_LVL    DBG_INFO
#include "rtdbg.h"

#define LED1_PIN GET_PIN(E, 3)

int main(void)
{
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

	while (1) {
        rt_pin_write(LED1_PIN, PIN_HIGH);
        LOG_I("LED1 ON");
        rt_thread_mdelay(1000);
        rt_pin_write(LED1_PIN, PIN_LOW);
        LOG_I("LED1 OFF");
        rt_thread_mdelay(1000);
	}
}

        RT-Thread自带一个调试子系统,感觉是模仿Easylogger的,需要导入rtdbg.h,还要定义DBG_TAG和DBG_LVL宏定义,前者是一个字符串标签,调试时会打印出来;后者是调试打印的等级。

        这里我使用了pin子系统,这样定义GPIO管脚会方便很多,使用GET_PIN宏定义可以获取管脚,使用rt_pin_mode可以定义管脚,rt_pin_write可以设置管脚输出,感觉这个又是模仿Arduino的。

        延时的话就调用rt_thread_mdelay即可,单位是毫秒。

        细心的同学可能发现,为什么代码中没有创建线程这种操作?其实main函数就是一个线程。那是怎么做到的呢?这里简单分析一下源码,位于components.c文件。

        RT-Thread在初始化系统的时候很巧妙地使用了MDK的$Sub$$main和$Super$$main两个特性;前者是在main函数执行前插入一段代码,后者是跳转到main函数中。

extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
    rtthread_startup();
    return 0;
}

        在main函数执行前,插入了rtthread_startup函数,用于初始化RT-Thread系统。

int rtthread_startup(void)
{
#ifdef RT_USING_SMP
    rt_hw_spin_lock_init(&_cpus_lock);
#endif
    rt_hw_local_irq_disable();

    /* board level initialization
     * NOTE: please initialize heap inside board initialization.
     */
    rt_hw_board_init();

    /* show RT-Thread version */
    rt_show_version();

    /* timer system initialization */
    rt_system_timer_init();

    /* scheduler system initialization */
    rt_system_scheduler_init();

#ifdef RT_USING_SIGNALS
    /* signal system initialization */
    rt_system_signal_init();
#endif /* RT_USING_SIGNALS */

    /* create init_thread */
    rt_application_init();

    /* timer thread initialization */
    rt_system_timer_thread_init();

    /* idle thread initialization */
    rt_thread_idle_init();

#ifdef RT_USING_SMP
    rt_hw_spin_lock(&_cpus_lock);
#endif /* RT_USING_SMP */

    /* start scheduler */
    rt_system_scheduler_start();

    /* never reach here */
    return 0;
}

         这个函数里面都是一些系统初始化的操作,重点在rt_application_init函数,main线程就是在这里面初始化的。

static void main_thread_entry(void *parameter)
{
    extern int main(void);
    RT_UNUSED(parameter);

#ifdef RT_USING_COMPONENTS_INIT
    /* RT-Thread components initialization */
    rt_components_init();
#endif /* RT_USING_COMPONENTS_INIT */

#ifdef RT_USING_SMP
    rt_hw_secondary_cpu_up();
#endif /* RT_USING_SMP */
    /* invoke system main function */
#ifdef __ARMCC_VERSION
    {
        extern int $Super$$main(void);
        $Super$$main(); /* for ARMCC. */
    }
#elif defined(__ICCARM__) || defined(__GNUC__) || defined(__TASKING__) || defined(__TI_COMPILER_VERSION__)
    main();
#endif /* __ARMCC_VERSION */
}

void rt_application_init(void)
{
    rt_thread_t tid;

#ifdef RT_USING_HEAP
    tid = rt_thread_create("main", main_thread_entry, RT_NULL,
                           RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
    RT_ASSERT(tid != RT_NULL);
#else
    rt_err_t result;

    tid = &main_thread;
    result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
                            main_thread_stack, sizeof(main_thread_stack), RT_MAIN_THREAD_PRIORITY, 20);
    RT_ASSERT(result == RT_EOK);

    /* if not define RT_USING_HEAP, using to eliminate the warning */
    (void)result;
#endif /* RT_USING_HEAP */

    rt_thread_startup(tid);
}

         可以看到main线程的实现函数中,调用了$Super$$main,将代码跳转到了实际的main函数里面。

        不得不感叹RT-Thread的骚操作!!!

2.4 运行结果

        RT-Thread系统启动时会打印版本信息,接下来就是用户的打印,因为RT-Thread的调试子系统是默认使用彩色打印的,所以最好使用支持彩色调试打印的串口助手,像我使用的MobaXterm,不然会出现一些乱码。

        移植成功的话就会看到板子上的LED灯闪烁了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2096864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习面试:请介绍下LR的损失函数?

在机器学习中,逻辑回归(Logistic Regression, LR)是一种广泛使用的分类算法,尤其适用于二分类问题。逻辑回归的损失函数主要是用来衡量模型预测值与真实值之间的差距。以下是对逻辑回归损失函数的详细介绍: 1. 逻辑回…

【千帆AppBuilder】使用Python调用基于官方的API创建图片故事的应用,一起体验下全代码模式下是怎样的效果

欢迎来到《小5讲堂》 这是《千帆》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 背景基本信息名称简介角色指令 能力扩展组件对话开场白推荐问 模型选…

Rust到底值不值得学,之二

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一 -CSDN博客 1.2.2 引用和借用 如果每次都发生所有权的转移,程序的编写就会变得异…

LVGL 控件之图表部件(lv_chart)

目录 一、图表1、组成2、类型3、显示数据3.1 lv_chart_set_ext_y_array/lv_chart_set_ext_x_array3.2 lv_chart_set_next_value3.3 lv_chart_set_all_value3.4 lv_chart_set_value_by_id3.5 在数组中手动设置 4、设置数据点数量5、辅助功能5.1 垂直范围5.2 分隔线5.3 设置默认起…

Mathematica如何进行公式推导和使用

目录 一、内容描述 二、如何打出公式[2] 三、具体操作 四、参考文献 一、内容描述 在Mathematica中通过几个简单命令可以将一大串的三角函数进行分解及简化,大大节省了推导时间,并保证了推导的正确性。 二、如何打出公式[2] 具体操作&#xff1a…

VastBase——VPatch版本控制

一、准备工作 1.概述 VPatch是用于Vastbase版本控制的工具。可以实现在单机环境下的升级和回退操作,具体功能如下: 升级环境检查,补丁冲突检查等。 PSU、PSR、OOP补丁的升级、回退、升级或回退失败时的还原。 升级过程中记录相关日志和步…

华为OD机试真题 - 来自异国的客人(Python/JS/C/C++ 2024 D卷 100分)

华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试真题(Python/JS/C/C)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,…

使用老毛桃的一些坑

个性设置不要去点 三种模式的区别 ISO模式:直接U盘成为某个系统的启动盘 本地模式:相当于硬盘中植入一个PE系统,与后续的windows系统,一起组成双系统 普通模式:PE系统在U盘中,这样ISO可以是多种不同的系…

98.SAP MII功能详解(12)Workbench-Transaction Logic(For Next Loop)

目录 1.Logic->For Next Loop 2.演示 配置对象 配置连接 for循环的整体演示 1.Logic->For Next Loop 此操作用于在预定义的次数内执行任务。每次迭代都会执行直接跟随For Next循环操作的所有操作,直到达到To限制。 若要在达到To属性限制之前停止&…

我用GPT对RAG技术的学习和探索

思维导图 下图是我的学习和探索过程,红点表示已研究,黄点表示待研究 目录 思维导图RAG技术概述RAG 的关键优点应用场景 如何了解RAG技术的原理和应用1. **基础理论学习**2. **实战演练**3. **学习资源利用**4. **保持学习的连贯性**5. **多角度理解**6. …

SpringBoot配置返回数据不存在null

一、引言 最近在做项目中遇到一个神奇的问题,在测试返回银行三级数据的时候有的项目中返回的数据中把null值的数据返回了,而有的时候就不存在null值数据,如下所示: 存在null值情况 不含null值情况 但是我们可以看一下返回的VO的…

AG32 MCU如何指定一段RAM可以重启或复位不丢失数据

AG32 MCU如何指定一段RAM可以重启或复位不丢失数据? 目前还没这样的功能。 建议可以试下: 把系统ram设置成120K,最后的8K只能自己访问。 这样重启时,系统不会自动擦除最后的8K。可能是可以的。 备份寄存器大概有几十字节可以用。但是这个需…

2024最新comfyui保姆级教程来啦!comfyui工作流搭建看这一篇就够了!

前言 一、SD主流 UI Stable Diffusion(SD)因为其开源特性,有着较高的受欢迎程度,并且基于SD的开源社区及教程、插件等,都是所有工具里最多的。基于SD,有不同的操作界面,可以理解为一个工具的不…

基于zigbee的广告牌安全监测系统设计与实现(论文+源码)

1.系统方案 本次基于Zigbee的广告牌安全监测系统,使用Zigbee组网,一共具有2块板子,其中1块作为协调器,另1块作为终端。首先由协调器构建Zigbee网络,终端连上协调器网络后,每隔1秒钟采集一次传感器数据并通…

2024好用的骨传导耳机有哪些?精选这热门五款拒绝踩雷!

作为一名运动狂热者,我已经坚持运动八年了,在这八年运动时间里我最离不开的就是运动耳机了,一副好的运动耳机重要性可太多了,不仅更加可以提高我们的运动效率,还有更多元化的功能。运动耳机市场在这几年获得了长足的发…

Docker占用根目录/存储空间过多如何清理?

问题背景 使用df -h查看磁盘空间时发现根目录空间不多了,已使用96%,红色警告!!! 于是使用df -h /* 一层一层定位,终于找到了一个大文件 9G多的文件夹,位置是: /var/lib/docker/o…

计算机毕业设计Hadoop+Spark抖音可视化 抖音舆情监测 预测算法 抖音爬虫 抖音大数据 情感分析 NLP 自然语言处理 Hive 机器学习 深度学习

技术栈:数据分析Spark、数据库Hive MySQL、服务器djano、爬虫requests jieba库中文分词,通俗来说,就是将一句(段)话按一定的规则(算法)拆分成词语、成语、单个文字。 中文分词是很多应用技术的前置技术,如搜索引擎、机器翻译、词…

Unity(2022.3.41LTS) - 视频

目录 零. 简介 一、视频支持的格式和平台 二、视频播放组件 三、视频播放控制 四、视频与游戏交互 五、性能和优化 零. 简介 在 Unity 中,视频播放是一项强大的功能,可以为游戏和应用程序增添丰富的多媒体体验。 一、视频支持的格式和平台 Unit…

Linux系统练习笔记【完整版】

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…

力扣1235.规划兼职工作

力扣1235.规划兼职工作 动态规划 二分 将所有工作按照结束时间排序f[i]表示前i个工作可获取的最大收益状态转移:取第i个工作,f[i] profit[i] f[j],其中j为结束时间小于i的开始时间的最大数不取第i个工作,f[i] f[i-1]可以通过二…