使用RTT studio 和Cubemx联合开发Alios Things_第三节:自动初始化机制

目录

  • 前言
  • 正文
  • 参考

前言

本文挖了挖自动初始化的实现,限于水平挖不到底,

正文

自动初始化很好用,不需要我们再去包含头文件调用函数,只要一句话cpu就会在特定的地方调用。自动初始化是6个宏。自动初始化的使用,官方的文档中心里是已经说的很明白了

初始化顺序 宏接口 描述
1 INIT_BOARD_EXPORT(fn) 非常早期的初始化,此时调度器还未启动
2 INIT_PREV_EXPORT(fn) 主要用于纯软件的初始化、没有太多依赖的函数
3 INIT_DEVICE_EXPORT(fn) 外设驱动初始化相关,比如网卡设备
4 INIT_COMPONENT_EXPORT(fn) 组件初始化,比如文件系统或者 LWIP
5 INIT_ENV_EXPORT(fn) 系统环境初始化,比如挂载文件系统
6 INIT_APP_EXPORT(fn) 应用初始化,比如 GUI 应用

我们就来捋一遍为什么一个宏就能让代码自动执行
这里牵涉到RTT的启动流程。

首先大家需要知道不同编译器对应的代码入口不同,

编译器 入口函数
__CC_ARM (Keil AC5) int $Sub$$main(void)
__CLANG_ARM (Keil AC6) int $Sub$$main(void)
__ICCARM__(IAR) int __low_level_init(void)
_GNUC_ (RTTstudio GCC) int entry(void)

RTThread将这些函数全部实现为调用rtthread_startup函数。所以,rtthread_startup函数是所有RTT工程的入口。rtthread_startup函数内容如下(有删减)

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();

    /* create init_thread */
    rt_application_init();

    /* timer thread initialization */
    rt_system_timer_thread_init();

    /* idle thread initialization */
    rt_thread_idle_init();

    /* start scheduler */
    rt_system_scheduler_start();

    /* never reach here */
    return 0;
}

可以看到,直到最后,RTThread才开启调度器,在此之前系统一直是未运行的状态。
依次找到rt_hw_board_init() -> rt_components_board_init() 内容如下
使用RTT studio 和Cubemx联合开发Alios Things_第三节:自动初始化机制_第1张图片
可以看到,在这里使用函数指针执行了从__rt_init_rti_board_start在内存中的位置A到__rt_init_rti_board_end在内存中的位置B,A到B中的所有函数。我们可以猜测到RTT自动初始化宏的作用就是将函数指针放到AB之间连续的位置,我们可以尝试操作一下,然后翻一翻map文件看看,编写以下代码,放到main.c末尾

int fun_BOARD(void){return RT_EOK;}
int fun_PREV(void){return RT_EOK;}
int fun_DEVICE(void){return RT_EOK;}
int fun_COMPONENT(void){return RT_EOK;}
int fun_ENV(void){return RT_EOK;}
int fun_APP(void){return RT_EOK;}

INIT_BOARD_EXPORT(fun_BOARD);
INIT_PREV_EXPORT(fun_PREV);
INIT_DEVICE_EXPORT(fun_DEVICE);
INIT_COMPONENT_EXPORT(fun_COMPONENT);
INIT_ENV_EXPORT(fun_ENV);
INIT_APP_EXPORT(fun_APP);

之后在工程目录中搜索后缀为 .map 的文件,打开后可以找到下图中的内容
使用RTT studio 和Cubemx联合开发Alios Things_第三节:自动初始化机制_第2张图片
我们可以发现,我们写的6个测试函数都被放到了连续的内存之中,验证了我们之前的猜测。那么为什么可以这样呢?我们对任意一个宏go to definition
使用RTT studio 和Cubemx联合开发Alios Things_第三节:自动初始化机制_第3张图片
可以看到他们调用的都是INIT_EXPORT宏,对它go to definition可以看到
在这里插入图片描述
看到这里不用慌,首先前面的RT_USED和const我们不用看,init_fn_t是一个函数指针类型
go to definition看到
在这里插入图片描述
是一个返回值为int,形参为void的函数指针类型。所以可以看出INIT_EXPORT其实就是在定义函数指针,这个函数指针的类型是 init_fn_t,名称是 __ rt_init_##fn,就是__rt_init_+fn名称。比如我们写INIT_BOARD_EXPORT(fun_BOARD);,函数指针就是__rt_init_fun_BOARD,从.map文件里也可以看到确实是这样。而这个函数指针本身的位置,靠SECTION(".rti_fn." level)指定。SECTION定义如下
在这里插入图片描述
__attribute__就是指定内存位置用的,而其参数section(x)已经不能再go to definition了。
就到此为止吧。函数指针指向的内容就是fn,也就是我们传入的函数。
总结一下
1,自动初始化里的函数必须符合init_fn_t指针形式,否则会报警告。比如

int fun(void)
{
    /*do something*/
	return RT_EOK;
}

2,自动初始化所有的宏都是在一处初始化,执行顺序见表,都是在系统运行前执行。

参考

链接: _Doon。 stm32 函数段使用

你可能感兴趣的:(单片机,stm32,c语言)