本文参考RT-Thread官方文档中心和RT-Thread创始人熊谱翔编写的《嵌入式实时操作系统:RT-Thread设计与实现》,官网给的资料很详细,书中和官网给的文档也一样。作这系列文章目的是加深学习印象。
在运行有RT-Thread操作系统的设备中,main()是用户程序入口,操作系统会启动一个主线程模块运行之。在运行主线程之前,需要先进行系统的初始化。故系统的一般启动顺序是 启动文件 → 在函数rtthread_startup()中实现系统的初始化 → 用户入口main()函数。
我们使用ARM官方提供的 $Sub$$
和 $Super$$
补丁功能在main()之前进行系统初始化,官方给的解释如下:
$Super$$foo:标识原始未打补丁的函数foo()。直接用这个调用原始函数。
$Sub$$foo:标识被调用的新函数,而不是原始函数foo()。使用这个在原始函数之前增加一些功能处理。
void $Sub$$foo(void)
{
ExtraFunc(); /* 做一些额外的准备工作,本文指系统初始化 */
$Super$$foo(); /* 调用原始的foo()函数 */
}
对应的RT-Thread源码components.c中的代码:
extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
rtthread_startup()是RT-Thread规定的统一启动入口,主要进行系统一系列初始化。它的流程图如下:
它的代码如下:
int rtthread_startup(void)
{
/* 关闭中断 */
rt_hw_interrupt_disable();
/* 板级初始化:需要在该函数内进行系统堆的初始化 */
rt_hw_board_init();
/* 打印RT-Thread版本信息 */
rt_show_version();
/* 定时器初始化 */
rt_system_timer_init();
/* 调度器初始化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 信号初始化 */
rt_system_signal_init();
#endif
/* 由此创建一个用户main()线程 */
rt_application_init();
/* 定时器线程初始化 */
rt_system_timer_thread_init();
/* 空闲线程初始化 */
rt_thread_idle_init();
/* 启动调度器 */
rt_system_scheduler_start();
/* 不会执行到此 */
return 0;
}
这部分启动代码大致可以分为4个部分:
(1)初始化与系统相关的硬件;
(2)初始化系统内核对象,例如定时器、调度器、信号;
(3)创建main线程,在main线程中对各类模块依次进行初始化;
(4)初始化定时器线程、空闲线程,并启动调度器。
上述步骤执行完后,系统会跳转到用户程序入口main()上,我们就可以在其中添加我们所需的代码了。
运行main()函数的线程是主线程,我们还可以创建自己的线程以供实时性操作。