1.前言
RT-Thread 是一个集实时操作系统(RTOS)内核、中间件组件和开发者社区于一体的技术平台,由熊谱翔先生带领并集合开源社区力量开发而成,RT-Thread 也是一个组件完整丰富、高度可伸缩、简易开发、超低功耗、高安全性的物联网操作系统。RT-Thread 具备一个 IoT OS 平台所需的所有关键组件,例如GUI、网络协议栈、安全传输、低功耗组件等等。经过11年的累积发展,RT-Thread 已经拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量超过6亿台,成为国人自主开发、国内最成熟稳定和装机量最大的开源 RTOS。
大部分初学者都是从裸机程序开发进入 STM32 单片机开发以及 Cortex-M 系列内核开发的,裸机程序的开发具有相当难度,入门过程当中的痛苦,我想各位开发者应该深有体会。当然掌握了裸机开发,意味着你对单片机的各个内部模块外设的功能和配置了如指掌了,为实践项目的开发奠定了非常重要的基础。随着项目变得更加的多样和庞大,这时候嵌入式操作系统的作用或优势将显得格外突出了。
举一个不恰当的例子,裸机开发好比自己组一个团队盖楼房,嵌入式操作系统开发项目相当于大型的建筑公司盖房。当只需要盖一座两层的小楼时,我们的小团队可以完全可以胜任,当需要盖一个有几十栋甚至上百栋房子的小区时,就心有余而力不足了。这时候建筑公司的专业团队,分工合作优势尤其明显。开发过程中引入操作系统的目的无非就是解放劳动力,提高生产效率。因此,开发的项目越来越庞大,嵌入式操作系统将成为开发过程必不可少的工具。
使用操作系统进行项目开发前,必须具备以下两个基本技能。第一,掌握操作系统各个核心组件的使用。第二,掌握操作系统内核工作原理及源码具体实现。掌握第一点基本可以开始项目开发,但作为开发者掌握第二点是必不可少的。毕竟实际项目的开发是一个持续的过程,一般都不是一次性的,涉及到产品的调试、维护、升级等工作,产品出现问题时,只有掌握了第二点,才能够快速的、高效率的解决问题。基于上述原因,本系列内容将逐一剖析国产嵌入式操作系统 RT-Thread 各个内核对象,并以 STM32F103xx 系列单片机作为硬件平台。
本节将解析 RTT(RT-Thread) 的启动流程。
2.裸机程序启动流程
众所周知,裸机程序开发过程中,任何一个项目都有唯一的一个 main 函数!它是项目的唯一入口函数,即从 main 函数开始执行程序代码。所谓的启动过程是指,从单片机上电起至进入 main 函数之前的运行过程。启动流程如下:
1.单片机上电;
2.单片机上电后,马上进入复位中断函数 Reset_handler,如下汇编代码所示;
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
3.如上述代码所示,在函数 Reset_handler 中首先进入系统初始化函数 SystemInit,该函数中完成单片机时钟初始化,为单片机启动做好准备;
4.随后,进入 __main 函数执行,执行完该函数后,将退出复位中断函数 Reset_Handler,进入用户 main 函数执行,至此,便完成了整过启动过程。
值得注意的是,此处的 __main 并不是用户 main 函数,初学者经常容易混淆。__main 函数由编译器自动创建,实现单片机的堆栈初始化及数据域的加载,为用户程序的执行做好准备,总而言之只有执行完了 __main 函数之后,才会自动跳转至用户 main 函数开始执行。
3. RTT 程序启动流程
RTT 启动流程和裸机启动流程基本一致,唯一的区别为在 __main 函数与 main 之间需要完成 RTT 操作系统的初始化。那么在 main 函数之前是如何实现 RTT 初始化的呢? RTT 团队巧妙的利用 MDK 的 submain() 和 suppermain()功能函数。定义了上述函数后,在进入 main 函数之前,先进入 submain() 执行,在该函数末尾调用 suppermain()函数便可回到 main 函数执行。因此,只需要将 RTT 系统初始化放在 submain() 函数中即可,如下代码所示:
int $Sub$$main(void)
{
rt_hw_interrupt_disable(); //关闭所有中断,防止影响 RTT 操作系统初始化
rtthread_startup(); //RTT 操作系统初始化
return 0;
}
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initalization
* 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 */
/* 1.初始化各优先级的线程链表
2.初始化僵尸线程链表
3.初始化当前线程为空
4.初始化当前线程优先级为31,即MAX-1*/
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* signal system initialization */
rt_system_signal_init();//信号量初始化,后续分析
#endif
/* create init_thread */
/*1.用户应用程序初始化rt_application_init()
1.1定义一个线程控制块结构体指针变量tid=&main_thread
1.2创建main线程rt_thread_init()
1.2.1检查线程指针是否初始化,检查栈开始是否不为0
1.2.2线程对象初始化rt_object_init()
1.2.3.1获取对象信息,属于线程对象information = rt_object_get_information(type);
1.2.3.2设置对象类型为静态对象object->type = type | RT_Object_Class_Static;
1.2.3.3把main线程控制块main_thread->list插入到对象容器information->object_list中;rt_list_insert_after(&(information->object_list), &(object->list));
1.2.3线程其他参数初始化_rt_thread_init()
1.2.3.1初始化线程栈,线程链表
1.2.3.2初始化线程其他参数
1.3启动main线程rt_thread_startup()
***********************************************/
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();
/* idle thread initialization */
rt_thread_idle_init();
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
/* the system main thread */
void main_thread_entry(void *parameter)
{
extern int main(void);
extern int $Super$$main(void);
/* RT-Thread components initialization */
rt_components_init();
/* invoke system main function */
#if defined (__CC_ARM)
$Super$$main(); /* for ARMCC. */
#elif defined(__ICCARM__) || defined(__GNUC__)
main();
#endif
}
int main(void)
{
return 0;
}
111