设为首页 加入收藏

TOP

源码解读·RT-Thread操作系统从开机到关机(三)
2019-08-27 07:20:57 】 浏览:105
Tags:源码 解读 RT-Thread 操作系统 开机 关机
return 0; }
以上代码我们主要脉络是这样的:先关闭全局中断->初始化硬件板上的资源->打印RT-Thread的LOGO->系统定时器功能初始化->调度器初始化->signal功能初始化->应用程序初始化(这个通常是用来创建用户任务的)->系统软timer任务初始化->系统idle任务初始化->启动调度器,永远不再返回。

这里我们先来说一下为什么要先关闭全局中断,因为在初始化过程中,有可能MCU就有其它的中断和异常触发了,这个时候系统还没有初始化完成,这就势必导致系统出现故障,所以先关闭全局中断,并在启动调度器后再打开。

rt_hw_board_init非常关键,在这个函数里面必须完成一些必须的初始化过程:堆内存系统的初始化和硬件资源模块以及如果开启了自动初始化组件时还需要调用rt_components_board_init完成必要的初始化,这个函数是自动初始化组件的一个接口。(代码摘录自bsp\stm32\libraries\HAL_Drivers\drv_common.c)

RT_WEAK void rt_hw_board_init()
{
#ifdef SCB_EnableICache
    /* EnableI-Cache---------------------------------------------------------*/
    SCB_EnableICache();
#endif
 
#ifdef SCB_EnableDCache
    /* Enable D-Cache---------------------------------------------------------*/
    SCB_EnableDCache();
#endif
 
    /* HAL_Init() function is called at thebeginning of the program */
    HAL_Init();
 
    /* System clock initialization */
    SystemClock_Config();
    rt_hw_systick_init();
 
    /* Heap initialization */
#if defined(RT_USING_HEAP)
    rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
#endif
 
    /* Pin driver initialization is open bydefault */
#ifdef RT_USING_PIN
    rt_hw_pin_init();
#endif
 
    /* USART driver initialization is openby default */
#ifdef RT_USING_SERIAL
    rt_hw_usart_init();
#endif
 
    /* Set the shell console output device*/
#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
 
    /* Board underlying hardwareinitialization */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
}
然后回到rtthread_startup函数中再看rt_application_init函数,由于我们是用的stm32的BSP,这个bsp系列是使用自动初始化组件和RT_USING_USER_MAIN功能的,所以过程稍微隐蔽一些,先是在rt_application_init中创建了一个小任务,然后再在小任务中调用了rt_components_init,这也是自动初始化组件的接口。如果没有开启自动初始化组件的话,通常我们的用户任务可以在rt_application_init中创建了。也可以像这里的实现一样,先创建一个小任务,然后再在小任务里完成一些初始化和创建用户任务。

然后再回到rthtread_startup中看到有初始化软timer和idle任务的,其中软件timer功能是可以通过裁剪配置选择的,如果打开后就可以在后续创建softtimer。否则所有的timer都会在OS TICK的中断上下文中计时。另外这个idle任务也是系统中必不可少和优先级最低的任务。即使我们启动调度器后没有创建任何用户任务,系统中也有一个idle任务在运行。Idle任务的优先级最低,在此我建议开发人员最好不要将自己的用户任务优先级配置成最低以免和idle竞争时间片,这会给你今后的开发带来不必要的麻烦。关于这个问题,我最后会提出一些新的设计构想。不过这里先要介绍一下idle任务的功能。Idle任务会在系统空闲时被调度运行,所以我们通常在idle任务里做低功耗设计。其次idle任务里还会完成系统资源的回收。例如被删除的任务,被删除的module等。

最后rthtread_startup启动调度器rt_system_scheduler_start开始调度系统的任务,从此就开始运行任务,不再返回。这里又要记住一个概念,在上文提到的PSP和MSP,到目前为止MCU还是使用一开始中断向量表中指定的MSP栈。但是当调度任务后,任务会有自己的栈,且rt-thread系统会将任务的栈切换到PSP栈指针。值得注意的是,这个MSP是全局共享的,所有的中断程序都会使用这个栈空间,所以我们需要根据自己的情况来配置这个MSP栈的空间大小。

接下来我们再来介绍自动初始化组件。RT-Thread中的自动初始化组件思路来自于Linux内核。其实现手段是将需要初始化的函数接口通过链接器指令放在特殊的section中。这个section的概念是当我们程序最终链接成一个image后会形成一个标准格式的文件,其中armcc中叫做ARM ELF。详细的介绍可以查阅官方资料。其中ELF文件就有将代码分成称为section的区域,可以称作段。并且可以指定自己的代码放在指定名称的段中,且可以指定这个section段的ROM地址。这样当我们设计玩初始化接口后,通过链接器的指令以及链接脚本文件将我们的初始化代码放在特定的地方,并且利用命名规则来做到顺序排序。等需要调用初始化的时候可以利用这些section的地址转换成函数指针直接批量循环调用。通常你会在MDK的工程文件链接器参数中看到这样的指令:--keep *.o(.rti_fn.*),这是为了在链接阶段保证这些自定义段不被删除。同时也可以看出rti_fn就是自动初始化组件的section名字。类似的将函数放置在这些段中的链接器指令如下:(摘录自rtdef.h)

/*initialization export */
#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER/* we do notsupport MS VC++ compiler *
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇解决SDL/SDL.h: No such file or .. 下一篇初级模拟电路:3-2 BJT的工作原理

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目