良许Linux教程网 干货合集 关于RT-Thread的启动问题

关于RT-Thread的启动问题

我们学习编程,特别是嵌入式编程,不仅仅要多写代码进行练习,还要多看看一些例程。最近在学习RT-Thread,原子的某例程的的主函数如下(这是在keil5下的截图):

image-20231011220959154
image-20231011220959154

这是主函数中的全部代码,主要是创建一个led线程并启动。那么问题来了,要点个灯,怎么也要进行led的硬件初始化吧?但是,在主函数中并没有发现有相关的初始化操作。那么其在哪进行初始化呢?按照我们以往的习惯,主函数就是用户程序的入口啊。难道还有其他入口?还真的有其他入口!这就涉及到RT-Thread的启动过程。

我们可以借助jlink仿真器进行硬件单步调试就可以知道程序的执行流程了。

首先,进入调试界面,并点击复位按钮光标就可以跳到程序开始运行的地方。如:

image-20231011221003299
image-20231011221003299

再次,一直点击单步运行按钮,直至光标运行到

BX      R0

这一行代码。此时,再点击单步运行按钮,并不会跳转到main.c中的main函数,而是会跳到component.c中的**$main**函数,该函数如下所示:

image-20231011221013269
image-20231011221013269

$main函数里主要是系统中断失能及调用系统启动函数(系统初始化)。

Super$$这两个符号是什么意思呢?在《RT-Thread内核实现与应用开发实战指南》这本书中有解释到:

RTThread 使用编译器(这里仅讲解 KEIL, IAR 或者 GCC 稍微有点区别,但是原理是一样的)自带的Super

main 可以在执行main 之前先执行,在Sub

main 来实现。

简单来说,**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线程:

image-20231011221017232
image-20231011221017232

main线程的线程函数为:

image-20231011221020013
image-20231011221020013

总结:Super$$是成对使用的。可以使用如下结构给函数进行扩展(打补丁):

extern void ExtraFunc(void); /* 用户自己实现的外部函数*/
void $Sub$function(void)
{
 ExtraFunc(); /* 做一些其它的设置工作 */
 $Super$function(); /* 回到原始的 function 函数 */
}

void function(void)
{
/* 函数实体 */
}

在执行 function 函数会先执行 function 的扩展函数,在扩展函数里面执行一些扩展的操作,当扩展操作完成后,最后必须调用Super$$function 函数通过它回到我们原始的 function 函数。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部