后来理解到全局变量是在main()函数之前初始化的。MDK默认情形下勾选下面选项,跳过了启动的汇编部分代码,直接进入了main() 函数.
实际起始位置

在cortex-m系列中,中断向量表存放在 Flash 开始部分,Flash中第一个字存放栈顶指针,第二个字存放复位中断做事函数入口地址,其他中断做事函数入口地址依次存放在Flash中。
MCU上电后,会将Flash中的第一个字
加载到R13 MSP寄存器中,第二个字加载到R15 PC寄存器中。
从上图可以看出ARM规定了M3,M4
内核要从地址0x0000 0000读取中断向量表,而STM32设置Flash地址到0x0800 0000怎么办?
STM32将地址0x0800 0000开始的内容重映射到首地址0x0000 0000中,这样就办理了从0x0000 0000读取中断向量表的问题。下图可以看出STM32F105实际读出的0x0000 0000和0x0800 0000内容一样
R13:栈顶指针寄存器SP
SP寄存器有两个,MSP或者PSP,PSP是为了RTOS特意设置的,如果利用RTOS,则在RTOS的任务中便是利用的PSP,在中断做事函数中则利用MSP。如果不该用RTOS,则默认一贯利用MSP。
在MCU中,RAM只是卖力暂存数据,真正的运算是在寄存器中完成的,例如要对两个变量进行加法运算,就须要将两个变量的值从RAM中取出存入寄存器中,然后操作寄存器进行打算,末了将打算结果存入RAM中。因此常说的在进入子函数或者中断做事函数时须要保存现场,实在也便是保存寄存器中的值,将寄存器值PUSH在栈中。
SP寄存器指向栈顶地址,因此随着PUSH和POP,SP寄存器会随着自动变革。
MSP寄存器存放栈顶指针,栈中存放局部变量、函数参数以及进入子函数、中断做事函数前寄存器的值,当从子函数或者中断做事函数中跳出时,会从栈中POP寄存器值,也便是规复现场,确保程序可以正常实行。平时只管即便不让利用递归便是为了防止多次调用自身,多次保存现场导致栈溢出。
入栈和出栈操作由编译器自动天生代码,但是入栈时默认只会将R0-R3入栈,如果中断做事函数过于繁芜,则编译器也会将R4-R11入栈,这也便是为什么中断做事函数只管即便简短的缘故原由之一。
R15:程序计数寄存器PC
PC寄存器指向当前的程序地址。如果修正它的值,就能改变程序的实行流(很多高等技巧就在这里面)
上电时将中断向量表中的第二个字加载到PC寄存器中,也便是让程序跳转到复位中断做事函数中。
不过复位中断做事函数是一个汇编函数。
复位中断做事函数中调用了SystemIn
it()函数,该函数紧张浸染是设置中断向量表的偏移地址。也便是说中断向量表位置是可变的,当利用BOOT后,就须要在APP修正该偏移地址。
接着复位中断做事函数跳转到__main()函数中,__main()和我们平时说的main()函数是有差异的。
RAM掉电会丢失数据,在上电后,RAM中的数据是不愿定的,在运行main()函数之前须要将RAM中的数据初始化,也便是下图左边到右边的过程,将flash中的RW数据加载到RAM中,并将RAM中的ZI段数据进行初始化操作。MDK中__main()函数帮我们自动完成了这个操作,也便是所谓的准备C措辞环境,C措辞环境准备好之后会跳到 main() 函数。
末了,实在还少说了一个,在上电后会根据boot0,boot1 的状态确定自举空间的位置,如果从系统存储器自举(系统bootLoad,出厂时,官方固化在单片机中的一段代码,用户无法修正的。在STM32中,常用的串口下载,DFU便是系统bootLoad中的功能),系统bootLoad实行完毕后才是我们上面说的哪些,文章中的图大部分来自《Cortex-M3 威信指南》






