一、存储区划分与变量分类
STM32的存储空间分为Flash(非易失性)和RAM(易失性)两大区域:
Flash存储器
- 代码段(Code):存储程序指令和常量(如字符串、const变量)。
- RW-Data段:存储已初始化的全局变量和静态变量的初始值,这些值在启动时会被复制到RAM中。
- RO-Data段:存放只读数据(如const修饰的全局变量)。
RAM存储器
- Data段:存放已初始化的全局变量和静态变量的运行时值(从Flash的RW-Data段复制而来)。
- BSS段:存放未初始化或初始化为0的全局变量和静态变量,启动时由系统清零。
- 堆(Heap):动态内存分配区域(如malloc申请的内存)。
- 栈(Stack):存储局部变量和函数调用上下文。
二、启动时的数据加载流程
STM32上电后,启动文件(如startup_stm32fxxx.s
)会执行以下操作:
初始化栈和堆指针
根据链接脚本(.ld或.sct文件)定义的Stack_Size
和Heap_Size
分配内存空间。复制RW-Data到RAM
- 从Flash的RW-Data段(如地址
0x08000000+Code_Size
)读取已初始化变量的初始值。 - 将这些值复制到RAM的Data段(如起始地址
0x20000000
)。
- 从Flash的RW-Data段(如地址
清零BSS段
将RAM中BSS段对应的区域全部初始化为0。跳转到main函数
完成上述初始化后,程序开始执行用户代码。
三、关键机制详解
1. RW-Data的双重存储
- Flash中的静态存储:初始值保存在Flash的RW-Data段(如
0x0800xxxx
)。 - RAM中的动态运行:启动时复制到RAM的Data段(如
0x2000xxxx
),确保变量在运行时可修改。
2. const变量的特殊处理
- 全局const变量:存储在Flash的RO-Data段,无法修改。
- 局部const变量:可能存储在栈中(取决于编译器优化),但仍为只读。
3. 动态数据管理
- 堆区:通过
malloc
动态申请的内存位于堆区,需手动释放。 - 栈区:局部变量和函数参数自动分配/释放,空间有限需避免溢出。
四、实例分析与调试
1. 查看变量存储位置
通过编译生成的.map
文件可确认变量分配:
- Code和RO-Data:映射到Flash地址(如
0x08000000
)。 - RW-Data和BSS:映射到RAM地址(如
0x20000000
)。
2. 手动访问Flash数据
通过指针可直接读取Flash中的变量初始值:
// 读取Flash中0x08000000地址的32位数据
uint32_t flash_data = *(__IO uint32_t*)(0x08000000);
此方法常用于读取存储在Flash末页的配置参数。
3. 优化存储空间
- 减少全局变量,优先使用局部变量和静态变量。
- 合理设置堆栈大小(通过修改启动文件)以避免溢出。
五、高级应用场景
1. IAP(在应用中编程)
将用户数据存储在Flash末页,通过HAL_FLASH_Program
函数动态更新。
2. 选项字节配置
通过操作选项字节(Option Bytes)设置读/写保护,增强安全性。
3. 从Flash搬移代码到RAM执行
对实时性要求高的函数(如中断服务程序),可将其加载到RAM中运行以提升速度。