Rt-Thread 启动流程与组件初始化
目录
1、启动流程
2、程序入口
2.1、入口函数
2.2、用户main函数
3、rtthread_startup()函数
3.1、rt_hw_board_init()函数
4、组件初始化
4.1、INIT_EXPORT宏
4.1.1、未定义RT_USING_COMPONENTS_INIT
4.1.2、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT
4.1.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT
4.2、INIT_EXPORT实例
4.2.1、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT
4.2.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT
4.3、INIT_XXX_EXPORT宏
4.4、rt_components_board_init()函数
4.5、rt_components_init()函数
1、启动流程
RT-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一启动入口。
2、程序入口
在进入 main() 之前需要进行RT-Thread 系统功能初始化,需要修改入口函数。
2.1、入口函数
#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
#elif defined(__ICCARM__)
extern int main(void);
/* __low_level_init will auto called by IAR cstartup */
extern void __iar_data_init3(void);
int __low_level_init(void)
{
// call IAR table copy function.
__iar_data_init3();
rtthread_startup();
return 0;
}
#elif defined(__GNUC__)
/* Add -eentry to arm-none-eabi-gcc argument */
int entry(void)
{
rtthread_startup();
return 0;
}
#endif
编译工具 | 入口函数 |
MDK | $Sub$$main() 注:使用了 MDK 的扩展功能 $Sub$$ 和$Super$$。可以给 main 添加 $Sub$$ 的前缀符号作为一个新功能函数 $Sub$$main,这个 $Sub$$main 可以先调用一些要补充在 main 之前的功能函数 |
IAR | __low_level_init() |
GCC | entry() |
2.2、用户main函数
void main_thread_entry(void *parameter)
{
extern int main(void);
extern int $Super$$main(void);
#ifdef RT_USING_COMPONENTS_INIT
/* RT-Thread components initialization */
rt_components_init();
#endif
/* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
$Super$$main(); /* for ARMCC. */
#elif defined(__ICCARM__) || defined(__GNUC__)
main();
#endif
}
编译工具 | 入口函数 |
MDK | $Super$$main() |
IAR | main() |
GCC |
3、rtthread_startup()函数
这部分代码,大致可以分为四个部分:
1)初始化与系统相关的硬件;
2)初始化系统内核对象,例如定时器、调度器、信号;
3)创建 main 线程,在 main 线程中对各类模块依次进行初始化;
4)初始化定时器线程、空闲线程,并启动调度器。
详细功能如下:
1)关中断
2)板级初始化,在该函数中初始化堆
3)打 印 RT-Thread 版 本 信 息
4)系统定时器系统初始化
5)系统调度器初始化
6)*系统信号量初始化
7)创建应用初始化线程
8)系统定时器线程初始化
9)空闲线程初始化
10)调度器开始调度
int rtthread_startup(void)
{
rt_hw_interrupt_disable(); //关中断
rt_hw_board_init(); //板级初始化,在该函数中初始化堆
rt_show_version(); //显示版本
rt_system_timer_init(); //系统定时器系统初始化
rt_system_scheduler_init(); //系统调度器初始化
#ifdef RT_USING_SIGNALS
rt_system_signal_init(); //如果定义了宏RT_USING_SIGNALS,初始化系统信号量
#endif
rt_application_init(); //创建应用初始化线程
rt_system_timer_thread_init(); //系统定时器线程初始化
rt_thread_idle_init(); //空闲线程初始化
rt_system_scheduler_start(); //调度器开始调度
return 0;
}
3.1、rt_hw_board_init()函数
此函数为板级初始化函数(不同板子的初始化函数不同)。
1)系统时钟设置
2)为系统提供心跳
3)*调用rt_components_board_init()函数,进行串口初始化(将系统输入输出终端绑定到这个串口,后续系统运行信息就会从串口打印出来)
4)*调用rt_system_heap_init()函数,进行堆初始化
4、组件初始化
4.1、INIT_EXPORT宏
#ifdef RT_USING_COMPONENTS_INIT
typedef int (*init_fn_t)(void);
#ifdef _MSC_VER /* we do not support MS VC++ compiler */
#define INIT_EXPORT(fn, level)
#else
#if RT_DEBUG_INIT
struct rt_init_desc
{
const char* fn_name;
const init_fn_t fn;
};
#define INIT_EXPORT(fn, level) \
const char __rti_##fn##_name[] = #fn; \
RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \
{ __rti_##fn##_name, fn};
#else
#define INIT_EXPORT(fn, level) \
RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
#endif
#endif
#else
#define INIT_EXPORT(fn, level)
#endif
4.1.1、未定义RT_USING_COMPONENTS_INIT
#define INIT_EXPORT(fn, level)
4.1.2、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT
#define INIT_EXPORT(fn, level) \
RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
定义了一个指向fn()函数的函数指针__rt_init_##fn,并将此函数指针定位到".rti_fn."level段。
4.1.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT
struct rt_init_desc
{
const char* fn_name;
const init_fn_t fn;
};
#define INIT_EXPORT(fn, level) \
const char __rti_##fn##_name[] = #fn; \
RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \
{ __rti_##fn##_name, fn};
定义了一个字符数组和一个结构体。
1)__rti_##fn##_name[]字符数组用于保存fn()函数的名称。
2)__rt_init_desc_##fn结构体此结构体有2个成员。并将__rt_init_desc_##fn结构体定位到".rti_fn."level段。
fn_name成员为函数名称,指向__rti_##fn##_name[]字符数组
fn成员为函数指针。指向fn()函数的函数指针,函数指针名为__rt_init_##fn。
4.2、INIT_EXPORT实例
static int rti_start(void)
{
return 0;
}
INIT_EXPORT(rti_start, "0");
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");
4.2.1、定义RT_USING_COMPONENTS_INIT,未定义RT_DEBUG_INIT
RT_USED const init_fn_t __rt_init_rti_start SECTION(".rti_fn.0") = rti_start
RT_USED const init_fn_t __rt_init_rti_board_start SECTION(".rti_fn.0.end") = rti_board_start
RT_USED const init_fn_t __rt_init_rti_board_end SECTION(".rti_fn.1.end") = rti_board_end
RT_USED const init_fn_t __rt_init_rti_end SECTION(".rti_fn.6.end") = rti_end
函数指针 | 段 | 函数 |
__rt_init_rti_start | .rti_fn.0 | rti_start() |
__rt_init_rti_board_start | .rti_fn.0.end | rti_board_start() |
__rt_init_rti_board_end | .rti_fn.1.end | rti_board_end() |
__rt_init_rti_end | .rti_fn.6.end | rti_end() |
4.2.2、定义RT_USING_COMPONENTS_INIT,且定义RT_DEBUG_INIT
const char __rti_rti_start_name[] = "rti_start";
RT_USED const struct rt_init_desc __rt_init_desc_rti_start SECTION(".rti_fn.0") = \
{ __rti_rti_start_name, rti_start};
const char __rti_rti_board_start_name[] = "rti_board_start";
RT_USED const struct rt_init_desc __rt_init_desc_rti_board_start SECTION(".rti_fn.0.end") = \
{ __rti_rti_board_start_name, rti_board_start};
const char __rti_rti_board_end_name[] = "rti_board_end";
RT_USED const struct rt_init_desc __rt_init_desc_rti_board_end SECTION(".rti_fn.1.end") = \
{ __rti_rti_board_end_name, rti_board_end};
const char __rti_rti_board_rti_end_name[] = "rti_end";
RT_USED const struct rt_init_desc __rt_init_desc_rti_end SECTION(".rti_fn.6.end") = \
{ __rti_rti_end_name, rti_end};
数组 | 字符串 |
__rti_rti_start_name[] | "rti_start" |
__rti_rti_board_start_name[] | "rti_board_start" |
__rti_rti_board_end_name[] | "rti_board_end" |
__rti_rti_board_rti_end_name[] | "rti_end" |
结构体 | 段 | 成员 | 函数 |
__rt_init_rti_start | .rti_fn.0 | fn_name | __rti_rti_start_name[] |
fn | rti_start() | ||
__rt_init_rti_board_start | .rti_fn.0.end | fn_name | __rti_rti_board_start_name[] |
fn | rti_board_start() | ||
__rt_init_rti_board_end | .rti_fn.1.end | fn_name | __rti_rti_board_end_name[] |
fn | rti_board_end() | ||
__rt_init_rti_end | .rti_fn.6.end | fn_name | __rti_rti_board_rti_end_name[] |
fn | rti_end() |
4.3、INIT_XXX_EXPORT宏
/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")
宏 | 段 |
INIT_BOARD_EXPORT | .rti_fn.1 |
INIT_PREV_EXPORT | .rti_fn.2 |
INIT_DEVICE_EXPORT | .rti_fn.3 |
INIT_COMPONENT_EXPORT | .rti_fn.4 |
INIT_ENV_EXPORT | .rti_fn.5 |
INIT_APP_EXPORT | .rti_fn.6 |
4.4、rt_components_board_init()函数
此函数用于板级组件初始化(调用.rti_fn.0.end段到.rti_fn.1.end段的函数)。一般为BOARD_EXPORT()宏定义的函数指针指向的函数(一般为串口初始化函数)。
__rt_init_rti_board_start位于.rti_fn.0.end段,__rt_init_rti_board_end位于.rti_fn.1.end段。
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
volatile 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.5、rt_components_init()函数
此函数用于组件初始化(调用.rti_fn.1.end段到.rti_fn.6.end段的函数)。一般为DEVICE_EXPORT()、COMPONENT_EXPORT(),FS_EXPORT(),ENV_EXPORT(),APP_EXPORT()宏定义的函数指针指向的函数。
__rt_init_rti_board_end位于.rti_fn.1.end段,__rt_init_rti_end位于.rti_fn.6.end段。
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
volatile 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
}