在STM32微控制器中,启动时的地址重映射(Remap)是一个重要的概念,它允许将不同的存储器区域映射到特定的地址空间,以便在启动时能够正确执行代码。具体来说,这通常涉及到将内部Flash、系统存储器(System Memory,即内置的Bootloader)或内部SRAM映射到0x00000000开始的地址空间。
1、为什么需要地址重映射?
在ARM Cortex-M
系列处理器(包括STM32的Cortex-M3、M4、M7
等)中,内核设计的特点是:处理器上电或复位后,会从两个特定的地址获取初始信息:
- 主栈指针(
MSP
)的初始值:从地址0x00000000
处读取的值作为MSP的初始值,属于硬件行为
,由内核的电路设计实现,而非软件控制内核。 - 复位向量(程序计数器
PC
初始值):从地址0x00000004
处读取的值作为PC
的初始值,也就是内核即将执行的第一条指令所在的地址,属于硬件行为
,由内核的电路设计实现,而非软件控制内核。
因此,必须确保在启动时,0x00000000
开始的地址空间是可访问的,并且有有效的栈指针和复位向量(存放正确的复位函数的地址)
。然而,STM32内部有多个存储器区域(如Flash、SRAM
、系统存储器)能够存放可执行的代码,它们的物理地址并不都在0x00000000
开始的地方。例如:
- 内部
Flash
通常起始于0x08000000
,存储用户程序,内核会从内部Flash取出指令
语句,交给内核的译码单元、ALU单元等进行运算即执行指令
语句。 - 内部
SRAM
通常起始于0x20000000
,存储运行时数据,也可以存放用户程序,用于临时调试。 - 系统存储器(
System Memory
)通常起始于0x1FFF0000
(M3/M4),这段地址上固化了一段出厂Bootloader
。如果MCU从系统存储器启动,那么这段代码配合官方给的上位机或者FlyMcu
上位机,能够让用户使用上位机通过串口烧写bin
文件到内部Flash
中。官方给定了串口烧写时的通信协议,所以实际上用户也可以自行开发上位机适配系统Bootloader
。
一般情况是用户把代码烧写到Flash中,然后从内部Flash启动。但还有另外两种情况:
- 用户把代码烧写到内部SRAM,并让MCU从内部SRAM启动,这样的好处是不会更改Flash中的代码就能验证、调试代码修改后的效果。但要注意:此时代码和数据都处在SRAM中,需要指定好两者各自存放的地址,不要冲突覆盖
- 用户想通过系统存储器里的Bootloader将用户代码烧写到Flash中,此时就需要让MCU从系统Bootloader启动即复位后去
0x1FFF0000
地址段获取MSP和PC初值:0x1FFF0000
地址存放了系统Bootloader代码计算的MSP值,0x1FFF0000+0x4
地址则存放了系统Bootloader代码的复位向量地址值。 - 至于代码为啥是这样存放的,则完全是由ARM的编译器和连接器决定的,本质就是ARM设计的架构规定的,根据架构编译出的bin文件,bin文件的开头就是MSP的值和复位向量地址值,紧跟着的一段地址上依次存放着其他向量即中断回调函数的地址,这些向量共同组成了中断向量表。这个就是ARM的特点:中断向量表存放在0x0地址。
由于这些存储器的物理地址并非从 0x0000_0000
开始,而Cortex-M
内核要求复位时必须访问零地址空间,如果想要内核能够灵活的选择不同地址上的代码作为启动引导代码,那么就要想办法将 0x0000_0000
地址【指向即重映射
】到这些目标代码的存放地址即上述三种存储器的首地址。
为什么要地址的重映射而不是将代码复制到0x0
地址?复制动作是将代码从一个存储器搬运到另一个存储器,但是0x0
地址处并不是一个存储器,而只是逻辑地址(虚拟概念而非实体),因此无法进行代码复制,只能将0x0
地址重映射到各个物理地址(物理地址意味着有对应的实体存储器)
Cortex-M
内核的启动时的地址重映射是硬件行为,由内核电路设计实现,而不是通过软件控制的,所以说,地址重映射(对应的是根据Boot
引脚电平选择启动引导源这个动作),发生在第一句代码执行之前。通过硬件重映射将其中一个物理存储区域映射到0x0
地址,可以将上述存储器区域之一映射到0x00000000
起始的地址空间。这样,在启动时,处理器就是去访问目标存储器里的bin
代码,就可以从映射后的地址空间读取栈指针和复位向量
。
2、如何实现地址重映射?
在STM32中,地址重映射是通过SYSCFG
模块(系统配置控制器)中的重映射寄存器(SYSCFG_MEMRMP
)来实现的。具体步骤如下:
2.1 复位后默认映射
当STM32复位后,根据BOOT引脚的状态(BOOT0和BOOT1
),选择不同的启动模式,从而决定将哪个存储器映射到0x00000000
:
BOOT1 | BOOT0 | 重映射目标 | 典型用途 |
---|---|---|---|
x | 0 | 从内部Flash启动(Flash映射到0x00000000 ,这个模式下,访问地址0x0和地址0x08000000都是访问Flash,也是访问代码) |
常规用户程序 |
0 | 1 | 从系统存储器启动(系统存储器,即系统Bootloader映射到0x00000000 ) |
使用内置Bootloader串口下载 |
1 | 1 | 从内部SRAM启动(SRAM映射到0x00000000 ,这个模式下,访问地址0x0和地址0x20000000都是访问SRAM,也是访问代码) |
调试或SRAM运行临时程序 |
2.1.1 硬件决定的地址重映射
这种地址重映射是通过芯片内部的硬件自动完成的,不需要软件干预
。—— 这个观点的来源依据?- 复位时,芯片内部通过一个硬件开关(称为
重映射开关
)将选中的物理存储区域别名映射
到0x0000_0000
- 例如:当BOOT0=0时,访问
0x0000_0000
实际访问的是0x0800_0000
的Flash内容。
2.1.2 STM32F4的内存地址分配
当STM32复位后,根据BOOT引脚的状态(BOOT0和BOOT1
),选择不同的启动模式,这时就只有三种启动模式,但是如果想从外部Flash或者存储器启动该怎么办?这个就是接下来的【运行时的重映射】,其发生在复位重映射之后。比如,复位重映射选择了从内部Flash启动,随后进入启动代码.s,从内部Flash取MSP和PC的初始值,然后执行
2.2 运行时的重映射
选择自举引脚后,应用程序软件可以将某些存储器设定为从代码空间进行访问(这样,可通过ICode 总线而非系统总线执行代码)。这样的修改通过在 SYSCFG 控制器中编程第 8.2.1节:SYSCFG存储器重映射寄存器 (SYSCFG_MEMRMP) 来实现。因此可重映射以下存储器:
- 主 Flash
- 系统存储器
- 嵌入式 SRAM1 (112 KB)
- FSMC 块 1(NOR/PSRAM 1 和 2)
2.2.0 SYSCFG存储器重映射寄存器
此寄存器的MEM_MODE位
用于对存储器重映射进行配置:
使用两个位来配置可在地址 0x0000 0000 访问的存储器区域。
从而通过软件选择物理重映射
,而旁路(绕开/忽略)
BOOT 引脚。这两个位的复位值和复位时 BOOT 引脚的设置相同
。当 BOOT 引脚设为 10 [(BOOT1,BOOT0)= (1,0)] 从主 Flash 中自举时,寄存器值为 0x00。当把
FSMC
重映射到地址 0x0000 0000 时,只有 FSMC 的 Bank1 的前两个区域(NOR/PSRAM 1和 NOR/PSRAM 2)可被重映射到低端地址
。在重映射模式下,CPU 可以通过ICode 总线
(而不是System 总线
)访问外部存储器来提高性能。偏移地址:0x00
复位值:0x0000 000X(
X 和 BOOT 引脚的设置相同
)
2.2.1 软件控制片上SRAM重映射
除了启动时的映射,在程序运行过程中,也可以通过配置SYSCFG_MEMRMP寄存器
来改变映射关系。例如,我们可以将SRAM映射到0x00000000,而将Flash映射到其原始地址(0x08000000)。这样做的目的通常是为了:
在SRAM中运行程序
(调试时更快速)。实现类似于中断向量表动态重定位的功能(在SRAM中重新设置向量表)。
注意:在STM32中,中断向量表的位置可以通过
NVIC
(嵌套向量中断控制器)中的向量表偏移寄存器(VTOR
)来重新定位,而不一定依赖于地址重映射。但地址重映射可以使得代码如同在0x0地址执行一样
。
2.2.1 实现步骤(以映射SRAM为例)
- 首先,需要确保SRAM已经被正确初始化(上电后SRAM默认可用)。
- 然后,通过配置SYSCFG_MEMRMP寄存器将SRAM映射到0地址:
// 寄存器写法示例:将SRAM重映射到0地址
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;// 使能SYSCFG时钟
SYSCFG->MEMRMP = SYSCFG_MEMRMP_MEM_MODE_1; //0x0000_0000 -> SRAM
//标准库写法
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);// 使能SYSCFG时钟
SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);// 设置重映射寄存器,将SRAM映射到0x00000000
- 此时,0x00000000开始的地址空间就是SRAM的前若干字节(具体大小取决于SRAM的大小)。
2.2.2 软件控制片外Flash重映射
如果从外部Flash运行程序,要把程序下载到外部Flash
2.3 注意事项
地址重映射只是提供了一个从0x0地址开始的视图,存储器的物理位置并没有改变。例如,当我们将Flash地址映射到0x0地址时,实际上是通过一个
别名访问(0x00000000对应0x08000000,0x00000004对应0x08000004)
。在启动后,如果改变了映射关系,需要特别注意中断向量表的处理。通常,我们会通过设置
VTOR
寄存器来指定新的中断向量表位置(例如,在重映射到SRAM后,如果要在SRAM中放置向量表,则需要将VTOR
设置为SRAM中的向量表地址)。在运行过程中改变映射关系时要小心,因为改变映射后,当前执行的代码可能会受到影响(如果代码不在0x0地址空间运行则可能不受影响,但通常改变映射前需要确保代码在不会受影响的区域运行)。
2.4 总结
STM32内部有一个名为 “内存地址重映射控制器” 的模块:
- 复位时,根据BOOT引脚状态生成
硬件映射选择信号
。 - 通过地址总线切换逻辑,将零地址空间访问转发到目标物理存储区。
- 目标存储区的物理地址被镜像到零地址空间,形成虚拟映射关系。
地址重映射是STM32启动过程中的一个重要机制,它通过硬件根据BOOT引脚的状态将不同的存储器映射到0地址。在程序运行时,也可以根据需要通过SYSCFG寄存器改变映射关系。这一机制使得STM32能够灵活地选择启动源,并在运行时动态调整存储器映射,以满足不同的需求(如在SRAM中调试程序)。
3、GD32F470启动简介
3.1 硬件BOOT开关
GD32F4xx系列微控制器提供了三种引导源,可以通过BOOT0和BOOT1
引脚来进行选择,该两个引脚的电平状态会在复位后的第四个CK_SYS(系统时钟)的上升沿进行锁存
。用户可自行选择所需要的引导源,通过设置上电复位和系统复位后的BOOT0和BOOT1
的引脚电平。一旦这两个引脚电平被采样,它们可以被释放并用于其他用途。
3.2 先BOOT再取SP值和PC值
上电序列或系统复位后,硬件根据BOOT电平自动选择引导源即进行了重映射
,然后Cortex-M4处理器先从0x0000 0000
地址获取栈顶值,再从0x0000 0004
地址获得引导代码的基地址,然后从引导代码的基地址开始执行程序。
3.3 SYSCFG寄存器
所选引导源对应的存储空间会被映射到引导存储空间,即从0x0000 0000
开始的地址空间。如果片上SRAM
(开始于0x2000 0000
的存储空间)被选为引导源
,用户必须在应用程序初始化代码中通过修改NVIC
异常向量表和偏移地址将向量表重置到SRAM
中。当主FLASH
存储器被选择作为引导源
,从0x0800 0000
开始的存储空间会被映射到引导存储空间。由于主FLASH存储器的Bank0或Bank1
均可映射到地址0x0800 0000
(通过配置SYSCFG_CFG0
寄存器的FMC_SWP
控制位),所以,微控制器可以使用该方法从Bank0或Bank1
中启动。
SYSCFG基地址:0x4001 3800
复位值:0x0000 000X(
根据BOOT0和BOOT1引脚的状态,X表示BOOT_MODE[1:0]
,可能为任意值)
BOOT_MODE[2:0]
这些位决定CPU在地址0x0000 0000
的访问值,复位之后,根据BOOT0和BOOT1
引脚的配置,通过下表获取BOOT_MODE[2:0]
的初始值
BOOT_MODE[2:0]
允许被软件写入。通过软件配置
可以选择更多的器件,一旦这些控制位通过软件写入,BOOT0和BOOT1引脚的电平状态将会被忽略
:- 000:
主FLASH存储器
(0x0800 0000~0x08FF FFFF
)被映射到地址0x0000 0000 - 001:引导装载代码所在
系统存储器
(0x1FFF 0000~0x1FFF 7FFF
)被映射到地址
0x0000 0000 - 010:
EXMC的SRAM/NOR 0和1(0x6000 0000~0x67FF FFFF)
被映射到地址0x0000
0000 - 011:
片上SRAM的SRAM0(0x2000 0000~0x2001 BFFF)
被映射到地址0x0000 0000 - 100:
EXMC的SDRAM Device0(0xC000 0000~0xC7FF FFFF)
被映射到地址0x0000
0000
- 000:
注意:即使映射到地址0x0000 0000,相应存储器仍可通过原始存储空间进行访问。
这展示出一个特点:MCU可以选择从外部存储器启动!如果是从外部存储器启动,那么显然需要提前将EXMC模块配置号才行,这样才能在重映射之后直接访问外部存储器的代码,可是在什么时候配置的EXMC模块的呢?
3.4 选项字节
为了使能引导块功能,选项字节中的BB控制位需要被置位。当该控制位被置位并且主FLASH存储器被选择作为引导源,微控制器从引导装载程序中启动并且引导装载程序跳至主FLASH存储器的Bank1中执行代码。在应用程序初始化代码中,用户必须通过修改NVIC异常向量表和偏移地址将向量表重置到Bank1基地址。
引导装载程序在生产器件的过程中已经被编程,用于通过以下其中一个通信接口重新编程主FLASH存储器:
- USART0(PA9和PA10)、USART2(PB10和PB11或PC10和PC11)。
4、N32G45启动简介
内嵌的自举程序存放在系统存储器 System Memory 内,用于通过 USART1 或者 USB-FS 接口(全速 USB 设
备,DFU 协议)对闪存存储器进行重新编程。当外部使用 4MHz、6MHz、8MHz、12MHz、16MHz、18MHz、
24MHz、32MHz 时钟(HSE)才能运行 USB-FS 接口。而 USART1 接口除了可以依靠上述的 8 个频率的外
部时钟(HSE)外,还可以依靠内部 8MHz 振荡器(HSI)运行
5、F28335启动简介
6、MPC5554启动简介
BOOTCFG取决于BOOT引脚的电平值
RCHW一起决定着BOOT模式
RCHW存放地址是可以变化的
审查控制寄存器
串行BOOT控制寄存器
7、硬件重映射
在STM32和Cortex-M架构的文档中,关于地址重映射的硬件开关机制的描述存在明确的依据。以下是具体来源和解释:
7.1 Cortex-M4权威指南(ARM官方文档)
文档:
《ARM Cortex-M4 Technical Reference Manual》(ARM DDI 0439)和《ARMv7-M Architecture Reference Manual》(ARM DDI 0403)。复位序列(Reset Sequence)(参考《ARMv7-M》章节 B1.5.5):
明确说明复位后,CPU会直接从0x0000_0000
读取MSP和复位向量,且此过程是硬件自动完成的,无需软件干预。内存映射(Memory Map)(参考《ARMv7-M》章节 B3.2):
提到Cortex-M内核通过“别名机制”访问零地址空间,具体映射源由芯片厂商(如ST)的硬件设计决定。结论:
Cortex-M内核硬件强制从零地址启动,映射到哪个物理存储区由芯片内部的硬件逻辑控制,与软件无关。
7.2 STM32参考手册(以STM32F4为例)
- 文档:
《STM32F4xx Reference Manual》(RM0090)。 - 启动配置(Boot configuration)(章节 2.4):
明确描述了BOOT引脚的电平状态如何选择映射源(Flash、SRAM或系统存储器)。
“The boot loader is activated when BOOT0 pin is high and BOOT1 pin is low. In this case, the hardware remaps the System Memory to address 0x0000_0000.”
SYSCFG寄存器(SYSCFG_MEMRMP)(章节 7.2.1):
提到复位后默认的映射由BOOT引脚决定,而运行时可通过SYSCFG寄存器修改映射(此时需软件参与)。硬件开关的明确描述:
在复位时序图(Figure 2. Boot modes)中,BOOT引脚的状态在复位信号的下降沿被锁存,芯片内部硬件自动完成映射切换,早于第一条指令执行。
7.3 硬件开关和软件开关
硬件开关的定义:此处的“硬件开关”指芯片内部的多路复用器(MUX)或地址解码逻辑,在复位时根据BOOT引脚状态自动选择物理存储区映射到零地址,完全无需代码执行。
硬件开关的时机:在处理器尚未执行任何代码时(即复位信号释放前的硬件初始化阶段)。以下设计特性证明重映射是硬件完成的:
- 复位时序要求:
Cortex-M内核要求在复位释放后的第一个时钟周期即读取0x0000_0000
的MSP和PC值。若依赖软件配置,时间上无法满足。复位后第一条指令执行前必须完成映射(否则无法获取PC)。 - BOOT引脚锁存时机:
STM32手册明确BOOT引脚状态在复位时被锁存,且映射切换在复位结束前完成(见RM0090的复位流程图)。BOOT引脚状态在复位时锁存,且手册明确描述硬件重映射。 - SYSCFG寄存器的存在意义:
如果复位映射是软件实现的,SYSCFG_MEMRMP寄存器将无需存在(因为软件可直接修改映射)。
7.4 硬件重映射的时序
STM32启动时硬件重映射的时序:
- 复位信号有效(低电平):
- CPU停止,BOOT引脚状态被锁存。
- 复位信号释放(上升沿):
- 硬件根据BOOT引脚选择映射源(Flash/SRAM/系统存储器)。
- 映射到
0x0000_0000
的物理区域生效。
- CPU读取MSP和PC:
- 从
0x0000_0000
读取栈指针(MSP)。 - 从
0x0000_0004
读取复位向量(PC)。
- 从
- 执行第一条指令:
- 此时已处于用户代码或Bootloader中。
7.5 总结
- 硬件开关的依据:Cortex-M架构要求 + STM32手册对BOOT引脚的描述。
- 硬件开关的实质:芯片内部的地址解码逻辑(多路复用器),在复位时自动完成映射。
- 与软件开关的区别:硬件开关在零周期(代码执行前)生效,软件开关需通过寄存器配置(如SYSCFG_MEMRMP)。
8、写程序验证功能
8.1 从SRAM启动
在SRAM中调试