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

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_SMPrt_hw_spin_lock_init(&_cpus_lock);
#endifrt_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_SMPrt_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_SMPrt_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_HEAPtid = rt_thread_create("main", main_thread_entry, RT_NULL,RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);RT_ASSERT(tid != RT_NULL);
#elsert_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.rhkb.cn/news/417080.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超详细步骤——Keil MDK-ARM 如何修改工程名字

背景: 注意:本项目是基于 STM32 单片机的裸机程序,使用 STM32CubeMX 工具生成的 Keil MDK-ARM 工程。 目标: 在 Keil MDK-ARM 开发环境中,将名为version0805 的工程重命名为 version0910,并确保所有新编译…

文本怎么在线做成二维码?文字信息生成活码的制作方法

文本怎么做成二维码来展示呢?现在通过二维码分享信息的方式越来越常见,可以将文本二维码应用于许多的用途,比如人员信息、物品信息、通知内容、企业介绍等内容都可以生成二维码来展示。那么文本生成二维码该怎么生成呢?下面教大家…

达梦数据库的系统视图v$sysstat

达梦数据库的系统视图v$sysstat 在达梦数据库(DM Database)中,V$SYSSTAT 视图提供了关于数据库系统性能和状态的一系列统计信息。这个视图是数据库管理员(DBA)用来监控和管理数据库性能的重要工具之一。它包含许多统计…

CUDA统一内存:简化GPU编程的内存管理

CUDA统一内存:简化GPU编程的内存管理 在现代GPU编程中,内存管理一直是开发者面临的一个重要挑战。特别是在使用NVIDIA CUDA进行高性能计算时,如何在CPU和GPU之间高效地传输数据、以及如何管理这些数据的生命周期,都是影响程序性能…

postman注入csrf

示例脚本 参数配置位置 必要参数 django项目仅需要设置domain即可,比如www.baidu.com,baidu.com尽量域名精确避免修改到其他域的参数 必须把这个domain添加到 cookies->Manage cookies ->Domains Allowlist 中,否则cookie的注入失败 代码 // 必…

图像白平衡

目录 效果 背景 什么是白平衡? 实现原理 将指定图色调调整为参考图色调主要流程 示例代码 效果 将图一效果转换为图二效果色调: 调整后,可实现色调对换 背景 现有两张图像,色调不一致,对于模型重建会有影响。因…

Java体系中的继承

前言 #继承(Inheritance) 是面向对象编程(OOP)中的一个重要概念,它允许一个类(称为子类或派生类)可以从另一个类(称为父类、基类或超类)继承属性(数据&#…

Unexpected token d in JSON at position 5, check bodyParser config错误解决

错误原因:json格式不对 { desc"设备1", iotProjectId11 } 解决:通过json在线校验格式校验json格式,找出错误原因,修改 在线JSON校验格式化工具(Be JSON) 修改: {"desc": &…

『功能项目』AssetBundle上传加载u3d模型【23】

本章开始做游戏的登陆界面,运用热更新的AssetBundle上传加载u3d模型 首先在22骑乘坐骑项目基础上重新创建一个场景 重命名为RegistrationUI 在资源商店下载一个场景 选择一个免费资源场景导入 进入新导入的场景 完全解压缩后重命名为ResUIScene 将颜色调成为蓝色调…

强制性国标!上海控安参编《汽车整车信息安全技术要求》正式发布

8月23日,上海控安参编的《GB 44495-2024 汽车整车信息安全技术要求》正式发布,标准将于2026年1月1日正式实施。 汽车整车信息安全技术要求 《汽车整车信息安全技术要求》由工业和信息化部归口,委托全国汽车标准化技术委员会智能网联汽车分会…

13、Django Admin创建两个独立的管理站点

admin文件 from .models import Epic, Event, EventHero, EventVillain from django.contrib.admin import AdminSiteclass EventAdminSite(AdminSite):site_header "Events管理"site_title "欢迎您!"index_title "管理员"even…

学习之MySQL函数(字符串,数值,日期,流程)

字符串函数 函数是指一段可以直接被另一段程序或代码 案例: – 1、由于业务需求变更,企业员工的工号,统一为5位数,目前不足5位数的全部在前面补0、比如:1号员工的工号应该为00001. update emp set worknolpad(workno, 5, 0) 运…

2024 年全国大学生数学建模竞赛(国赛)浅析

需要完整资料,请关注WX:“小何数模”! (需要完整B、C和E题资料请关注WX:“小何数模”,获取资料链接!) 本次万众瞩目的全国大学生数学建模赛题已正式出炉,无论是赛题难度…

2024 数学建模高教社杯 国赛(A题)| “板凳龙”舞龙队 | 建模秘籍文章代码思路大全

铛铛!小秘籍来咯! 小秘籍团队独辟蹊径,运用等距螺线,多目标规划等强大工具,构建了这一题的详细解答哦! 为大家量身打造创新解决方案。小秘籍团队,始终引领着建模问题求解的风潮。 抓紧小秘籍&am…

Android 下的 XML 文件(概念理解、存储位置理解)

一、XML 1、XML 概述 XML(Extensible Markup Language,可扩展标记语言)是一种用于存储和传输数据的标记语言 类似于 HTML,但旨在传输和存储数据,而不是显示数据,且基本语法都是标签 2、XML 的特点 &am…

记录ssl epoll的tcp socket服务端在客户端断开时崩溃的问题

文章目录 当客户端关闭后,Epoll 的 TCP socket 服务端会收到两次断开事件可能有以下原因及解决方法:原因分析解决方法 问题ssl socket服务端代码出错现象第一次尝试修改正确改法附上客户端代码 记录ssl epoll的tcp socket服务端在客户端断开时接收到多次…

进程的那些事——了解进程(虚拟地址空间)

目录 前言 一、程序地址空间(虚拟地址空间) 二、虚拟地址寻找物理内存 1.页表 总结 前言 提示:这里可以添加本文要记录的大概内容: 程序和进程之间的区别: 进程:对用户而言,进程是运行中的…

web群集--nginx常见的几种负载均衡调度算法的配置过程和效果展示

文章目录 前言环境前置配置httpd主机tomcat主机 负载均衡调度算法1.轮询配置过程效果展示 2.加权轮询配置过程效果展示 3. IP哈希(IP Hash)配置过程效果展示 4. 最少连接(Least Connections)配置过程效果展示 5.加权最小连接这个在…

25考研人数预计下降?这一届考研有哪些新趋势?

2025年考研时间线: 2024年9月:公共课及各院校考试大纲公布; 2024年9月下旬:预报名; 2024年10月:正式报名; 2024年11月:线上/线下确认; 2024年12月中下旬&#xff1a…

如何批量修改图片的名称,高效修改图片名的软件

图片存在我们电脑上,有的时候由于某些原因,可能需要对图片进行大批量的名称修改,这个时候如果我们使用系统的重命名来做的话,它只能一个一个修改,想要批量修改,只能使用专门的命令,不仅复杂&…