1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。关注微信公众号【嵌入式大杂烩】,回复1024,即可免费获取!
最近在学习RT-Thread,原子的某例程的的主函数如下(这是在keil5下的截图):
这是主函数中的全部代码,主要是创建一个led线程并启动。那么问题来了,要点个灯,怎么也要进行led的硬件初始化吧?但是,在主函数中并没有发现有相关的初始化操作。那么其在哪进行初始化呢?按照我们以往的习惯,主函数就是用户程序的入口啊。难道还有其他入口?还真的有其他入口!这就涉及到RT-Thread的启动过程。
我们可以借助jlink仿真器进行硬件单步调试就可以知道程序的执行流程了。
首先,进入调试界面,并点击复位按钮光标就可以跳到程序开始运行的地方。如:
再次,一直点击单步运行按钮,直至光标运行到
BX R0
这一行代码。此时,再点击单步运行按钮,并不会跳转到main.c中的main函数,而是会跳到component.c中的$Sub$$main函数,该函数如下所示:
$Sub$$main函数里主要是系统中断失能及调用系统启动函数(系统初始化)。
$Sub$$与$Super$$这两个符号是什么意思呢?在《RT-Thread内核实现与应用开发实战指南》这本书中有解释到:
RTThread 使用编译器(这里仅讲解 KEIL, IAR 或者 GCC 稍微有点区别,但是原理是一样的)自带的$Sub$$和$Super$$这两个符号来扩展了 main 函数,使用$Sub$$main 可以在执行main 之前先执行$Sub$$main,在$Sub$$main 函数中我们可以先执行一些预操作,当做完这些预操作之后最终还是要执行 main 函数,这个就通过调用$Super$$main 来实现。
简单来说,$Sub$$和$Super$$具有补丁功能,可以给一些函数打上“补丁”,如RT-Thread的内核文件component.c中就给我们的用户主函数main打上了”补丁“。
在rtthread_startup函数中:主要实现了板级初始化(如led的初始化,串口初始化就是在这里边调用的);打印RT-Thread的logo和版本信息;初始化系统定时器;初始化调度器;创建application初始化线程(这里将用户main函数作为一个线程,用户main里面是空的);初始化软件定时器;创建空闲线程;启动系统调度(启用调度后,main函数就会参与调度开始运行)。如:
int rtthread_startup(void) { rt_hw_interrupt_disable(); /* board level initialization * 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 */ rt_system_scheduler_init(); #ifdef RT_USING_SIGNALS /* signal system initialization */ rt_system_signal_init(); #endif /* create init_thread */ rt_application_init(); /* timer thread initialization */ rt_system_timer_thread_init(); /* idle thread initialization */ rt_thread_idle_init(); #ifdef RT_USING_SMP rt_hw_spin_lock(&_cpus_lock); #endif /*RT_USING_SMP*/ /* start scheduler */ rt_system_scheduler_start(); /* never reach here */ return 0; }
rt_application_init函数中创建了一个main线程:
main线程的线程函数为:
总结:$Sub$$和$Super$$是成对使用的。可以使用如下结构给函数进行扩展(打补丁):
extern void ExtraFunc(void); /* 用户自己实现的外部函数*/ void $Sub$function(void) { ExtraFunc(); /* 做一些其它的设置工作 */ $Super$function(); /* 回到原始的 function 函数 */ } void function(void) { /* 函数实体 */ }
在执行 function 函数会先执行 function 的扩展函数$Sub$$function,在扩展函数里面执行一些扩展的操作,当扩展操作完成后,最后必须调用$Super$$function 函数通过它回到我们原始的 function 函数。
相关资料:
《RT-Thread内核实现与应用开发实战指南》、
https://blog.csdn.net/yang1111111112/article/details/80913001