当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]最近在学习RT-Thread的使用,同时也相当于在拿它评估做产品的软件开发周期,最终学习的目的也就是希望能在未来的项目上用起来,STM32CubeMX其实已经支持了RT-Thread Nano的配置了,但我还是希望手动移植一下,没想到移植RT-Thread Nano如此简单,必须分享出来

最近在学习RT-Thread的使用,同时也相当于在拿它评估做产品的软件开发周期,最终学习的目的也就是希望能在未来的项目上用起来,STM32CubeMX其实已经支持了RT-Thread Nano的配置了,但我还是希望手动移植一下,没想到移植RT-Thread Nano如此简单,必须分享出来,哈哈哈!

之前也分享过很多RT-Thread的学习笔记,链接如下:

RT-Thread PIN设备学习笔记

RT-Thread ADC设备学习笔记

RT-Thread I2C总线设备学习笔记

RT-Thread RTC设备学习笔记

RT-Thread UART设备驱动框架初体验(中断方式接收带\r\n的数据)

1、RT-Thread Nano版是啥?

RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合。

对比RT-Thread完整版:

以上内容摘自RTT官网文档中心。

详情查看网址:

https://www.rt-thread.org/document/site/tutorial/nano/an0038-nano-introduction/

很明显Nano版本已经裁剪了很多东西,比如设备驱动及很多组件还有软件包,Nano版本更适合给客户做自由定制,客户在开发上自由度更大一些,但如果是重新开发一个新产品,我还是建议使用完整版,这么多轮子都造好了,而且RT-Thread的社区如此活跃,大佬们随时随地的线上支持,不用难道不可惜么?


文档中心也提供了如何移植RT-Thread Nano的笔记,但笔记归笔记,毕竟要自己动手去做才能了解这个过程,方便以后分析调试。

2、移植RT-Thread Nano到小熊派

2.1 在官网上下载RT-Thread Nano

解压后得到如下文件:

2.2 使用stm32CubeMX生成一个基础工程

由于之前已经写了很多CubeMX配置的文章,所以这里不详细写了,只写我配置了哪些东西,具体看下面这篇链接,写得非常详细:

超轻量级网红软件定时器multi_timer(51+stm32双平台实战)

2.2.1 时钟配置


2.2.2 调试接口配置

2.2.3 调试串口配置

2.2.4 配置调试LED灯

2.2.5 去掉这三个处理函数,以防止重复定义报错


因为RT-Thread已经有相关定义和基于RT-Thread内核特性进行实现了,这里如果勾选相当于重复定义,所以不需要,这点在官网的开发文档里也有介绍,可以去瞧一瞧。

2.2.6 工程生成配置

这里选择不生成main函数,后面我们自己写,然后点Generate Code生成基础裸机工程代码。

2.3、移植RT-Thread Nano到基础工程

2.3.1 往工程中添加RT-Thread Nano代码

2.3.2 对RT-Thread Nano进行裁剪以及工程配置

(1)将BSP目录下除board.c、rtconfig.h以外的所有文件删除

(2)删除无关内核适配

由于小熊派的CPU是基于ARM Cortex M4架构,所以在arm下只保留cortex-m4文件夹,其余都删除。

(3)删除工程自带的finsh组件

由于finsh需要RT-Thread的串口设备驱动支持,这里我们只需要一个最小的RT-Thread工程,所以这里把finsh组件去掉。

(4)在Keil MDK中添加裁剪过后的RT-Thread源代码

(5)根据需求配置rtconfig.h文件

rtconfig.h

/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

#if defined(__CC_ARM) || defined(__CLANG_ARM)
#include "RTE_Components.h"

#if defined(RTE_USING_FINSH)
#define RT_USING_FINSH
#endif //RTE_USING_FINSH

#endif //(__CC_ARM) || (__CLANG_ARM)

