STM32:(0)上电启动之地址重映射

发布于:2025-08-17 ⋅ 阅读:(14) ⋅ 点赞:(0)

在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内部有一个名为 “内存地址重映射控制器” 的模块:

  1. 复位时,根据BOOT引脚状态生成硬件映射选择信号
  2. 通过地址总线切换逻辑,将零地址空间访问转发到目标物理存储区。
  3. 目标存储区的物理地址被镜像到零地址空间,形成虚拟映射关系。

地址重映射是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
  • 注意:即使映射到地址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引脚状态自动选择物理存储区映射到零地址,完全无需代码执行

硬件开关的时机:在处理器尚未执行任何代码时(即复位信号释放前的硬件初始化阶段)。以下设计特性证明重映射是硬件完成的:

  1. 复位时序要求
    Cortex-M内核要求在复位释放后的第一个时钟周期即读取 0x0000_0000 的MSP和PC值。若依赖软件配置,时间上无法满足。复位后第一条指令执行前必须完成映射(否则无法获取PC)。
  2. BOOT引脚锁存时机
    STM32手册明确BOOT引脚状态在复位时被锁存,且映射切换在复位结束前完成(见RM0090的复位流程图)。BOOT引脚状态在复位时锁存,且手册明确描述硬件重映射。
  3. SYSCFG寄存器的存在意义
    如果复位映射是软件实现的,SYSCFG_MEMRMP寄存器将无需存在(因为软件可直接修改映射)。

7.4 硬件重映射的时序

STM32启动时硬件重映射的时序:

  1. 复位信号有效(低电平):
    • CPU停止,BOOT引脚状态被锁存。
  2. 复位信号释放(上升沿):
    • 硬件根据BOOT引脚选择映射源(Flash/SRAM/系统存储器)。
    • 映射到 0x0000_0000 的物理区域生效。
  3. CPU读取MSP和PC
    • 0x0000_0000 读取栈指针(MSP)。
    • 0x0000_0004 读取复位向量(PC)。
  4. 执行第一条指令
    • 此时已处于用户代码或Bootloader中。

7.5 总结

  • 硬件开关的依据:Cortex-M架构要求 + STM32手册对BOOT引脚的描述。
  • 硬件开关的实质:芯片内部的地址解码逻辑(多路复用器),在复位时自动完成映射。
  • 与软件开关的区别:硬件开关在零周期(代码执行前)生效,软件开关需通过寄存器配置(如SYSCFG_MEMRMP)。

8、写程序验证功能

8.1 从SRAM启动

在SRAM中调试

8.2 复制到SRAM中运行


网站公告

今日签到

点亮在社区的每一天
去签到