bootloader的实现
前面我们已经将APP下载到了QSPI, 终于进入主题了,描述一下跳转的过程,为了保证bootloader的纯净,我们应当尽量让bootloader简化,使用到了QSPI,我们只需要保证QSPI是正常运行的,这里需要设置为内存映射模式,便可直接访问QSPI的地址,像操作内存那样,其他的外设都需要解初始化,以及使用到的中断需要清除关闭,并且为了保证正常的跳转我们还需要屏蔽掉可能出现的中断(异常)
这里是跳转的主要逻辑

首先会检查qspi是否初始化正常,并且会开启内存映射模式,这一步之后应该就可以通过仿真来看到qspi地址的内容了,即app的内容

这里的前八个字节对应着跳转过去的 sp与pc ,
F8 08 00 24 B1 02 00 90因为是小端字节序,
跳转过去的首地址为为0x9000 0000,对应的指令为 0x2400 08F8
将加载0x2400 08F8的值到堆栈指针寄存器(SP)中,从而设置堆栈的首地址为0x2400 08F8。
下一个四字节即 地址为 0x9000 0000+4 对应的指令为 9000 02B1
将加载初始程序计数器(PC)值,即程序的入口点 9000 02B1
我们再回头看一下APP的map文件理解一下 堆栈的首地址前一部分是什么,以及sp的前一部分是什么

从以上的文件中不难看出,内存中存在data段,bss段以及 STACK栈,
data段:data段通常用于 存储初始化的全局变量和静态变量。- 这些变量在程序开始运行时被赋予一个非零的初始值。
data段的内容通常在程序加载时从非易失性存储(如Flash内存)复制到RAM中。
bss段:bss段用于 存储未初始化的全局变量和静态变量。- 在程序开始运行时,
bss段的所有内容通常被初始化为零。 bss段不占用程序的存储空间,它仅在链接时保留空间,以便在运行时可以初始化为零。
stack段:stack段用于存储局部变量、函数参数、返回地址和保存的寄存器值。- 它是动态的,其大小会随着函数的调用和返回而改变。
stack通常是由程序的运行时系统自动管理的,例如,当函数被调用时,它的参数和返回地址被推送到栈上,而当函数返回时,这些值被弹出。
在APP中我们为栈分配了,2KB (堆也给了2k)


由于栈是向下生长的,所以我们的栈顶地址会被设置为0x240000F8+0X800,最终即得到了我们的栈顶地址 0x2400 08F8
这也可以解释栈溢出是个什么东西了,总结看来就是当栈用完以后如果没有安全保护将 会改写bss段的数据,这将导致我们程序中的某个 未初始化的全局变量和静态变量被改写,这将导致致命错误,
以上看来似乎是这样的,但是这里忽略了堆区的存在(以上说法是错误的)
堆区位于 栈与bss段之间,由于我们在程序中没有分配内存,编译器自动优化掉了,看下面小实验
在原来的工程中添加以下示例
#include <stdlib.h>
int *arr;
int n = 5; // 例如,我们想要分配5个整数的空间
arr = (int *)malloc(n * sizeof(int)); // 分配内存

现在堆出现了,现在可以正确解释堆栈溢出了
以上解释完了栈顶地址,接下来该看 base address +4的值是个什么东西,以及它的前一段内容
9000 02B1
一点一点来看,首先基地址对应的为中断向量表的地址 计算可以得出 中断向量表占664个字节(这包括异常)
__Vectors 0x90000000 Data 4
__Vectors_End 0x90000298 Data 0 _main_scatterload 设置内存区域,将读写(RW)和只读(RO)输出段从加载地址复制到执行地址,并初始化零初始化(ZI)区域
这一阶段可能包括调用_main_cpp_init和_main_init等函数,以初始化C++运行时环境和执行其他必要的系统初始化。中间的阶段似乎是时钟初始化与 引入 c c++ 并初始化, 这里具体的过程不太了解
- Reseat_Handle 配置中断向量表 从复位向量所指向的复位中断ISR开始运行的,pc指针指向它,接着加载指令执行
制作logo
系统上电的时候有一个启动logo很是炫酷,咱也来做一个
logo制作网站, 实际上是打印出来,简单明了
http://patorjk.com/software/taag/
最重要跳转


其中我们需要清理所用到的外设
DeInit_all_bsp_and_IRQ函数

if(qspi_init_and_enable_MemoryMapMode() == 0)
{
display_logo();
jump_app();
}这里QSPI初始化完成并开启内存映射之后 会打印一个logo,接着跳转到qspi的基地址

再次提醒
需要在我们的的bootloader中失能全局中断 并在app的开始打开全局中断
踩坑:在配置时钟的时候避免与 QSPI 时钟重叠 在解初始化外设的时候在 再次检验一下QSPI是否正常,如果不正常则是解初始化的外设时钟与QSPI重叠
如下

另一种情况,,把其他外设的时钟关闭了QSPI就不能正常运行,很玄学,总之 解初始化其他外设时钟之后 再判断QSPI是否正常 在调试阶段有必要的