STM32从Flash地址0x08000000的启动重映射

本文详细解释了STM32微控制器如何通过地址重映射技术实现从0x08000000地址处的Flash存储代码,并确保CM3内核能够正确地从0地址启动。文中还介绍了中断向量表的重定位过程及其在启动过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在初写STM32程序时,遇到一个困惑,STM32的Flash在MDK里被设置为起始地址0x0800 0000,而CM3手册规定芯片复位时要从0x0000 0000地址开始取出中断向量 ,那STM32怎么样执行代码呢?地址重映射?或者在0x0000 0000里有对应有实际存储器?

仔细阅读手册,发现这件事是因为STM32设计的Flash起始地址是在0x0800 0000位置开始的。全部代码都只能从这里开始存储。详见STM32 referenc manual手册第54页。

那既然从这里才能存储代码,就必须在MDK里设置Flash地址为0x0800 0000,下面是MDK设置页面,这个应该都看到过:

这样就还有一个问题,理论上,CM3中规定上电后CPU是从0地址开始执行,但是这里中断向量表却被烧写在0x0800 0000地址里,那启动时不就找不到中断向量表了?既然CM3定下的规矩是从0地址启动,SMT32当然不能破坏ARM定下的“规矩”,所以它做了一个启动映射的过程,就是和芯片上总能见到的BOOT0和BOOT1有关了,当选择从主Flash启动模式后,芯片一上电,Flash的0x0800 0000地址被映射到0地址处,不影响CM3内核的读取,所以这时的CM3既可以在0地址处访问中断向量表,也可以在0x0800 0000地址处访问中断向量表,而代码还是在0x0800 0000地址处存储的。这就是最难理解的地方,其实,这是基本上所有ARM芯片采用的启动映射方法。ARM7,ARM9没有内部Flash的通常都是这样做的。这个过程出自STM32 referenc manual手册,里面是有说明的:

还要注意,这个中断向量表是可以在程序中再次被映射的。控制它的就是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等一系列操作,这里摘要与中断向量有关的代码:

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。以后CM3再取中断向量里,就会根据SCB->VTOR的设置,从这里取向量执行了。中断向量自此终于转正。

注意这时连__main函数都还没进,看起来中断向量的重映射位置还是够早的。

 

 

 

 

### STM32 程序重映射0x00000000 地址的方法 对于 STM32 微控制器而言,程序通常默认从内部闪存启动。然而,在某些情况下可能希望改变这一行为,比如将程序加载到外部存储器并从此处执行。为了使程序能够从特定地址(如 `0x00000000`)运行,需调整向量表偏移以及设置正确的启动文件。 #### 向量表重新定位 STM32 的中断向量表位于 Flash 或 SRAM 起始位置,默认情况下指向的是内部 FLASH 的起始地址 (`0x0800_0000`)。要让处理器从其他地方开始执行代码,则需要修改 VTOR (Vector Table Offset Register),这可以通过 HAL 库中的函数完成: ```c HAL_NVIC_SetVectorTable(NVIC_VectTab_RAM, OFFSET); ``` 这里的 `OFFSET` 是相对于所选基地址的偏移量;如果想要完全替换为新的基地址,则应使用如下方式设定: ```c SCB->VTOR = NEW_BASE_ADDRESS; ``` 其中 `NEW_BASE_ADDRESS` 即为目标地址 `0x00000000`[^1]。 #### 修改链接脚本 除了更改向量表的位置之外,还需要告知编译工具链关于新入口的信息。这意味着更新 linker script 文件以指定不同的输出段布局。假设目标是在 RAM 中运行应用程序,那么可以在 `.ld` 文件里定义类似下面的内容: ```linker-script MEMORY { RAM : ORIGIN = 0x20000000, LENGTH = 64K /* 假定SRAM大小 */ } SECTIONS { .text : { *(.vectors) *(.text*) } >RAM AT>FLASH } ``` 上述配置会告诉链接器将可执行部分放置于 SRAM 并保持原有 flash 上的数据不变。注意实际应用时还需考虑堆栈分配等问题。 #### 设置启动文件 最后一步涉及创建自定义 startup file 来适应这种变化。一般做法是从标准版本复制一份,并对其进行适当编辑以便支持非零初始 PC 和 SP 寄存器值。确保该文件正确设置了 Stack Pointer 及 Program Counter 初始状态,使得 CPU 开机后能顺利跳转到预期位置执行指令序列。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值