写STM32程序时,遇到一个困惑,STM32的Flash在MDK里被设置为起始地址0x0800 0000,
而CM4手册规定芯片复位时要从0x0000 0000地址开始取出**中断向量表** ,
那STM32怎么样执行代码呢?**地址重映射**?或者在0x0000 0000里有对应有实际存储器?
仔细阅读手册,发现这件事是因为STM32设计的**Flash起始地址**是在0x0800 0000位置开始的。
全部代码都只能从这里开始存储。
这样就还有一个问题,理论上,CM4中规定上电后CPU是从0地址开始执行,
但是这里**中断向量表**却被烧写在0x0800 0000地址里,那启动时不就找不到中断向量表了?
既然CM4定下的规矩是从0地址启动,SMT32当然不能破坏ARM定下的“规矩”,
所以它做了一个启动映射的过程,就是和芯片上总能见到的BOOT0和BOOT1有关了,
当选择从主Flash启动模式后(BOOT1=x BOOT0=0 芯片内置的Flash。 ),
芯片一上电,Flash的0x0800 0000地址被映射到0地址处,不影响CM3内核的读取,
所以这时的CM3既可以在0地址处访问中断向量表,也可以在0x0800 0000地址处访问中断向量表,
而代码还是在0x0800 0000地址处存储的。这就是最难理解的地方,
其实,这是基本上所有ARM芯片采用的启动映射方法。这里补充下**stm32的启动方式。**
用户闪存: BOOT1=x BOOT0=0 芯片内置的Flash。
SRAM: BOOT1=1 BOOT0=1 芯片内置的RAM 区,就是内存啦。
系统存储器:BOOT1=0 BOOT0=1 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,
就是通常说的ISP程序。这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM 区。
BOOT1=x BOOT0=0 从用户闪存启动,**这是正常的工作模式**。
BOOT1=0 BOOT0=1 从系统存储器启动,这种模式启动的程序功能由厂家设置。
BOOT1=1 BOOT0=1 从内置SRAM 启动,这种模式可以用于调试。
还要注意,这个中断向量表是可以在程序中再次被映射的。控制它的就是CM3已经规定的NVIC寄存器SCB->VTOR。在STM32库中给出的启动代码里,startup_stm32f10x_hd.s文件里,第146行,是上电后读取中断向量表中的复位中断位置,并执行复位中断处理代码,代码如下:
; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
注意复位后第一个被执行的是SystemInit代码,这个代码在库目录下的system_stm32f10x.c文件里,它初始化了时钟,NVIC等一系列操作,这里摘要与中断向量有关的代码: ![](https://img-blog.csdnimg.cn/21048f38c8f74519ba1609e21751e71f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5aWU6LeR55qE5bCP6LWb5YWU,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
void SystemInit (void)
{
…
#ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. / #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; / Vector Table Relocation in Internal FLASH. */ #endif }
可以看出中断向量重映射是一个选择性编译,通常宏定义VECT_TAB_SRAM都没有被定义,所以这里执行结束后,SCB->VTOR就是FLASH_BASE了,值为0x0800 0000。以后CM4再取中断向量里,就会根据SCB->VTOR的设置,从这里取向量执行了。中断向量自此终于转正。
注意这时连__main函数都还没进,看起来中断向量的重映射位置还是够早的。
|