文章目录
1. RT-thread启动流程
我们先来看RT-thead的启动流程,其在rt_components_board_init()和rt_components_init()分别对RT-Thread定义的7个等级的初始化函数按顺序进行了自动初始化。
2. 自动初始化原理
2.1 基本原理
自动初始化的实现方式是通过将初始化函数放在同一个内存段,内存段内存储类型一致的全局变量,全局变量保存有初始化函数入口(如全局变量为一个函数指针变量),然后在逐个遍历该内存段中的全局变量(函数指针)来调用初始函数。
2.2 段内存布局
我们使用keil编译成功,打开内存布局文件*.map,从里面我们可以看到rtt等级0初始化的内存段布局。map内存布局文件目录位于:board\build\keil\List
2.3 定义初始化内存段
如下代码定义了一个全局变量,该全局变量为一个类型为 init_fn_t的函数指针变量,放置在.rti_fn.xxx段。
RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
2.4 自启动初始化函数注册
RT-thread根据系统启动阶段不同,将初始化划分为7个等级,用户可使用的等级1-6,其具体注册接口如下,我使用对应的注册接口即可将自定义初始化函数进行注册
3. 自启动初始化是如何按等级依次进行的?
RT-thread巧妙利用了编译器默认按单词顺序,在内存布局中对各内存段进行链接排序,keil中我们也可以使用–sort=algorithm进行配置,RT-thread各等级初始化内存段布局如下:
4. 自启动初始化函数什么时候调用?
从RT-thread官文文档或代码我们可以知道,自启动初始函数分成了两步调用:
4.1 第1步(系统调度器启用前)
在系统调度器启动前,先进行等级0,等级1(板级硬件)的初始化,代码如下:
void rt_components_board_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
{
(*fn_ptr)();
}
#endif
}
4.2 第2步(系统调度器启用后)
系统启动后,系统按等级顺序依次进行初始化,代码如下:
void rt_components_init(void)
{
#if RT_DEBUG_INIT
int result;
const struct rt_init_desc *desc;
rt_kprintf("do components initialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
result = desc->fn();
rt_kprintf(":%d done\n", result);
}
#else
const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
{
(*fn_ptr)();
}
#endif
}