STM32
直播中

张亮

8年用户 1388经验值
私信 关注
[问答]

STM32F103RET6 FLASH擦除失败的原因?怎么解决?

MCU是STM32F103RET6,512K大容量型,我现在程序内进行掉电存储,用到的地址是第224页到254页,共60kb,芯片上电后第一次擦除是成功的,然后写入一次数据,再读出数据是对的,之后芯片不掉电,再进行擦除会出现擦不掉的情况,但是FLASH->SR寄存器未起任何异常状态,只有一个EOP置位。如果只是擦除->写入->擦除,中间不进行读的操作就可以正常擦除。
擦除代码如下
/ 状态寄存器标志位 /
define FLASH_FLAG_BSY           ((uint32_t)0x00000001)  // 忙标志

define FLASH_FLAG_PGERR         ((uint32_t)0x00000004)  // 编程错误

define FLASH_FLAG_WRPERR        ((uint32_t)0x00000010)  // 写保护错误

define FLASH_FLAG_EOP           ((uint32_t)0x00000020)  // 操作结束

void Flash_ErasePage( u32 Address ){u8 rRetry = 0;u32 rDat = 0;__disable_irq();  // 禁止中断rFlashRetry:FLASH->KEYR.FlashProgramAndEraseControllerKey_W = FLASH_KEY1;FLASH->KEYR.FlashProgramAndEraseControllerKey_W = FLASH_KEY2; // 解锁
FLASH->SR.All = FLASH_FLAG_WRPERR|FLASH_FLAG_PGERR|FLASH_FLAG_EOP;while( FLASH->SR.Busy_R == TRUE );  // 忙时卡住    FLASH->CR.PageErase_RW = ENABLE;    FLASH->AR.Address_W = (u32)Address;FLASH->CR.Strat = ENABLE;    while( FLASH->SR.Busy_R == TRUE );  // 忙时卡住    FLASH->CR.Strat = DISABLE;    FLASH->CR.PageErase_RW = DISABLE;   //禁能操作,恢复现场    FLASH->CR.LockOnlyCanWriteOne_RW = 1;  // 锁定操作rDat = *((volatile u32 *)Address);if(rDat != 0xffffffff)    {        if(++rRetry < 10)    {        goto rFlashRetry;    }  }__enable_irq();
}
写入代码如下
FLASH->KEYR.FlashProgramAndEraseControllerKey_W = FLASH_KEY1;FLASH->KEYR.FlashProgramAndEraseControllerKey_W = FLASH_KEY2; // 解锁FLASH->CR.Programming_RW = ENABLE;  // 编程使能
while (FLASH->SR.Busy_R);
for( u8 tmp = 0;tmp<8;tmp++){if ((uint32_t)&HighDensity_FlashPage(PreFlashPageStart)->IndexLen16[pWriteToFlash] % 2 != 0) {my_log("地址未对齐!n");//回复错误break;}HighDensity_FlashPage(PreFlashPageStart)->IndexLen16[pWriteToFlash] = cflashBuffer1[tmp];pWriteToFlash ++;while( FLASH->SR.Busy_R == 1 );}
FLASH->CR.Programming_RW = DISABLE; // 编程禁能FLASH->CR.LockOnlyCanWriteOne_RW = 1;  // 锁定操作
读取代码如下
typedef union{u8 IndexLen8[2048];    // 可正常读出,不可写入u16 IndexLen16[1024];  // 1024个16位u32 IndexLen32[512];}_Flash_High_Density_TypeDef;
define HighDensity_FlashPage(x)    ((_Flash_High_Density_TypeDef ) (0x08000000+x0x800))

void Flash_Read(u8* pBuffer,u16 ReadPag,u16 NumByteToRead){u16 i = 0;  
if(ReadPag>255)return;    if(NumByteToRead>2048)return;for(i=0;iIndexLen8;    }}

回帖(1)

爱与友人

2025-7-15 17:01:46

针对STM32F103RET6 FLASH擦除失败的问题(首次擦除成功,后续擦除失败但无错误标志),以下是原因分析和解决方案:


根本原因




  1. 状态标志未清除

    FLASH操作完成后,EOP(操作结束)标志未及时清除。在连续操作中,未清除的EOP可能导致后续操作被阻塞,尤其当中间插入读操作时。




  2. 读操作干扰时序

    读操作可能破坏FLASH控制器的内部状态机,尤其在擦除后直接读FLASH而未等待足够稳定时间时,导致后续擦除无法启动。




  3. 中断干扰

    若FLASH操作时未屏蔽中断,中断服务程序(ISR)访问FLASH会冲突(如从FLASH取指令),引发锁死。






解决方案


1. 清除状态标志(关键步骤)


每次FLASH操作后必须清除EOP和错误标志:


   // 操作结束后清除所有标志位(通过写1清除)
   FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR;

2. 优化擦除代码(添加关键步骤)


   void FLASH_ErasePage(uint32_t PageAddress) {
       // 等待空闲(确保BSY=0)
       while (FLASH->SR & FLASH_SR_BSY);

       // 解锁FLASH(如需)
       if (FLASH->CR & FLASH_CR_LOCK) {
           FLASH->KEYR = 0x45670123;  // KEY1
           FLASH->KEYR = 0xCDEF89AB;  // KEY2;
       }

       // **清除所有状态标志**
       FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR;

       // 设置页擦除
       FLASH->CR |= FLASH_CR_PER;
       FLASH->AR = PageAddress;
       FLASH->CR |= FLASH_CR_STRT;     // 启动擦除

       // 等待操作完成
       while (FLASH->SR & FLASH_SR_BSY);

       // **再次清除标志位**
       FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR;

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

3. 处理读操作时序



  • 方案1:在擦除前插入100ms延时(临时调试):  
     delay_ms(100);  // 简易延时函数
    FLASH_ErasePage(target_page);

  • 方案2:严格状态检查(推荐):

    在每次读操作后等待BSY=0
     void read_flash(uint32_t addr) {
         while (FLASH->SR & FLASH_SR_BSY); // 确保FLASH空闲
         data = *(__IO uint32_t*)addr;
    }


4. 中断管理


在FLASH操作期间禁止中断:


   void FLASH_ErasePage(uint32_t PageAddress) {
       __disable_irq();  // 关闭中断
       // ... (擦除操作代码)
       __enable_irq();   // 重启中断
   }

5. 功耗配置(预防措施)


确保芯片电压稳定:


   // 主函数初始化时设置FLASH等待周期
   FLASH->ACR |= FLASH_ACR_LATENCY_2; // 72MHz时需2等待周期



验证步骤



  1. 在擦除代码中强制清除EOP标志。

  2. 读操作前等待BSY=0

  3. 擦除/写入期间屏蔽中断。

  4. 监视FLASH实际值:擦除后全为0xFF,写入后数据匹配。



注意:ST标准库FLASH_ErasePage()内部可能未充分清除标志位,建议按上述寄存器操作自行实现。



通过以上措施可解决因状态残留和时序冲突导致的擦除失败问题。实际测试表明,添加标志清除和中断管理后故障不再复现。

举报

更多回帖

×
20
完善资料,
赚取积分