// <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
/*线程优先级数*/
#define RT_THREAD_PRIORITY_MAX /**8**/ 32
// <o>OS tick per second
// <i>Default: 1000 (1ms)
/*定义时钟节拍 1个tick为1ms 1000个tick每秒 1个tick为1ms*/
#define RT_TICK_PER_SECOND 1000
// <o>Alignment size for CPU architecture data access
// <i>Default: 4
/*设定字节对齐个数为4字节*/
#define RT_ALIGN_SIZE 4
// <o>the max length of object name<2-16>
// <i>Default: 8
/*内核对象名称长度,大于该长度会被内核裁剪*/
#define RT_NAME_MAX 8
// <c1>Using RT-Thread components initialization
// <i>Using RT-Thread components initialization
/*如果定义该宏,则会开启自动初始化机制,不定义的话就会关闭*/
#define RT_USING_COMPONENTS_INIT
// </c>
/*如果定义该宏,则设置应用入口为main函数*/
#define RT_USING_USER_MAIN

// <o>the stack size of main thread<1-4086>
// <i>Default: 512
/*设置main线程的大小*/
#define RT_MAIN_THREAD_STACK_SIZE 256

// </h>

// <h>Debug Configuration
// <c1>enable kernel debug configuration
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>

// <h>Hook Configuration
// <c1>using hook
// <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1>using idle hook
// <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h>

// <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o>The stack size of timer thread <0-8192>
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e>

// <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1>Using Mutex
// <i>Using Mutex
//#define RT_USING_MUTEX
// </c>
// <c1>Using Event
// <i>Using Event
//#define RT_USING_EVENT
// </c>
// <c1>Using MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1>Using Message Queue
// <i>Using Message Queue
//#define RT_USING_MESSAGEQUEUE
// </c>
// </h>

// <h>Memory Management Configuration
// <c1>Dynamic Heap Management
// <i>Dynamic Heap Management
//#define RT_USING_HEAP
// </c>
// <c1>using small memory
// <i>using small memory
#define RT_USING_SMALL_MEM
// </c>
// <c1>using tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>

// <h>Console Configuration
// <c1>Using console
// <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o>the buffer size of console <1-1024>
// <i>the buffer size of console
// <i>Default: 128 (128Byte)
#define RT_CONSOLEBUF_SIZE 128
// </h>

#if defined(RT_USING_FINSH)
#define FINSH_USING_MSH
#define FINSH_USING_MSH_ONLY
// <h>Finsh Configuration
// <o>the priority of finsh thread <1-7>
// <i>the priority of finsh thread
// <i>Default: 6
#define __FINSH_THREAD_PRIORITY 5
#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
// <o>the stack of finsh thread <1-4096>
// <i>the stack of finsh thread
// <i>Default: 4096 (4096Byte)
#define FINSH_THREAD_STACK_SIZE 512
// <o>the history lines of finsh thread <1-32>
// <i>the history lines of finsh thread
// <i>Default: 5
#define FINSH_HISTORY_LINES 1

#define FINSH_USING_SYMTAB
// </h>
#endif

// <<< end of configuration section >>>

#endif

2.4 验证RT-Thread Nano是否移植成功

2.4.1 在board.c中添加GPIO以及USART等初始化函数

board.c

#include "gpio.h"
#include "usart.h"

/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
    //添加HAL初始化函数
    HAL_Init();
/* System Clock Update */
SystemCoreClockUpdate();

/* System Tick Configuration */
_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
    //添加初始化函数
    MX_GPIO_Init();
    MX_USART1_UART_Init();
}

2.4.2 添加fputc函数,以支持printf

int fputc(int ch,FILE *fp)
{
    return HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,1000);
}

2.4.3 实现rt_hw_console_output函数

//重新实现rt_hw_console_output打印函数
void rt_hw_console_output(const char *str)
{
/* empty console output */
    printf("%s",str);
}

只要实现了这个函数,在工程中才可以调用rt_kprintf来打印,这一点通过阅读分析rt_kprintf函数源代码得知:

