You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F413ZH仅重建项目后可写入Flash问题求助

STM32F413ZH Flash写入异常:修改写入值后地址仍保留旧值

问题详情

测试STM32F413ZH的Flash基础写入功能,最初成功将0x42写入扇区11的0x080E0000地址,断电重启后数据正常保留。但把写入值改成0x40后,该地址始终显示旧值0x42,完全没变化。

调试时断点跟踪:

  • HAL_Init()执行后读0x080E0000是0xff
  • HAL_FLASH_Program()执行前读该地址还是0xff
  • HAL_FLASH_Lock()执行后读值变成0x42,哪怕代码里已经把写入参数改成0x40了

只有完全重建项目后,才能成功写入新值0x40。

涉及代码片段:

HAL_Init(); 

HAL_FLASH_Unlock();

FLASH_Erase_Sector(FLASH_SECTOR_11, VOLTAGE_RANGE_3);

HAL_FLASH_Program(TYPEPROGRAM_WORD, 0x080E0000, 0x40); // 修改后的目标值

HAL_FLASH_Lock();

链接脚本(.lds)配置:

MEMORY
{
    FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 1536K-128K
    DATA (RWX) : ORIGIN = 0x080E0000, LENGTH = 128K
    SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 320K
}

_estack = 0x20050000;

SECTIONS
{
    .user_data :
    {
        . = ALIGN(4);
        KEEP(*(.user_data))
        . = ALIGN(4);
    } > DATA
}

排查与解决方法

1. 编译器优化缓存了旧写入值

如果开启了-O1及以上的编译器优化,编译器可能会把HAL_FLASH_Program的第三个参数当成常量缓存起来,哪怕你修改了代码里的数值,实际运行时还是用旧值0x42。

解决办法:

  • 给写入值加volatile修饰:定义成volatile uint32_t write_val = 0x40;再传入函数,强制编译器每次都读取最新值。
  • 临时关闭该函数的优化:在函数前加__attribute__((optimize("O0"))),或者在IDE里把这个文件的优化级别改成O0。

2. 调试器的Flash缓存没刷新

ST-Link这类调试器会缓存Flash区域的读取结果,你看到的可能是缓存里的旧数据,不是Flash实际存储的内容。

解决办法:

  • 调试时手动刷新Flash缓存:在IDE的调试面板里找“Flash Refresh”之类的选项,刷新后再读地址。
  • 断电重启后验证:跳过调试器缓存,直接硬件重启后读Flash值。

3. 链接脚本的DATA段配置干扰Flash写入

你把0x080E0000这个Flash区域定义成了DATA (RWX),编译器会把它当成RAM类的可读写可执行区域,调试器可能会把这段映射到RAM镜像里,而非实际Flash空间。

解决办法:

  • 修改链接脚本,单独给用户Flash数据定义一个段:
MEMORY
{
    FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 1536K-128K
    USER_FLASH (RWX) : ORIGIN = 0x080E0000, LENGTH = 128K
    SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 320K
}

SECTIONS
{
    .user_data :
    {
        . = ALIGN(4);
        KEEP(*(.user_data))
        . = ALIGN(4);
    } > USER_FLASH
}
  • 确保这个地址没有被链接脚本分配给其他程序段,避免调试器的内存映射搞混。

4. Flash擦除操作没成功

代码里调用了FLASH_Erase_Sector,但可能电压范围设置错了或者扇区编号不对,导致擦除失败,Flash里还留着旧值。

解决办法:

  • 检查擦除操作的返回值,确认是否成功:
uint32_t sector_err = 0;
HAL_StatusTypeDef erase_status = FLASH_Erase_Sector(FLASH_SECTOR_11, VOLTAGE_RANGE_3, &sector_err);
if (erase_status != HAL_OK) {
    // 这里加错误处理,比如打印扇区错误码
}
  • 核对STM32F413ZH的扇区映射:扇区11对应的地址范围确实是0x080E0000~0x080FFFFF,别搞混扇区编号。

内容的提问来源于stack exchange,提问作者b-rad90

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:42:29