应用跳转:1级boot,2级boot, app之间

📅 2026/7/6 12:58:49
应用跳转:1级boot,2级boot, app之间
1.__initial_sp 变量2.Reset_Handler 第一步硬件规定的“黄金八字节”Cortex-M 处理器上电或复位后其硬件逻辑会执行一个固定的操作从地址0x00000000读取第一个 32 位数据将其自动加载到主堆栈指针 (MSP)寄存器中。从地址0x00000004读取第二个 32 位数据将其自动加载到程序计数器 (PC)寄存器中。因此0x00000000和0x00000004这两个地址的内容必须分别是__initial_sp和Reset_Handler的地址。️ 第二步启动文件中的“向量表”定义启动文件通常是以.s为后缀的汇编文件如startup_stm32f4xx.s是确保这一切的第一步。它会定义一个名为__Vectors的数据段并按照处理器规定的顺序依次列出所有异常和中断处理函数的入口地址。其核心片段如下assembly__Vectors DCD __initial_sp ; 向量表第1项: 栈顶地址[reference:12][reference:13] DCD Reset_Handler ; 向量表第2项: 复位向量[reference:14][reference:15] DCD NMI_Handler ; 第3项: NMI DCD HardFault_Handler ; 第4项: 硬错误 ; ... 后续其他中断向量DCD指令用于分配一个 32 位的存储器单元并将后面符号的地址放入其中。这样__initial_sp和Reset_Handler的地址就被按顺序放在了向量表的开头。第三步链接器脚本中的“地址”决议启动文件只是定义了符号而链接器脚本Linker Script则负责最终把这些符号和代码段安排到正确的内存地址。确定__initial_sp的值这个符号通常在链接器脚本中定义代表栈的起始地址栈顶。c_estack ORIGIN(RAM) LENGTH(RAM); /* 栈顶设在 RAM 的最高地址 */ /*[reference:21]*/然后在启动文件中通过IMPORT __initial_sp或EXTERN声明将其引入并使用。链接器会在链接阶段把这个符号替换为_estack的实际数值。确定Reset_Handler的地址Reset_Handler作为函数其地址由链接器根据代码在 Flash 中的位置自动分配。链接器脚本会通过ENTRY(Reset_Handler)命令将其指定为程序的入口点。 第四步FreeRTOS 的介入与“接管”当芯片复位后会按照上述顺序执行硬件自动加载__initial_sp到 MSP。硬件自动跳转到Reset_Handler执行。Reset_Handler完成 C 运行时环境初始化后调用main()函数。在main()中我们调用vTaskStartScheduler()来启动 FreeRTOS 调度器。FreeRTOS 的vPortStartFirstTask()函数会再次从向量表NVIC 表中读取__initial_sp的值并将其重新写入 MSP 寄存器。这一步是为了确保任务调度开始时栈指针被正确地重置到向量表定义的位置。这个过程可以总结为下表阶段执行主体关键动作涉及文件/组件定义开发人员在启动文件中按顺序列出向量表启动文件 (.s)决议链接器计算__initial_sp和Reset_Handler的最终地址链接器脚本 (.ld)加载CPU 硬件自动从0x00和0x04加载 MSP 和 PCCortex-M 处理器执行复位处理函数初始化系统最终跳转到main()启动文件、C 运行时库接管FreeRTOS启动调度器时再次从向量表加载 MSPtasks.c,port.c所以FreeRTOS 能确保向量表内容正确关键在于它依赖并遵循由启动文件和链接器脚本共同建立的、符合硬件规范的工程结构。