一、startup_stm32f407xx.S

系统进入汇编文件

image-20250215165008148

RT-Thread使用的是GCC

启动流程

二、不同编译器的启动函数

调用stm32f407_demo3\rt-thread\src\components.c中的$Sub$$main()

image-20250215223923007

三、调用rtthread_startup(void)

在stm32f407_demo3\rt-thread\src\components.c中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int rtthread_startup(void)
{
/* 禁用了所有中断 */
rt_hw_interrupt_disable();
/* 执行板级支持包(BSP)初始化
包括配置硬件、系统时钟、外设初始化等 */
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
/* 创建应用任务、初始化外设 */
rt_application_init();
/* 初始化定时器线程 */
rt_system_timer_thread_init();
/* 初始化空闲线程 */
rt_thread_idle_init();
/* 如果启用了 SMP(对称多处理) */
#ifdef RT_USING_SMP
/* 进行多核处理器的初始化和同步 */
rt_hw_spin_lock(&_cpus_lock);
#endif /*RT_USING_SMP*/
/* 开始任务调度 */
rt_system_scheduler_start();

/* never reach here */
return 0;
}

3.1rt_hw_board_init和rt_application_init的 外设初始化的不同

  • rt_hw_board_init

硬件初始化初始化硬件资源,如 GPIO、串口、SPI、I2C、PWM、ADC、定时器等。

系统时钟配置:配置系统时钟、外设时钟以及 PLL(锁相环)等,确保系统和外设运行在合适的频率下。

内存初始化:配置堆栈、堆内存和静态内存区域,确保系统资源可用。

中断配置:初始化中断控制器,并为特定外设启用中断。

启动引导程序:执行系统初始化,如配置时钟源、初始化硬件外设等,通常会包括一个初始化阶段的启动代码。

设备驱动注册:为基础硬件外设(如 UART、SPI、I2C 等)注册驱动,使操作系统能够访问这些外设。

  • rt_application_init

创建应用任务:创建系统中的应用任务,例如数据采集任务、处理任务等。

初始化外设:在 应用层 对外设进行更高层次的初始化。例如,在硬件初始化后,可能会初始化一些外设的具体参数,如设置 ADC 采样周期、配置传感器等。

启动应用程序逻辑:进行传感器数据采集、通信协议的初始化、数据处理等应用相关的工作。

任务调度和资源管理:创建并调度多个任务,管理应用程序层的资源。

3.2rt_hw_board_init()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
RT_WEAK void rt_hw_board_init()
{
extern void hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq);

/* Heap initialization */
#if defined(RT_USING_HEAP)
rt_system_heap_init((void *) HEAP_BEGIN, (void *) HEAP_END);
#endif
/* 时钟源初始化,配置 MCU 的时钟系统,设置系统时钟、外设时钟 */
hw_board_init(BSP_CLOCK_SOURCE, BSP_CLOCK_SOURCE_FREQ_MHZ, BSP_CLOCK_SYSTEM_FREQ_MHZ);

/* 设置控制台设备。通常,这意味着将输出通过串口或其他通信接口进行调试输出。 */
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

/* 始化板级硬件组件 */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif

}

3.2.1hw_board_init()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
oid hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq)
{
extern void rt_hw_systick_init(void);
extern void clk_init(char *clk_source, int source_freq, int target_freq);

#ifdef SCB_EnableICache
/* 开启指令缓存,用于加速程序的指令获取。*/
SCB_EnableICache();
#endif

#ifdef SCB_EnableDCache
/* 开启数据缓存,用于加速数据存取。*/
SCB_EnableDCache();
#endif

/* 初始化 HAL 库需要的硬件资源,例如时钟配置、外设初始化等 */
HAL_Init();

/* 将 PRIMASK 寄存器清零,开启全局中断 */
__set_PRIMASK(0);
/* 初始化系统时钟 */
clk_init(clock_src, clock_src_freq, clock_target_freq);
/* 将 PRIMASK 寄存器设置为 1,禁止全局中断。确保时钟配置的过程中不会受到中断的干扰 */
__set_PRIMASK(1);
/* 初始化 SysTick 定时器 */
rt_hw_systick_init();

/* 初始化与硬件引脚相关的驱动(如 GPIO 控制)。
初始化所有的通用输入输出引脚,设置引脚模式、方向、输出类型等 */
#ifdef RT_USING_PIN
extern int rt_hw_pin_init(void);
rt_hw_pin_init();
#endif

/* 初始化 USART 驱动 */
#ifdef RT_USING_SERIAL
extern int rt_hw_usart_init(void);
rt_hw_usart_init();
#endif

}

image-20250215174007724

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int rt_hw_usart_init(void)
{
/* 计算定义了几个串口,通过串口配置结构体的总大小/每个结构体的大小来计算*/
rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart);
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
rt_err_t result = 0;

stm32_uart_get_dma_config();

for (int i = 0; i < obj_num; i++)
{
uart_obj[i].config = &uart_config[i];
uart_obj[i].serial.ops = &stm32_uart_ops;
uart_obj[i].serial.config = config;
/* 用于注册串口设备,将串口设备与操作系统的设备管理系统连接起来,使得串口设备能够被操作系统识别和管理
register ---- 注册*/
result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
RT_DEVICE_FLAG_RDWR
| RT_DEVICE_FLAG_INT_RX
| RT_DEVICE_FLAG_INT_TX
| uart_obj[i].uart_dma_flag
, NULL);
RT_ASSERT(result == RT_EOK);
}

return result;
}

image-20250215174346247

3.3 rt_show_version(void)

image-20250215224815579

3.4 rt_application_init()

创建main()线程

image-20250215230134023

3.5 rt_system_timer_thread_init()

创建rt_thread_timer_entry()线程

image-20250215230248093

3.5.1rt_thread_timer_entry()

专门用于处理软件定时器的线程函数,定期检查并触发到期的定时器回调。当没有定时器超时时,当前线程会被挂起,直到下一个定时器到期为止。

image-20250215231635484

  • 它首先通过 rt_timer_list_next_timeout 获取下一个定时器的超时时间。
  • 如果没有定时器超时,它会挂起当前线程,直到有定时器超时。
  • 如果有定时器将要超时,函数会计算剩余时间,并使线程在该时间段内休眠,直到定时器超时。
  • 每次循环结束时,rt_soft_timer_check() 会检查所有的软件定时器,触发到期的定时器回调。

3.6 rt_thread_idle_init()

初始化 空闲线程,是操作系统中的一个特殊线程,它在所有其他任务都没有运行时执行。通常,空闲线程用来降低系统功耗,或者执行一些后台清理任务。

image-20250215232409967

四、宏定义函数执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
/* 负责硬件平台的初始化,如时钟配置、外设初始化等。 */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* 初始化一些软件模块,可能包括设置一些内核参数、初始化操作系统调度器等 */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* 初始化系统中的外设,如串口、GPIO、I2C、SPI 等 */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* 包括文件系统(如 FatFS)、网络协议栈(如 lwIP)和其他应用组件的初始化 */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* 涉及外部设备的挂载、环境配置、磁盘挂载等 */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* 与应用程序级别的初始化相关,如图形界面(rtgui)、应用任务初始化等 */
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")