STM32 内存映射和地址重映射
STM32的内存映射与地址重映射是其底层架构的核心机制,理解它们对于深入掌握单片机工作原理、进行高效开发和复杂问题调试至关重要。下面将结合搜索结果,从概念、机制、实现与应用等多个角度进行详细阐述。
一、内存映射:为“房间”分配“门牌号”
内存映射的核心思想是为物理存储器分配逻辑地址。STM32基于32位地址总线,拥有一个从0x0000 0000到0xFFFF FFFF的、连续的4GB理论地址空间。然而,芯片内部实际的物理存储器(如Flash、SRAM)容量远小于4GB。这个巨大的地址空间就像一座规划好的城市,而内存映射就是为城市中实际建好的“建筑”(物理存储器)分配唯一的“门牌号”(逻辑地址)。
根据ARM Cortex-M内核的规定,这4GB空间被均匀划分为8个块(Block),每块大小为512MB,并规定了各自的主要用途:
- Block 0 (0x0000 0000 - 0x1FFF FFFF):这是一个特殊的启动块。系统复位后,CPU总是从0地址开始执行,因此该块被设计为可重映射区域,通过BOOT引脚配置,可以将内部Flash、系统存储器或SRAM映射到此。
- Block 1 (0x2000 0000 - 0x3FFF FFFF):用于连接内部SRAM。所有Cortex-M芯片的SRAM都起始于
0x2000 0000,用于存放运行时变量、堆栈等数据。 - Block 2 (0x4000 0000 - 0x5FFF FFFF):用于连接片上外设。这是寄存器映射发生的地方。外设(如GPIO、USART)的控制单元以4字节(32位)为一个寄存器,被分配了特定地址。为了方便编程,工程师给这些地址单元起了别名,这就是寄存器映射。例如,操作GPIOA的输出数据寄存器,本质上是通过指针访问
0x4002 0410这个地址。
- STM32内部通过AHB(高级高性能总线)和APB(高级外设总线)连接内核与外设。外设寄存器被进一步映射到更具体的地址段:
- APB1外设:地址范围约为
0x40000000至0x4000FFFF,连接低速外设(如TIM2、TIM3、UART2等)。 - APB2外设:地址范围约为
0x40010000至0x4001FFFF,连接高速外设(如GPIOA-GPIOG、SPI1、ADC1、USART1等)。 - AHB外设:地址范围约为
0x40020000开始,连接DMA、CRC、以太网等高速模块。
其他块则用于外部存储器、Cortex-M内核内部外设等。
二、地址重映射:启动时的“地址魔术”
地址重映射是内存映射在启动阶段的一个关键应用,其核心目的是解决CPU固定启动地址与存储器物理地址不匹配的矛盾。
-
为什么需要重映射? 根据ARM Cortex-M内核设计,处理器上电或复位后,会执行两个固定的硬件操作:从地址
0x0000 0000读取主栈指针(MSP)初始值,从地址0x0000 0004读取复位向量(程序计数器PC初始值)。这意味着,必须确保0地址处有有效的代码。然而,STM32的主要程序存储器——用户Flash的物理起始地址是0x0800 0000,系统Bootloader在0x1FFF F000附近,SRAM在0x2000 0000。它们的物理地址都不在0。因此,需要通过硬件“重映射”,将0地址空间“指向”这些实际的物理存储器。 -
如何实现重映射? 重映射主要通过硬件根据BOOT引脚的电平在复位时自动完成。具体模式如下:
| BOOT1 | BOOT0 | 启动模式 | 映射关系 | 主要用途 |
|---|---|---|---|---|
| X | 0 | 主Flash启动 | 将Flash (0x0800 0000) 映射到 0x0000 0000 |
常规运行模式,程序存储在Flash中。 |
| 0 | 1 | 系统存储器启动 | 将系统存储器(Bootloader, 0x1FFF F000)映射到 0x0000 0000 |
使用串口(ISP)下载程序到Flash。 |
| 1 | 1 | 内置SRAM启动 | 将SRAM (0x2000 0000) 映射到 0x0000 0000 |
用于调试,代码在SRAM中运行,无需擦写Flash。 |
例如,在最常见的BOOT0=0模式下,虽然我们的程序被烧录到0x0800 0000,但上电后,硬件将这块Flash“别名”映射到了0地址。因此,CPU从0地址取指令,实际上执行的是Flash中的程序。
- 运行时的重映射 除了复位时的硬件重映射,在程序运行后,也可以通过软件配置SYSCFG模块中的存储器重映射寄存器(
SYSCFG_MEMRMP)来改变映射关系。这通常用于高级场景,例如将程序从内部Flash切换到外部Nor Flash执行,此时需要特别注意中断向量表(VTOR寄存器)的重定位。
三、对程序开发的实际影响
理解内存映射和重映射,能帮助我们更清晰地认识程序的存储与运行:
- 程序段的分布:编译器将代码分类到不同段(Section),链接器根据内存映射将它们放置到正确地址。例如,代码段(
.text)和常量(.rodata)存放在Flash(0x0800 0000开始);已初始化的全局变量(.data)其初始值在Flash,运行时本体在SRAM;未初始化变量(.bss)在SRAM;堆(heap)和栈(stack)也在SRAM中向上或向下增长。 - 启动过程:上电后,硬件根据BOOT引脚重映射地址。CPU从0地址(实际是映射后的Flash/系统存储器/SRAM)读取MSP和PC值,然后跳转到复位向量执行启动文件代码,该代码负责将
.data段从Flash复制到SRAM,并将.bss段清零,最后才跳转到main()函数。 - 外设编程基础:我们通过
GPIOA->ODR = 0xFFFF;这样的语句操作外设,其本质就是通过寄存器映射访问Block2中的特定地址。GPIOA这个宏定义,就是一个指向0x4002 0000(GPIOA基址)的结构体指针。
扩展概念:需要注意的是,STM32还有另一种“重映射”(Remap),通常指外设引脚功能的重映射(即Alternate Function),例如将USART1的TX引脚从PA9重映射到PB6。这与本文讨论的存储器地址重映射是不同的概念,但中文术语相同,需根据上下文区分。
总结来说,内存映射是ST公司根据ARM架构为芯片所有资源(存储器和外设)分配逻辑地址的静态蓝图;而地址重映射是在启动或运行时,动态改变CPU对0地址空间的访问目标的关键硬件机制。二者共同构成了STM32灵活、强大的存储器访问基础。
更多推荐
所有评论(0)