流程入口-main函数
以 MDK-ARM 为例,MDK-ARM 的用户程序入口为 main() 函数,位于 main.c 文件中。系统启动后先从汇编代码开始运行,然后跳转到 C 代码,进行 RT-Thread 系统功能初始化,最后进入用户程序入口 main()。
/* re-define main function */
int $Sub$$main(void)
{
rtthread_startup();
return 0;
}
在这里
S
u
b
Sub
Sub$main 函数仅仅调用了 rtthread_startup() 函数。RT-Thread 支持多种平台和多种编
译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一入口点,所以
S
u
b
Sub
Sub$main 函数只需调用
rtthread_startup() 函数即可(例如采用 GNU GCC 编译器编译的 RT-Thread,就是直接从汇编启动代码
部分跳转到 rtthread_startup() 函数中,并开始第一个 C 代码的执行)。在 components.c 的代码中找到
rtthread_startup() 函数,我们看到 RT-Thread 的启动流程如下图所示:
启动函数:rtthread_startup
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* 板 级 初 始 化: 需 在 该 函 数 内 部 进 行 系 统 堆 的 初 始 化 */
rt_hw_board_init();
/* 打 印 RT-Thread 版 本 信 息 */
rt_show_version();
/* 定 时 器 初 始 化 */
rt_system_timer_init();
/* 调 度 器 初 始 化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 信 号 初 始 化 */
rt_system_signal_init();
#endif
/* 由 此 创 建 一 个 用 户 main() 线 程 */
rt_application_init();
/* 定 时 器 线 程 初 始 化 */
rt_system_timer_thread_init();
/* 空 闲 线 程 初 始 化 */
rt_thread_idle_init();
/* 启 动 调 度 器 */
rt_system_scheduler_start();
/* 不 会 执 行 至 此 */
return 0;
}
这部分启动代码,大致可以分为四个部分:
(1)初始化与系统相关的硬件;
(2)初始化系统内核对象,例如定时器、调度器、信号;
(3)创建 main 线程,在 main 线程中对各类模块依次进行初始化;
(4)初始化定时器线程、空闲线程,并启动调度器。
rt_hw_board_init() 中完成系统时钟设置,为系统提供心跳、串口初始化,将系统输入输出终端绑定
到这个串口,后续系统运行信息就会从串口打印出来。main() 函数是 RT-Thread 的用户代码入口,用户可以在 main() 函数里添加自己的应用。
/* defined the LED0 pin: PB1 */
#define LED0_PIN GET_PIN(B, 1)
int main(void)
{
int count = 1;
/* set LED0 pin mode to output */
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
while (count++)
{
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED0_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
return RT_EOK;
}
硬件初始化:rt_hw_board_init
/**
* This function will initial STM32 board.
*/
RT_WEAK void rt_hw_board_init()
{
#ifdef SCB_EnableICache
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
#endif
#ifdef SCB_EnableDCache
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
#endif
/* HAL_Init() function is called at the beginning of the program */
HAL_Init();
/* enable interrupt */
__set_PRIMASK(0);
/* System clock initialization */
SystemClock_Config();
/* disbale interrupt */
__set_PRIMASK(1);
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 by default */
#ifdef RT_USING_PIN
rt_hw_pin_init();
#endif
/* USART driver initialization is open by 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 hardware initialization */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
rt_components_board_init
/**
* RT-Thread Components Initialization for board
*/
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
rt_components_board_init() 函数执行的比较早,主要初始化相关硬件环境,执行这个函数时将会遍
历通过 INIT_BOARD_EXPORT(fn) 申明的初始化函数表,并调用各个函数。