STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题

1.问题描述

产品在运行过程中需要保存一些断电不丢失的数据,为此将数据保存在STM32内部的flash中。但是测试人员在测试的过程中,修改了数据参数,直接断电重启机器,并没有等待flash的操作时间,导致原有的数据丢失。

2. 原理分析

本产品硬件平台是基于STM32F429,采用HAL库开发。在操作内部flash这部分中,查看数据手册得知:
STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题_第1张图片
STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题_第2张图片
对于操作128KB的扇区擦写32位数据需要的时间,典型值是1S。最大值是2S。才能保证操作完成。
而在参考手册中提到:在Flash操作期间发生器件复位,则无法保证flash中的内容,
STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题_第3张图片
为此,我特地在擦写过程中,断电,然后看flash中的数据是什么,经过多次擦写,断电,然后用ST-Link查看扇区的数据发现,其数据如图所示:
STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题_第4张图片
STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题_第5张图片
数据为0xFFFFFFFF 或者0x00000000 不定。但是经过多次发现,基本上都是在这两个数据当中变化,无规则。
为此在判断的时候,可以采用这两个数据进行判断。

3. 解决方案:

采用一块Backup sector(备份扇区)用来存储修改参数前的数据,当第一块扇区数据丢失的时候,就读取备份扇区的内容。
具体看代码:

void flash_set_date(void)
{
    static u8 update_flag=0;
    uint8_t i=0;
    //读取扇区内容,2块扇区内容同时为0xFFFFFFFF 表示没有参数,使用默认值
    if((FLASH_ReadWord(MDATA_BASE+0)==0xffffffff)&&(FLASH_ReadWord(BACK_FLASH_BASE+0)==0xffffffff))
    {
        GD_BUF[INDEX_ID] = 0xff;//子控制板的ID默认设置为0xff
        GD_BUF[INDEX_RED_CURRENT]=110;       //红光电流默认值100mA
        GD_BUF[INDEX_FORWORD_V]=38;      //前向光默认值500
        GD_BUF[INDEX_PD_BACK]=193;       //回光默认值2500
        GD_BUF[INDEX_5620_A2]=27;
        GD_BUF[INDEX_5620_B2]=27;
        GD_BUF[INDEX_BIAS_V]=154;     //偏置电压默认值2000

        GD_BUF[INDEX_OV_DTEMP]=40;     //电水冷板温度报警默认值40
        GD_BUF[INDEX_ADJ_POWER]=187;   //满功率微调值默认186

        GD_BUF[INDEX_OV_TEMP]=45;      //泵源温度报警默认值45
        GD_BUF[INDEX_OV_GTEMP]=35;     //光水冷板温度报警默认值35
        GD_BUF[INDEX_5620_A1]=27;   

        GD_BUF[INDEX_OVER_V]=131;//过压报警点
        GD_BUF[INDEX_LOW_V]=100;//低压报警点
        GD_BUF[INDEX_OVER_I]=181;//过流报警点
    }
    else//有参数,先读取扇区1
    {
        for(i=0;i4);
        }
        //意外擦除了
        if((GD_BUF_FLASH[FLASH_RED_CURRENT]==0xffffffff)&&(GD_BUF_FLASH[FLASH_FORWORD_V]==0xffffffff)&&(GD_BUF_FLASH[FLASH_PD_BACK]==0xffffffff)\
        &&(GD_BUF_FLASH[FLASH_BIAS_V]==0xffffffff))update_flag=1;
        //被意外清零了。
        if((GD_BUF_FLASH[FLASH_RED_CURRENT]==0)&&(GD_BUF_FLASH[FLASH_FORWORD_V]==0)&&(GD_BUF_FLASH[FLASH_PD_BACK]==0)\
        &&(GD_BUF_FLASH[FLASH_BIAS_V]==0))update_flag=1;
    }

    //不正确,读取扇区2的内容  
    if(update_flag>0)
    {
        for(i=0;i4);
        }
//      flash_update();//写入扇区1
//      pcset_5620_pro();//第一次上电设置5620输出。
        TLC5620_Set1((u8)GD_BUF[INDEX_5620_A1],0);
        TLC5620_Set1((u8)GD_BUF[INDEX_RED_CURRENT],1);
        TLC5620_Set1((u8)GD_BUF[INDEX_FORWORD_V],2);
        TLC5620_Set1((u8)GD_BUF[INDEX_PD_BACK],3);
        TLC5620_Set2((u8)GD_BUF[INDEX_5620_A2],0);
        TLC5620_Set2((u8)GD_BUF[INDEX_5620_B2],1);
        TLC5620_Set2((u8)GD_BUF[INDEX_BIAS_V],2);
    }
    else//参数正确,比较扇区1 
    {
        if(Compare_Sector_Date(MDATA_BASE,BACK_FLASH_BASE,GD_LEN_FLASH))
        {
            Update_Back_Flash(BACK_FLASH_BASE,GD_LEN_FLASH);
        }
        for(i=0;i0);
        TLC5620_Set1((u8)GD_BUF[INDEX_RED_CURRENT],1);
        TLC5620_Set1((u8)GD_BUF[INDEX_FORWORD_V],2);
        TLC5620_Set1((u8)GD_BUF[INDEX_PD_BACK],3);
        TLC5620_Set2((u8)GD_BUF[INDEX_5620_A2],0);
        TLC5620_Set2((u8)GD_BUF[INDEX_5620_B2],1);
        TLC5620_Set2((u8)GD_BUF[INDEX_BIAS_V],2);
    }   
}

具体流程:
1. 读取到两块扇区都为0xFFFFFFFF时,表示第一次烧写程序,采用默认值。
2. 有参数,则读取第一块扇区内容,
3. 判断第一块扇区内容是否正确,(可以采用校验的方式,或者采用在一个固定的位置写入固定的数据:写入0x55AA55AA)如果说扇区数据丢失,则写入的固定数据也将丢失,则说明第一块扇区内容不正确。
4. 不正确,读取第二块扇区内容,写入第一块扇区中。正确,比较两个扇区内容的差异,不同,则写入备份扇区。
对此,操作完成。flash扇区数据备份。

你可能感兴趣的:(STM32)