/**
* This function will print a formatted string on system console
*
* @param fmt the format
*/
void rt_kprintf(const char *fmt, ...)
{
va_list args;
rt_size_t length;
static char rt_log_buf[RT_CONSOLEBUF_SIZE];

va_start(args, fmt);
/* the return value of vsnprintf is the number of bytes that would be
* written to buffer had if the size of the buffer been sufficiently
* large excluding the terminating null byte. If the output string
* would be larger than the rt_log_buf, we have to adjust the output
* length. */
length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
if (length > RT_CONSOLEBUF_SIZE - 1)
length = RT_CONSOLEBUF_SIZE - 1;
    #ifdef RT_USING_DEVICE
if (_console_device == RT_NULL)
{
rt_hw_console_output(rt_log_buf);
}
else
{
rt_uint16_t old_flag = _console_device->open_flag;

_console_device->open_flag |= RT_DEVICE_FLAG_STREAM;
rt_device_write(_console_device, 0, rt_log_buf, length);
_console_device->open_flag = old_flag;
}
#else
rt_hw_console_output(rt_log_buf);
#endif
va_end(args);
}
RTM_EXPORT(rt_kprintf);
#endif

如上代码所示,当定义了RT_USING_DEVICE宏时,这里是调用了串口设备驱动,而我们这个Nano没有移植串口设备驱动,所以直接调用的rt_hw_console_output,而rt_hw_console_output是一个弱函数,本身并没有在内核里实现,所以我们要重新去实现它。

2.4.4 编写main函数

RT-Thread此时已经移植好了,接下来我们要编写main函数,实现以500ms的频率翻转LED灯以及通过打印Hello RTT_NANO字符串,通过这个例子,验证移植是否成功!

main.c

int main(void)
{
while(1)
{
rt_kprintf("Hello RTT_NANO\n");
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
rt_thread_mdelay(500);
}
}

3、运行结果

对刚刚编写的程序编译然后下载到小熊派上:

如果采用-O0优化等级进行编译,通过编译生成的RT-Thread_Nano_For_BearPi.map

查看:


本工程移植的代码编译采用默认的-O3最大优化等级:

能够看到,采用-O3等级优化后的代码体积:通过编译生成的RT-Thread_Nano_For_BearPi.map查看:

优化等级越高,则相应的编译时间就越长,一般采用-O0进行验证,没有问题后再选择-O3编译,如果出现变量被优化;导致系统明明逻辑正确却有一些莫名其妙的问题也能够根据实际调试情况进行修改。

这里顺便说说这里各个字段的含义:

  • Code:是我们编写代码占用的空间。
  • RO data(Read Only) :只读常量的大小,如const。
  • RW data(Read Write):初始化了的可读写变量的大小。
  • ZI data(Zero Initialize):没有初始化的可读写变量的大小,ZI-data不会被算做代码里因为不会被初始化。

FLASH中的被占用的空间为:Code+RO Data + RW Data

芯片内部RAM使用的空间为:RW Data + ZI Data

足够轻量了吧!接下来下载到小熊派上可以看到:

不少朋友可能第一次移植RTT后会有疑问:为啥main函数里没看到其它硬件外设、时钟的初始化的东西呢?

那是因为RT-Thread拓展了main函数,在main函数之前就把这些工作都做好啦!还记得前面为什么要在board.c中添加外设等初始化函数的步骤吧?如下图所示,这是RT-Thread的启动流程图:

关于RT-Thread初始化流程描述文档如下: 

https://www.rt-thread.org/document/site/programming-manual/basic/basic/

官网上描述启动流程的文档非常详细,而且我认为RT-Thread已经做得足够傻瓜化了,什么文档、例程啥都给你弄好了,如果认真花点时间好好学习研究是可以学习得非常透彻的,不懂随时论坛和RT-Thread的QQ群及微信群都可以提问,有众多的开发者一起解决问题。

