所以这个东西到底是咋运行起来的,一给电源就启动了。
启动代码是 MCU 复位后执行的第一段代码,主要作用是 初始化堆栈、设置中断向量表、调用系统初始化函数,并最终跳转到 main()。该文件采用 ARM 汇编实现,并按照 Cortex-M 内核启动流程设计。
因为最终是要有一个稳定的执行指令的环境的,就是PC指针开始工作,CPU开始工作。
一开始的堆栈初始化就是:为 SP(栈指针)和 malloc() 分配 RAM。
接下来是:存储 MCU 的中断入口地址,就是NVIC
第一项:栈指针 第二项:Reset_Handler 作为复位后执行的代码
接下来是开始复位:
设置 SP,确保堆栈正确 调用 SystemInit(),初始化 MCU 时钟 跳转 __main(),最终执行 main()
在总结一下:
1️⃣ MCU 复位,CPU 读取向量表 0x00000000
2️⃣ 加载 __initial_sp 到 SP
3️⃣ 跳转 Reset_Handler 执行
4️⃣ 调用 SystemInit() 初始化系统
5️⃣ 跳转 __main() 进行 C 运行环境初始化
6️⃣ 最终进入 main(),运行用户代码
这也是一样的流程
就在这里
基址在这里,下面是引导的中断向量表。接着是引导代码,直接一段没使用,然后是用户的中断表,这个表还会拿出来继续映射。
这个一个栈指针,下一个就是程序指针
下一个就是中断源了
CPU 复位后,取出向量表中的 MSP(堆栈指针).
第 0 号地址:存储堆栈指针(MSP, Main Stack Pointer) 初始值。 第 1 号地址:存储复位向量(Reset Vector),指向 Reset_Handler。 第 2~N 号地址:存储 各种异常和中断的入口地址。
那就是APB,AHB和M0+往下了
从下往上走
初始化串口等外设,确保BootLoader可以与外部设备通信。 在跳转到应用程序之前,需要关闭所有中断,以避免在跳转过程中发生中断导致不可预知的行为。 从应用程序的起始地址(即中断向量表的第一个条目)读取初始堆栈指针的值,并将其设置为当前堆栈指针。 从应用程序的起始地址+4的位置读取复位向量的地址,并将其强制转换为函数指针,然后跳转到该地址执行。
大概就是这样
MSR MSP, r0:将传入的参数(addr,存储在寄存器 r0 中)赋值给主堆栈指针(MSP)。 BX r14:跳转到链接寄存器(r14,即 LR)中存储的地址,用于返回到调用函数。
看看这个复杂的函数
jump2app = (void(*)())*(vu32*)(appxaddr+4):读取应用程序起始地址的第二个字(复位中断地址),并将其赋值给函数指针 jump2app。
是这样
栈顶地址检查:确保应用程序的栈顶地址在合法的RAM范围内。 复位中断地址:应用程序的第二个字是复位中断地址,BootLoader通过该地址跳转到应用程序。 关闭中断:在跳转之前关闭所有中断,确保跳转过程的安全。 堆栈指针设置:在跳转之前,正确设置应用程序的堆栈指针。
然后呢?怎么走?
堆栈已经好了
当然这个还是写的不全面,下次再写!