电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
RT-Thread学习笔记+2.RTT的启动分析
分 享
扫描二维码分享
RT-Thread学习笔记+2.RTT的启动分析
RTT
启动
川楠
关注
发布时间: 2019-11-18
丨
阅读: 3494
**摘要** 本文主要介绍RT-Thread刚刚入手,以及RTT的上电启动过程分析。 **系统移植** 关于RTT的系统移植,我觉得还是很简单的,之前我做过针对自己的开发板做了一款BSP。参考RTT官网提供的BSP制作教程,一次性成功,唯一的是要花点时间。 ![](https://cf01.ickimg.com/bbsimages/201911/9220cf8a977bcfaf040d3ac0509e1dca.jpg) 而本次我准备使用使用的正点原子的战舰V3的板子来学习RTT,因为这个板子上的板载资源要丰富一些。当我准备按照之前的经验,做一款战舰V3的BSP的时候才发现,原来已经有成品了。那就本着拿来主义,先用用吧。 ![](https://cf01.ickimg.com/bbsimages/201911/60f073787a228e876f1ad4663ce36846.jpg) 最终我在从官网下载的压缩包里面找到正点原子战舰V3的BSP。 ![](https://cf01.ickimg.com/bbsimages/201911/28746c9a14717121c0c02616538085ad.jpg) 个人推荐,可以把用不到的BSP删了,毕竟这个源码压缩包解压之后有700多M,还是蛮占用空间的。然后在rt-thread\bsp\stm32\libraries目录下,把其他用不到的库文件也删掉,只保留了F1的库文件夹即可。 最后强调一下:学习RTT,板子不是关键,不论是正点原子、野火、安富莱,还是F1、F4、F7都是可以的,不要纠结板子,最主要的了解RTT的使用方法。 程序下载进去之后,我使用的Xshell5软件,将板载的USB串口与PC连接: ![](https://cf01.ickimg.com/bbsimages/201911/3012d4ddba060736182c6f2f0a230afe.jpg) Main.C文件的代码十分简单,就一个闪灯程序。 ![](https://cf01.ickimg.com/bbsimages/201911/26a84f473ae993e6089f5b9e809bd76d.jpg) RTT的系统初始化,以及空闲任务等启动系统启动,都不见踪影,这不得不让我想一探究竟。 **代码框架分析** 首先,看了下启动文件startup_stm32f103xe.s,这个文件还是使用的是hal库提供的标准文件,RTT并没在这个上面做文章。 ![](https://cf01.ickimg.com/bbsimages/201911/3e1be35281113d10d23537887b4cd4b8.jpg) 启动代码还是没有变,流程还是一样: 166行:将SystemInit()函数的入口地址放到R0寄存器 167行:跳转到R0地址的,开始执行SystemInit()函数,这个函数还是ST官方提供的函数。 168行,将__main函数的入口地址给到R0 169行:跳转到__main函数,开始执行。 需要注意的是__main()是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()。 所以说,前者是库函数,后者就是我们自己编写的main()主函数; 但是RTT的启动函数呢? 经过一番查找,RTT的启动用到了MDK提供的$Super$$ 和 $Sub$$ “补丁”函数的功能,这个是在__CC_ARM 编译器环境中,编译器提供的一个功能。下图为MDK提供官方原文: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0377g/pge1362065967698.html ![](https://cf01.ickimg.com/bbsimages/201911/875e5b588e361b9bfcc9579decd19c91.jpg) 其意思是,以下文中的示例代码为例: int $Sub$$main(void) { 补丁函数(); $Super$$main(); return 0; } 在进入main()之前,会先执行$Sub$$main(void)函数中的内容, 是以,补丁函数();得以优先运行。 最后当执行到$Super$$main()函数时,程序才开始跳转到main()函数,去执行main()函数的内容。 而RTT也就是用的这种“补丁”的方式,也下面我将整个RTT的初始化流程做成了一个简单的流程示意图,方便大家更明白的了解RTT的启动流程。 ![](https://cf01.ickimg.com/bbsimages/201911/c1379df9950dafdae9b847f837807141.jpg) 程序从启动文件的__main函数执行完毕之后,在准备进入main()函数之前,会优先执行$Sub$$main()函数,该函数包含了RTT的初始化过程,如下图所示。 ![](https://cf01.ickimg.com/bbsimages/201911/9f10471ec78809a95ceaab5f97101272.jpg) 在rtthread_startup()函数中完成对RTT的所有初始化。 另外需要额外的说明,在rt_application_init()函数中,定义了一个“main”线程。 ![](https://cf01.ickimg.com/bbsimages/201911/c80e51351a8877b9becf7930c794c967.jpg) 这个main线程的入口函数是main_thread_entry(),就是我们的正主,main函数的跳转入口,$Super$$main()。 ![](https://cf01.ickimg.com/bbsimages/201911/888288fb7c8fc788ec8a58b69609ff08.jpg) 程序执行到rt_application_init()时,并没有真正意义上的执行到$Super$$main(),而是将含有$Super$$main()的这个任务线程放置到就绪状态。 最后,当程序执行到rt_system_scheduler_start()函数后,此刻任务调度器已经启动了,这个含有$Super$$main()的线程会立即得到执行,从而转入到我们的main函数。 ![](https://cf01.ickimg.com/bbsimages/201911/dc98a73a452722045ce1e0debed2bb58.jpg) 所以,这就是为什么,我们看到这个main()函数这么简洁的原因。 不用我多说,相信大家也知道这样设计的好处:尽最大的可能,保证hal库,与RTT的文件保持独立,又能很好的相互衔接。降低RTT的移植难度。 **Shell串口初始化** 这个串口也就是我使用Xshell5连接的调试串口,为什么我要单独的把它拿出来说?因为,在我们设计新的硬件的时候,由于布线方便的原因,有时候会使用其他的串口作为调试串口。 所以,针对这个串口的初始化,我重点了看了下RTT的调试串口初始化,方便以后项目中需要调整的时候,进行调整。 我也是找了很久才看明白RTT是如何初始化调试串口的。 在说RTT的调试串口初始化之前,我建议先看看单纯使用HAL库的时候,串口是如何进行初始化的,我做了截图,如下图所示: ![](https://cf01.ickimg.com/bbsimages/201911/3cf4b971e98ef819a5ccb685e0ebd97c.jpg) 在HAL库中,先对UartHandle结构体进行赋值,在HAL_UART_Init(&UartHandle)函数中完成串口引脚的初始化,和串口外设的配置(波特率、数据位等等)。 ![](https://cf01.ickimg.com/bbsimages/201911/0996c4bcfac1db8ad2448a1c5646ee0d.jpg) 好了,说到了这里,在回头RTT的代码吧!根据上文,RTT是在rt_hw_board_init()函数中的rt_hw_usart_init()函数中进行串口初始化。 ![](https://cf01.ickimg.com/bbsimages/201911/b99f6e18f73c8bdca1a25c32883af7e1.jpg) 在rt_hw_usart_init()函数中,需要重点注意stm32_uart_ops结构体 ![](https://cf01.ickimg.com/bbsimages/201911/cdaa394c6a571221978a7beb3c1421d6.jpg) 这个stm32_configure就是我们调试串口的初始化,至于这个.configure = stm32_configure的写法,意思是,将stm32_configure赋值给configure,这里我不多做解释。 继续查看stm32_configure函数,就可以看如下图所示: ![](https://cf01.ickimg.com/bbsimages/201911/1c67c3905319ee7f9ccbcad74436a381.jpg) 这里已经和单独使用HAL库,初始串口的流程一样了,在HAL_UART_Init(&uart->handle)函数中,将会对调试串口的引脚、以及外设参数进行配置。 **结语** 从RTT的代码中,能看到很对linux嵌入式开发的影子,同时,其又能和ST的HAL进行兼容与配套,如果有兴趣的朋友可以研究下,每当看了一段时间RTT的代码,不禁发出感叹“原来如此!”。 总之,学习RTT一定会让你有所收获!
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
川楠
擅长:单片机综合应用 硬件设计
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交