通用芯片启动流程(以iar举例)
通用启动流程简单来说分为如下四步:第一步是从 ROM 区域中断向量表里获取入口函数开始执行,设置好初始栈指针,有了正确的栈,内核就具备函数跳转执行的能力了。第二步和第三步是全局变量的初始化(将全局变量初值从 ROM 区域拷贝到变量所链接的 RAM 区域),全局变量初始化完成,应用程序就有了正确的初始态,最后一步就是跳转到 main函数。
从源代码角度看启动流程
在通用启动流程的指导下,我们还需要增加一些 MCU 外设相关的初始化便形成了完整的芯片启动流程,现在我们从源代码角度再来看一下具体实现。
典型的 Cortex-M 复位函数
我们知道复位函数 Reset_Handler() 是芯片上电启动执行的第一个函数(有时又叫入口函数),它完成了进入用户 main() 函数之前的全部动作。随便下载一家 Cortex-M 厂商芯片 SDK 包,找到 IAR 版启动文件,其复位函数流程都差不多,这是 Cortex-M 内核架构决定的。
如下是典型的复位函数代码。复位函数里的操作包括关全局中断、设置中断向量表首地址、设置栈顶、系统初始化、开全局中断、进启动函数。其中系统初始化 SystemInit() 函数是因芯片而异的,各厂商 SDK 里会有具体源代码实现(一般在 system_xxDevice.c 文件里),这里面主要做芯片硬件层面的初始化,比如关看门狗、Cache 初步设置等,保证内核不受硬件模块状态影响,能正常执行指令。
__iar_program_start() 到底干了啥?
我们知道复位函数里的最后一个动作就是跳转到启动函数,将内核执行权交给 __iar_program_start(),这个启动函数源代码并不在厂商 SDK 包里,而在 IAR 安装目录下,因为它是 IAR 的通用底层设计。
为了找到 __iar_program_start() 的源代码,我们可以随便编译一个 SDK 例程(痞子衡选择的是 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar),查看其对应映射文件(.map),发现启动函数来自于 cstartup_M.o,然后我们在 IAR 安装目录下搜索 cstartup_M.c/.s 文件,最终我们在如下路径找到了启动函数相关的全部源文件。
结合启动函数相关源文件里的代码,我们终于搞清了启动函数全部流程,也找到了我们最关心的 __low_level_init() 函数调用位置,它在 .data/.bss/.textrw 段初始化之前被执行,所以它的功能应该跟 SystemInit() 差不多。默认 __low_level_init() 函数是空的,返回值是 1(返回值 0/1 决定后面的 __iar_data_init3() 要不要执行,1 是要执行),如果你想激活这个函数,需要在自己的源文件里重新定义实现,IAR 编译时会优先引用重新定义的版本。
参考原文资料https://www.eet-china.com/mp/a91226.html