网站推广策划执行方案,郑州短视频代运营公司,机械设计师接私活的网站,郑州企业健康码二维码怎么申请一、简介 上一章#xff0c;我们已经了解了如何通过MDK来移植RTT#xff0c;不熟悉的可以看如下链接#xff1a;RTThread-Nano学习一-基于MDK移植-CSDN博客本章我们就来继续了解一下#xff0c;RTT的启动流程。
二、启动流程 官方给了一幅非常清晰的启动流程图我们已经了解了如何通过MDK来移植RTT不熟悉的可以看如下链接RTThread-Nano学习一-基于MDK移植-CSDN博客本章我们就来继续了解一下RTT的启动流程。
二、启动流程 官方给了一幅非常清晰的启动流程图可以看下 使用 MDK来开发的芯片大部分都是从startip_XXX.s开始。 程序在这里开始启动这里本来是要调用main函数的但是RTT添加了$Sub$$main函数。该功能是MDK特有的可以在main函数之前补充一些其他函数。最后通过$Super$$main来调用真正的main函数。 全局搜索一下$Sub$$main函数。 可以看到在components.c中找到了$Sub$$main。该函数调用了rtthread_startup。在进入看一下。 可以看到这里面调用了一堆函数这里用中文备注一下这些函数。
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();/* 由此创建一个用户 main 线程 */rt_application_init();/* 定时器线程初始化 */rt_system_timer_thread_init();/* 空闲线程初始化 */rt_thread_idle_init();/* 启动调度器 */rt_system_scheduler_start();/* 不会执行至此 */return 0;
}需要注意的是很多文件是只读属性开发者只能看无法修改。只有board.c和rtconfig,h两个文件是可以修改的。 可以看到在关闭中断后首先运行的就是rt_hw_board_init()函数。这个函数是不是看着有点眼熟没错这个函数就是在移植系统是要操作的函数在该函数中必须要给系统提供底层节拍。 在看一下rt_application_init()函数。 该函数创建了main线程但是没有运行。看一下这个main线程。 在这里找到了$Super$$main函数。 那什么时候调用main线程呢 再看rt_system_scheduler_start()函数。 这里之后就跳转到我们自己的main函数中开始执行。 那总结一下 rtthread_startup()函数总体可以分为4个部分。 1初始化与系统相关的硬件。rt_hw_board_init 2初始化系统内核对象例如定时器、调度器、信号量rt_system_timer_init、rt_system_scheduler_init 3创建main线程。rt_application_init 4初始化定时器线程、空闲线程并启动调度器rt_system_timer_thread_init、rt_thread_idle_init、rt_system_scheduler_start。 注 创建的线程在rt_thread_startup()执行后并不会立马执行他们会处于就绪状态等待系统调度直到rt_system_scheduler_start调度器被调用后才会开始执行。在启动调度器后系统会转入第一个线程开始执行根据调度规则选择的是就绪队列中优先级最高的线程。
三、自动初始化机制 RTT提供了一种自动初始化机制来满足用户在对外设初始化时的运行顺序的需求。 自动初始化机制是指初始化函数不需要被显性调用只需要在函数定义处通过宏定义的方式进行申明就会在系统启动过程中被执行。 该机制主要涉及以下宏定义
INIT_BOARD_EXPORT(fn)非常早期的初始化此时调度器还未启动 INIT_PREV_EXPORT(fn)主要是用于纯软件的初始化、没有太多依赖的函数 INIT_DEVICE_EXPORT(fn)外设驱动初始化相关比如网卡设备INIT_COMPONENT_EXPORT(fn)组件初始化比如文件系统或者 LWIP INIT_ENV_EXPORT(fn) 系统环境初始化比如挂载文件系统 INIT_APP_EXPORT(fn)应用初始化比如 GUI 应用 那这些定义是在哪里执行呢 执行位置对应如下
宏定义执行位置INIT_BOARD_EXPORT(fn)board init functions INIT_PREV_EXPORT(fn)pre-initialization functions INIT_DEVICE_EXPORT(fn)device init functionsINIT_COMPONENT_EXPORT(fn)components init functions INIT_ENV_EXPORT(fn) enviroment init functions INIT_APP_EXPORT(fn)application init functions 这里以实际的例子来演示一下 在rt_components_board_init()函数前后各加一行打印。main函数如下 打印结果 可以看到main函数在最后才调用并且sys_init最后被调用。 接下来使用INIT_BOARD_EXPORT函数将sys_init的执行提前。 可以看到sys_init已经出现在了rt_components_board_init中与官方图对应。 可能会有人问这么做的意义是什么 上面已经介绍过了最后执行main实际上是创建了一个main任务既然是任务那就一定会有栈的分配查看一下main任务的栈是多少。 可以看到main线程的栈大小是256。 如果程序要初始化的东西不多那确实可以把sys_init放在main任务中执行。但是如果系统初始化的东西很多如果都放在main任务中执行那么很有可能会造成main任务的栈溢出导致整个程序崩溃。所以如果要初始化的东西比较多且种类很多的时候就可以通过自动初始化的方式来在不同的位置进行外设的初始化。