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

STM32G031 Flash页擦除启用操作偶发HardFault问题求助

STM32G031 Flash页擦除偶尔触发HardFault的排查与解决

核心问题定位

你遇到的偶发HardFault,根源是CFGBSY位未清零就尝试写入FLASH_CR寄存器。从你提供的SR值0x40000能看到CFGBSY位被置位,该位表示Flash控制器正在执行配置类操作(比如选项字节加载、时钟相关的Flash配置),此时写入FLASH_CR会触发总线错误,直接引发HardFault。你的代码只等待了BSY1位,完全忽略了CFGBSY位,这是故障偶发的关键原因。

具体修复步骤

1. 等待Flash完全就绪(同时检查BSY1和CFGBSY)

把所有等待Flash就绪的循环,修改为同时等待BSY1和CFGBSY两位清零:

// 替换原有的仅检查BSY1的循环
while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) {
    __asm("nop");
}

2. 优化错误标志清除逻辑

原代码逐个判断清除错误位,效率低且易遗漏,直接按手册要求写入错误位掩码即可一次性清除所有错误标志:

// 替换原有的多个if判断
FLASH->SR = FLASH_SR_OPTVERR | FLASH_SR_RDERR | FLASH_SR_FASTERR | 
            FLASH_SR_MISERR | FLASH_SR_PGSERR | FLASH_SR_SIZERR | 
            FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR | FLASH_SR_OPERR;

3. 确保解锁操作安全(可选)

在解锁前检查LOCK位,避免重复执行解锁序列(错误的解锁序列会直接锁死FLASH_CR并触发HardFault):

if ((FLASH->CR & FLASH_CR_LOCK) != 0) {
    FLASH->KEYR = 0x45670123;
    FLASH->KEYR = 0xCDEF89AB;
}

4. 规范页擦除寄存器操作顺序

按RM0444手册步骤,合并寄存器操作减少写入次数,逻辑更清晰:

// 先清除原有PER和PNB位,再同时配置
FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_PNB);
FLASH->CR |= FLASH_CR_PER | (0xF << FLASH_CR_PNB_Pos);

修复后的关键代码片段

void FLASH_WriteValue(uint16_t val) {
    uint32_t old_primask = __get_PRIMASK();
    __disable_irq();

    // 等待Flash完全就绪(BSY1 + CFGBSY)
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 安全解锁Flash
    if ((FLASH->CR & FLASH_CR_LOCK) != 0) {
        FLASH->KEYR = 0x45670123;
        FLASH->KEYR = 0xCDEF89AB;
    }

    // 等待Flash就绪
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 清除所有错误标志
    FLASH->SR = FLASH_SR_OPTVERR | FLASH_SR_RDERR | FLASH_SR_FASTERR | 
                FLASH_SR_MISERR | FLASH_SR_PGSERR | FLASH_SR_SIZERR | 
                FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR | FLASH_SR_OPERR;

    // 等待Flash就绪
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 配置页擦除参数
    FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_PNB);
    FLASH->CR |= FLASH_CR_PER | (0xF << FLASH_CR_PNB_Pos);

    // 启动擦除
    FLASH->CR |= FLASH_CR_STRT;

    // 等待擦除完成
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 关闭页擦除模式
    FLASH->CR &= ~FLASH_CR_PER;

    // 后续编程操作同理,所有等待都要检查BSY1和CFGBSY
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 清除错误标志
    FLASH->SR = FLASH_SR_OPTVERR | FLASH_SR_RDERR | FLASH_SR_FASTERR | 
                FLASH_SR_MISERR | FLASH_SR_PGSERR | FLASH_SR_SIZERR | 
                FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR | FLASH_SR_OPERR;

    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    // 写入数据
    uint32_t address = 0x08007800;
    uint32_t data = val;
    uint32_t dataPadding = 0;
    FLASH->CR |= FLASH_CR_PG;

    *(volatile uint32_t*)address = data;
    *(volatile uint32_t*)(address + 4) = dataPadding;

    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_CFGBSY)) != 0) { __asm("nop"); }

    FLASH->CR &= ~FLASH_CR_PG;

    // 锁定Flash
    FLASH->CR |= FLASH_CR_LOCK;

    __set_PRIMASK(old_primask);
}

额外注意事项

  • 确保系统时钟配置稳定,Flash操作对时钟稳定性要求高,时钟异常可能导致CFGBSY位异常置位
  • 避免在Flash操作期间触发任何修改Flash配置的操作(比如选项字节编程、时钟切换)

内容的提问来源于stack exchange,提问作者Henrik Rune Jakobsen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:12:02