在野火的i.MX RT 1052 MINI开发板的资料中,对于RT-Thread的支持无疑是其RT1052开发板的最大亮点,接下来我们一起结合野火的RT-Thread例程分析一下RT-Thread的启动过程。
在野火的资料文档中"0-野火【i.MX RT1052 MINI 开发板】资料\3-程序源码\2-RT-Thread-Fire-RT1052\RT-Thread-Fire-RT1052"目录是RT-Thread相关代码。
在该文件夹中除了三个说明文档,有四个文件夹,分别对应了RT-Thread的文件系统,图形,网络例程和基本的内核例程。
首先从最简单的基本内核例程开始,例程的Keil工程。
打开工程后,找到startup_MINXRT1052.s,这个汇编文件是1052的启动文件,系统一般都是从复位开始的,这里找到复位处理代码,在L325设置断点,然后进入调试状态。
点击复位按钮,使系统复位,此时系统在startup_MINXRT1052.s的L325设置的断点处停止了,这样就可以通过单步调试的方式跟踪系统执行的过程了。
接下来简单分析一下这里的汇编代码:
Reset_Handler PROC ;子程序开始
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
CPSID I ; 关闭中断
LDR R0, =0xE000ED08 ;将中断向量表偏移寄存器的地址值加载到R0寄存器
LDR R1, =__Vectors ;将中断向量地址加载到R1寄存器
STR R1, [R0] ;将R1的值存储到R0所指向的地址中。至此设置中断向量偏移地址完成。
LDR R2, [R1] ;将R1地址中的值存储到R2中
MSR MSP, R2 ;把R2寄存器的数据写入到状态寄存器
LDR R0, =SystemInit ;把系统初始化函数SystemInit的地址加载到R0寄存器
BLX R0 ;跳转到R0寄存器所在地址,也就是执行SystemInit函数。
CPSIE i ;开中断
LDR R0, =__main ;把__main函数的地址加载到R0寄存器
BX R0 ;跳转到R0寄存器所在地址,也就是执行__main函数
ENDP;子程序结束
这段汇编代码实现了在复位后,首先调用SystemInit初始化系统,然后条用__main函数。
接下来我们看看SystemInit函数。这个函数是在system_MIMXRT1052.c中的。
在SystemInit函数中,首先设置了FPU相关寄存器,然后禁用了看门狗,禁用SysTick,使能数据缓存和指令缓存。
函数最后调用了rt_lowlevel_init()函数,着就正式进入了RTT的初始化。
rt_lowlevel_init()函数在board.c中实现,这个文件就是RT-Thread针对特定硬件环境的配置文件了。
函数中首先配置了MPU,然后初始化了sdram。
接下来分析一下__main函数,__main函数是C/C++运行时库的一个函数,嵌入式系统在进入应用主程序之前必须有一个初始化的过程,使用__main标号引导系统时必须将应用程序的入口定义为main()。
在调试状态,鼠标移动到__main函数上时,提示函数所在地址为0x60002400。
在汇编窗口右击,菜单中选择show Disassembly at Address。
窗口中输入0x60002400后点击Go To,就可以跳转到该地址了。
在__main函数中会调用__rt_entry函数。
调用__rt_entry_man。最终调用$Sub$$main函数。
此函数在文件components.c中。
$Sub$$是Keil所使用的_CC_ARM编译器的特有模式,用于有一个已经存在且不能被改变的函数的情况。使用这个模式可以帮原函数打补丁。
在$Sub$$main函数中调用了rtthread_startup()。
此函数是RT_Thread的入口函数,在这里实现了RT-Thread的几乎所有启动过程。
首先调用了rt_hw_board_init()函数进行板级初始化。
主要实现了设置时钟,配置滴答定时器,各个组件和控制台设置。
在rt_show_version()函数中,打印了RT-Thread的Logo和版本信息。
在rt_system_timer_init()函数中初始化了定时器。
在rt_system_scheduler_init()函数中初始化任务调度器。
在rt_application_init()函数中创建了main_thread_entry任务,任务中调用了$Super$$main()。
$Super$$main()将直接调用用户的main函数。
在rt_system_timer_thread_init()函数中初始化软件定时器;
在rt_thread_idle_init()函数中初始化并创建空闲任务。
在rt_system_scheduler_start()函数中开启任务调度器,开启任务调度器之后,main函数会参与调度。
至此,RT-Thread的启动过程分析完成。
总结:RT-Thread作为国产的RTOS,发展的越来越成熟,也是笔者用到的除了FreeRTOS外另一个优秀的嵌入式操作系统,再配合NXP的跨界处理器i.MX RT1052,甚至可以胜任之前部分入门级MPU所做的工作。再配合I.MX超高的性价比,一定会在更多的领域一展拳脚。