RTT学习之启动流程

2年前 (2022) 程序员胖胖胖虎阿
366 0 0
  1. 总结RT-Thread的启动流程。
  2. 非运行时与运行时的image文件分别是什么样的,请画下来。是谁将 RW 段中的  RW-data(初始化的全局变量)搬运到 RAM 中?
  3. MDK环境下各种数据段存储的什么数据?
  4. 在RT-Thread启动时,关了中断,那么在什么时候开启的中断?
  5. 总结自动初始化原理。
  6. 总结BSP制作过程。

1RT-Thread启动流程

RTT学习之启动流程

 

 RTT学习之启动流程

 

 

 

 

这部分启动代码,大致可以分为四个部分:

(1) 初始化与系统相关的硬件;

(2) 初始化系统内核对象,例如定时器、调度器、信号;

(3) 创建 main 线程,在 main 线程中对各类模块依次进行初始化;

(4) 初始化定时器线程、空闲线程,并启动调度器。

启动流程中蓝色部分是自动初始化的数据段,使用自动初始化宏导出的函数放置到相应的数据段,在启动流程中对函   数进行遍历初始化。2、加载时地址与运行时地址映射

image文件

RTT学习之启动流程

 

 RTT学习之启动流程

 

 

 STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM 中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零。

分散装载配置文件里会有配置,关于code的地址,有两个设置,一个是存储地址(这个地址配置的是烧写器把代码  段写到flashrom的何处),一个是装载运行地址,也就是你程序在什么地方运行

RTT学习之启动流程

【如果想要深入了解的话,可以看看arm的连接器手册,或者是《ARM体系结构与编程》中也讲到了】

 

3MDK环境下各种数据段存储的什么数据?

code:代码段,存放程序

RO:只读数据段,存放程序中定义的常量RW:读写数据段,存放非0全局变量

ZI:0数据段,存放未初始化的全局变量与初始化为0的变量

MDK 在编译完成之后

Total RO Size (Code + RO Data) 53668 ( 52.41kB) Total RW Size (RW Data + ZI Data) 2728 ( 2.66kB)

Total ROM Size (Code + RO Data + RW Data) 53780 ( 52.52kB)

1) RO Size 包含了 Code  RO-data,表示程序占用 Flash 空间的大小;

2) RW Size 包含了 RW-data  ZI-data,表示运行时占用的 RAM 的大小;

3) ROM Size 包含了 Code、RO Data 以及 RW Data,表示烧写程序所占用的 Flash 空间的大小;

4、在RT-Thread启动时,关了中断,那么在什么时候开启的中断?

在启动调度器,切换到第一个线程时开启的中断【直接使用CPSIE I 开了中断的】。代码详见:

rt_system_scheduler_start() rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);

RTT学习之启动流程

 

 

 5、总结自动初始化原理。

RT-Thread 的自动初始化机制使用了自定义 RTI  符号段,将需要在启动时进行初始化的函数指针放到了该段中,形成一张初始化函数表,在系统启动过程中会遍历该表,并调用表中的函数,达到自动初始化的目的。

用来实现自动初始化功能的宏接口定义详细描述如下表所示:

 

初始化顺序

宏接口

描述

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 应用

 

初始化函数主动通过这些宏接口进行申明,如 INIT_BOARD_EXPORT(rt_hw_usart_init),链接器会自动收集所有被申明的初始化函数,放到 RTI 符号段中,该符号段位于内存分布的 RO 段中,该 RTI 符号段中的所有函数在系统初始化时会被自动调用。

原理:

在rtdef.h中,使用SECTION(x)定义: 

#define SECTION(x)  attribute ((section(x)))

     attribute ((section("name"))):将作用的函数或数据放入指定名为"name"的输入段中。(在不同的编译器中实现的方式也有所不同。)

将SECTION(".rti_fn."level)使用 INIT_EXPORT(fn, level) 这个宏进行定义,fn是函数  

#define INIT_EXPORT(fn, level)  RT_USED const init_fn_t rt_init_##fn SECTION(".rti_fn."level) = fn

分段:

RTT学习之启动流程

 compnents.c中:

static int rti_start(void)
{
return 0;
}
INIT_EXPORT(rti_start, "0");


static int rti_board_start(void)
{
return 0;
}
INIT_EXPORT(rti_board_start, "0.end");


static int rti_board_end(void)
{
return 0;
}
INIT_EXPORT(rti_board_end, "1.end");


static int rti_end(void)
{
return 0;
}
INIT_EXPORT(rti_end, "6.end");

所以就有: 

段名

函数指针/

.rti_fn.0

    rt_init_rti_start

.rti_fn.0.end

    rt_init_rti_board_start

.rti_fn.1

INIT_BOARD_EXPORT(fn)

.rti_fn.1.end

    rt_init_rti_board_end

.rti_fn.2

INIT_PREV_EXPORT(fn)

.rti_fn.3

INIT_DEVICE_EXPORT(fn)

.rti_fn.4

INIT_COMPONENT_EXPORT(fn)

.rti_fn.5

INIT_ENV_EXPORT(fn)

.rti_fn.6

INIT_APP_EXPORT(fn)

.rti_fn.6.end

    rt_init_rti_end

非调试模式下rt_components_board_init():for循环会遍历位于 rt_init_rti_board_start 到

     rt_init_rti_board_end 之间保存的函数指针,然后依次执行这些函数

void rt_components_board_init(void)
{
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
}

非调试模式下rt_components_init():for循环会遍历位于  rt_init_rti_board_end 到  rt_init_rti_end 之间保存的函数指针,然后依次执行这些函数

void rt_components_init(void)
{
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
}

举例:

main函数中添加了函数pin_beep_sample(),并使用INIT_APP_EXPORT()进行自动初始化。  

INIT_APP_EXPORT(pin_beep_sample);

那么,展开为:

INIT_APP_EXPORT(pin_beep_sample) INIT_EXPORT(pin_beep_sample, "6")

也就是  

const init_fn_t rt_init_pin_beep_sample SECTION(".rti_fn.""6") = pin_beep_sample

表示把函数pin_beep_sample的地址赋值给常量函数指针 rt_init_pin_beep_sample,然后放入名称为".rti_fn.6"的数据段中。(其中init_fn_t是一个函数指针类型,原型为typedef int (*init_fn_t)(void) 。)

在编译后的.map文件中可以查看到:

Symbol Name Value Ov Type Size Object(Section)

RTT学习之启动流程

 

  

版权声明:程序员胖胖胖虎阿 发表于 2022年9月16日 上午4:00。
转载请注明:RTT学习之启动流程 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...