ARM Cortex-M 内存映射详解:如何基于寄存器直接读写 寄存器映射方式编码程序 直接操作硬件寄存器来控制 MCU

发布于:2025-03-10 ⋅ 阅读:(16) ⋅ 点赞:(0)

ARM Cortex-M 的系统映射空间

​ 在 STM32 等 ARM Cortex-M 系列 MCU 中,内存地址空间按照 存储功能 进行了严格划分,包括 Flash(程序存储)、RAM(数据存储)、外设寄存器(GPIO、UART、SPI 等)以及系统控制寄存器(中断、调试相关)。下面详细解析各个地址段的作用和特点。

1.1 内存地址映射总览

​ 在 ARM Cortex-M 处理器(如 STM32 系列 MCU)中地址空间通常采用 32 位地址总线,因此可寻址 4GB(0x00000000 ~ 0xFFFFFFFF),但在嵌入式系统中,MCU 的可用内存远小于 4GB,并且地址空间被划分为多个功能区。

地址范围 存储内容 描述
0x00000000 - 0x000003FF 向量表(Vector Table) 存放复位向量(起始栈指针)、异常入口地址
0x08000000 - 0x0800FFFF Flash(代码存储) 存储 程序代码(.text)只读数据(.rodata)
0x1FFFF000 - 0x1FFFF7FF 系统 Boot ROM 预留给 MCU BootLoader(ISP、IAP 相关)
0x20000000 - 0x20004FFF RAM(可变数据存储) SRAM(RAM,存储 .data.bss、堆、栈)
0x40000000 - 0x500607FF 外设寄存器 片上 GPIO、UART、SPI、I2C、TIM、ADC 等外设的控制寄存器
0xE0000000 - 0xE00FFFFF System 控制寄存器 NVIC(中断控制)、SysTick(系统定时器)、调试接口

1.20x00000000 - 0x000003FF:向量表 (Vector Table)

​ MCU 复位后,系统从 0x00000000 地址处读取向量表,该表包含了复位后跳转到 main() 的入口地址。

作用:

  • 存储异常和中断向量表,即异常/中断入口地址
  • 第一项存放的是栈指针初值(SP),用于 CPU 复位时初始化堆栈。
  • 其余项是中断服务程序(ISR)地址,例如:
    • 复位向量(Reset Vector)
    • 硬件故障处理(HardFault、NMI)
    • 外设中断(UART、GPIO、TIM 等)

向量表示例

0x00000000: 0x20004FFF   ; 初始栈指针地址(RAM 顶部)
0x00000004: 0x08000239   ; 复位处理函数(Reset_Handler)
0x00000008: 0x08000321   ; NMI_Handler
0x0000000C: 0x08000345   ; HardFault_Handler

该表通存储于 Flash(0x08000000)

1.3 0x08000000 - 0x0800FFFF:Flash(程序存储)

作用

  • 存放 MCU 固件(程序代码),包括:
    • .text(代码段)
    • .rodata(只读数据)
  • 代码段的存储区域,运行时 CPU 直接从 Flash 取指令,不会加载到 RAM。

特点

  • Flash 只能按扇区擦除,不能按字节修改(通常 1 次擦除需要 20ms 左右)。
  • RAM 访问速度远快于 Flash,因此 关键代码可拷贝到 RAM 执行

1.4 0x1FFFF000 - 0x1FFFF7FF:系统 Boot ROM

作用

  • STM32 MCU 内置 Bootloader(引导程序),支持:
    • ISP(In-System Programming):通过 UART/SWD 进行固件烧录。
    • IAP(In-Application Programming):运行时更新 Flash 代码。

特点

  • Bootloader 可以让 MCU 在 Flash 损坏的情况下仍然可以进行固件更新
  • 通过 BOOT0 / BOOT1 硬件引脚可以选择启动 Flash 还是 Bootloader

1.5 0x20000000 - 0x20004FFF:RAM(数据存储)

作用

  • 存储 MCU 运行时的变量和数据,包括:
    • .data 段:已初始化的全局变量(上电后从 Flash 复制到 RAM)
    • .bss 段:未初始化的全局变量(上电后初始化为 0)
    • 堆(Heap):malloc() 动态分配的内存
    • 栈(Stack**)**:局部变量、函数调用信息

结构

+------------------+ 0x20005000 (RAM 结束)
|       Heap      |  动态分配(malloc)
+------------------+
|       Stack     |  栈(局部变量、返回地址)
+------------------+
|      .bss       |  未初始化数据(RAM)
+------------------+
|      .data      |  已初始化全局变量(RAM)
+------------------+ 0x20000000 (RAM 起始)

注意

  • 栈向下增长,堆向上增长,如果二者相遇会导致崩溃(Stack Overflow)。
  • 优化方法:
    • 尽量使用 const 让数据存入 Flash,减少 RAM 占用。
    • 避免使用 malloc(),防止内存碎片化。

1.6 0x40000000 - 0x500607FF:外设寄存器

作用

  • 用于 MCU 片上外设的控制,如:
    • GPIO(0x40010800):控制 I/O 口输入/输出。
    • UART(0x40013800):串口收发数据。
    • SPI(0x40013000):SPI 传输数据。
    • ADC(0x40012400):模拟信号转换。

代码示例

#define GPIOC_ODR  (*((volatile uint32_t*) 0x4001100C))
GPIOC_ODR |= (1 << 13); // 置位 PC13(LED 亮)

特点

  • 访问外设寄存器时 必须使用 volatile 修饰,否则编译器可能优化导致错误。

1.7 0xE0000000 - 0xE00FFFFF:System 控制寄存器

作用

  • 控制 中断、调试、系统时钟,主要包括:
    • NVIC(Nested Vectored Interrupt Controller,中断控制器)
    • SysTick(系统定时器)
    • SCB(System Control Block,系统控制块)

代码示例

#define NVIC_ISER0 (*((volatile uint32_t*) 0xE000E100))
NVIC_ISER0 |= (1 << 6); // 使能外部中断 6

特点

  • NVIC 允许中断嵌套,可以配置优先级。
  • SysTick 是 Cortex-M 内置的 24-bit 计时器,用于系统心跳计时