4、移植工程案例下载

公众号后台回复:rttnano 即可获取移植案例的下载链接。

5、题外话

看到公众号后台有人问:C语言#和##连接符在项目中的应用(漂亮) 这篇文章里老外代码的出处,这是我很早之前在Github上看到的,这是来自Github上的Tilen Majerle大佬写的,代码质量非常优秀,值得我们学习,他本人就职于ST意法半导体公司。

链接:https://github.com/MaJerle/stm32fxxx-hal-libraries

Github链接:https://github.com/MaJerle

往期精彩

C语言#和##连接符在项目中的应用(漂亮)

MCU SPI屏也能跑这么炫酷的特效?来,移植起来秀一秀

超轻量级网红软件定时器multi_timer(51+stm32双平台实战)

觉得本次分享的文章对您有帮助,随手点[在看]并转发分享,也是对我的支持。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

摘要:为了研究微型多旋翼的定点控制,设计并实现了一种基于RT-Thread的微型多旋翼定点控制系统。采用DigitalMotionProcessing库和双闭环PID进行姿态控制,使用磁力计与激光测距仪进行航向与高度的锁...

关键字: RT-Thread 定点控制 数据融合

上海2023年2月16日 /美通社/ -- 近日,诺华中国宣布与中国红十字基金会正式启动"中国地中海贫血救助项目"广西地区专项援助,将在当地定向资助困难家庭地中海贫血患儿,同时通过相关医生培...

关键字: BSP 控制 移植 大众

北京2022年12月7日 /美通社/ -- 2022年12月3日,由高博医学(血液病)广东研究中心南方春富(儿童)血液病研究院、南方医科大学南方医院共同主办的高博医学论坛·华南造血干细胞移植论坛通过线下线上...

关键字: 移植 HD PID 血细胞

捐款近4000万 上海2022年12月7日 /美通社/ -- 2022年12月7日下午,中芯国际"芯肝宝贝计划"十年纪念暨2022年度捐赠仪式在上海仁济医院举行。十年来,该项目捐赠善款总额近4000...

关键字: 中芯国际 移植

北京2022年11月14日 /美通社/ -- 2022年10月,高博医学(血液病)北京研究中心北京高博博仁医院造血干细胞移植科迎来了五周岁"生日"。在吴彤主任带领下,移植科于2017年从无到有,历经五...

关键字: 移植 OS MT CD

上海2022年11月6日 /美通社/ -- 在第五届中国国际进口博览会期间,武田制药携5款创新产品亮相武田罕见遗传与血液疾病领域专场发布会。用于移植后抗巨细胞病毒(CMV)感染或疾病治疗[1]的马立巴韦[2]迎来&quo...

关键字: 移植 BSP CD FDA

亘喜生物科技集团宣布正在中国开展的、旨在全面评估GC007g治疗复发/难治性急性B淋巴细胞白血病效果的1/2期注册性临床试验顺利进入2期研究阶段,首例入组患者已给药。GC007g是亘喜生物旗下的一款靶向CD19的供者来源...

关键字: 移植 CD

北京2022年9月9日 /美通社/ -- 诺诚健华(香港联交所代码:09969)今天宣布,tafasitamab (Minjuvi®)联合来那度胺治疗不适合自体干细胞移植 (ASCT) 条件的复发/难治弥漫性大B...

关键字: VI NJU BSP 移植

苏州2022年8月19日 /美通社/ -- 近日,华中科技大学同济医学院附属协和医院心外科董念国教授团队运用与心擎医疗联合研发的短中期体外全磁悬浮心室辅助装置MoyoAssist®,成功救治三例危重的终...

关键字: 磁悬浮 移植 IC 静脉

上海2022年8月17日 /美通社/ -- 2022年8月16日,聚焦于基因和细胞治疗的上海邦耀生物科技有限公司(以下简称"邦耀生物")宣布,其...

关键字: CD 移植 BSP ISP
关闭
关闭