STM32G070xx系列MCU的Flash页分块存储技术解析:固定数据块存储与一次擦除多次写入实现方法

STM32G070xx将Flash页分块方式存储,固定数据块存储,实现一次擦除多次写入

  • 参考例程
  • 例程说明
  • 一、存储区数据结构
  • 二、读取存储区数据
  • 三、写入存储区数据
  • 四、测试函数
  • 五、测试结果
  • 参考例程

  • STM32G0xx使用LL库将Flash页分块方式存储数据实现一次擦除可多次写入
  • STM32G030Cx HAL库Flash擦除或编程操作出错的解决办法
  • STM32G0xx HAL和LL库Flash读写擦除操作

  • 例程说明

  • 本例程使用STM32G070xx芯片,Flash大小128KB。第125~126KB为操作存储区,地址0x0801F000 ~ 0x0801F7FF每块32字节;第127~128KB为标定存储区,地址0x0801F800 ~ 0x0801FFFF每块128字节
  • Flash每页(2048字节)写满后再擦除。操作存储区分为64块,每块32字节,即写满64次擦除一次;标定存储区分为16块,每块128字节,即写满16次擦除一次
  • 每块读写都有校验。读取时校验不通过表示数据异常,往前继续读取数据,直到校验通过为止
  • 在写入Flash前。数据前后对比,只有数据发生变化才写入Flash中
  • 每个存储区的块都有各自的头部标记

  • 一、存储区数据结构

    
    #define FLASH_STORE_OPERAT_PARM_PAGE                         (125)
    #define FLASH_STORE_OPERAT_PARM_START_ADDRE                  (0x0801F000UL)
    #define FLASH_STORE_OPERAT_PARM_HEADER_TAG                   (0x2A3D)
    #define FLASH_STORE_OPERAT_PARM_BLOCK_SIZE                   (32)
    #define FLASH_STORE_OPERAT_PARM_BLOCK_COUNT                  (u16)(FLASH_PAGE_SIZE / FLASH_STORE_OPERAT_PARM_BLOCK_SIZE) //64
    
    #define FLASH_STORE_DEMAR_PARM_PAGE                          (127)
    #define FLASH_STORE_DEMAR_PARM_START_ADDRE                   (0x0801F800UL)
    #define FLASH_STORE_DEMAR_PARM_HEADER_TAG                    (0x6C5A)
    #define FLASH_STORE_DEMAR_PARM_BLOCK_SIZE                    (128)
    #define FLASH_STORE_DEMAR_PARM_BLOCK_COUNT                   (u16)(FLASH_PAGE_SIZE / FLASH_STORE_DEMAR_PARM_BLOCK_SIZE) //16
    
    
    
    #pragma pack(1)
    
    typedef struct
    {
        u16 HeaderTag;  /* 头部标记 */
        u16 StoreIndex; /* 存储索引 */
    }FlashStoreHeader, * FlashStoreHeader_t;
    
    typedef struct
    {
        FlashStoreHeader  Header;
        ............ /* 用户定义数据1 */ 
        ............ /* 用户定义数据2 */ 
    
        u8 ubRes[23]; /* 块大小对齐 */
        u8 ubCRC8;    /* 校验和 */
    }DemarParam_TypeDef, * DemarParam_TypeDef_t;
    
    typedef struct
    {
        FlashStoreHeader  Header;
        ............ /* 用户定义数据1 */ 
        ............ /* 用户定义数据2 */ 
    
        u8 ubRes[9]; /* 块大小对齐 */
        u8 ubCRC8;   /* 校验和 */
    }OperatParam_TypeDef, * OperatParam_TypeDef_t;
    
    typedef struct
    {
        OperatParam_TypeDef Operat; /* 操作存储区 共32字节 */
        DemarParam_TypeDef  Demar;  /* 标定存储区 共128字节 */
    }SystemParamStore_TypeDef, * SystemParamStore_TypeDef_t;
    
    #pragma pack()
    
    
    
    static SystemParamStore_TypeDef SystemStoreParam = {0};
    DemarParam_TypeDef  * pStoreSysDemar  = &SystemStoreParam.Demar;
    OperatParam_TypeDef * pStoreSysOperat = &SystemStoreParam.Operat;
    
    

    二、读取存储区数据

    
    static u16 usGet_Flash_Read_Index(u16 page)
    {
        u32 startAddr  = FLASH_STORE_DEMAR_PARM_START_ADDRE;
        u16 blackSize  = FLASH_STORE_DEMAR_PARM_BLOCK_SIZE;
        u16 headerTag  = FLASH_STORE_DEMAR_PARM_HEADER_TAG;
        u8  blackCount = FLASH_STORE_DEMAR_PARM_BLOCK_COUNT;
        u8  len = XOFS(DemarParam_TypeDef , ubCRC8);
        u16 dat = 0, i = 0;
        u8  crc = 0;
    
        if (page == FLASH_STORE_OPERAT_PARM_PAGE)
        {
            startAddr  = FLASH_STORE_OPERAT_PARM_START_ADDRE;
            blackSize  = FLASH_STORE_OPERAT_PARM_BLOCK_SIZE;
            headerTag  = FLASH_STORE_OPERAT_PARM_HEADER_TAG;
            blackCount = FLASH_STORE_OPERAT_PARM_BLOCK_COUNT;
            len = XOFS(OperatParam_TypeDef , ubCRC8);
        }
    
        #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
        dprintf("R-startAddr:%X blackSize:%u headerTag:%X  blackCount:%u  len:%u\r\n", startAddr, blackSize, headerTag, blackCount, len);
        #endif
    
        for (i = 0; i < blackCount; ++i)
        {
            dat = *(volatile u16 *)(startAddr + ((blackCount - 1 - i) * blackSize));
            if (dat == headerTag)
            {
                crc = ubCheckSum_CRC8((void *)(startAddr + ((blackCount - 1 - i) * blackSize)), len);
                dat = *(volatile u8 *)(startAddr + ((blackCount - 1 - i) * blackSize) + (blackSize - 1));
                if (dat == crc)
                {
                    return (blackCount - 1 - i);
                }
            }
        }
    
        return FLASH_STORE_OPERAT_PARM_BLOCK_COUNT;
    }
    
    
    
    static void vFixed_Operat_Value(void)
    {
        SystemStoreParam.Operat.Header.HeaderTag = FLASH_STORE_OPERAT_PARM_HEADER_TAG;
    }
    
    static void vRestore_Operat_Parameter()
    {
        memset((void *)(&SystemStoreParam.Operat), 0, sizeof(OperatParam_TypeDef));
        vFixed_Operat_Value();
    }
    
    static void vRead_Operat_Parameter(void)
    {
        u16 index = usGet_Flash_Read_Index(FLASH_STORE_OPERAT_PARM_PAGE);
        if (index < FLASH_STORE_OPERAT_PARM_BLOCK_COUNT)
        {
            vFlash_Read_DoubleWord(FLASH_STORE_OPERAT_PARM_START_ADDRE + (FLASH_STORE_OPERAT_PARM_BLOCK_SIZE * index), (u64 *)(&SystemStoreParam.Operat), (FLASH_STORE_OPERAT_PARM_BLOCK_SIZE >> 3));
            vFixed_Operat_Value();
    
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Read Operat Param OK...%u\r\n", SystemStoreParam.Operat.Header.StoreIndex);
            #endif
        }
        else
        {
            vRestore_Operat_Parameter();
    
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Restore Operat Param...%u\r\n", SystemStoreParam.Operat.Header.StoreIndex);
            #endif
        }
    
    
        #if 1
        dprintf("--------------------- Operat Param Info ---------------------\r\n");
        dprintf("            00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  \r\n");
        dprintf("-------------------------------------------------------------\r\n");
        for (index = 0; index < FLASH_STORE_OPERAT_PARM_BLOCK_SIZE; ++index)
        {
            if (index && (index % 16 == 0)) dprintf("\r\n");
            if (index % 16 == 0) dprintf("0x%08X  ", (FLASH_STORE_OPERAT_PARM_START_ADDRE + (FLASH_STORE_OPERAT_PARM_BLOCK_SIZE * SystemStoreParam.Operat.Header.StoreIndex) + index));
            dprintf("%02X ", *(volatile u8 *)(FLASH_STORE_OPERAT_PARM_START_ADDRE + (FLASH_STORE_OPERAT_PARM_BLOCK_SIZE * SystemStoreParam.Operat.Header.StoreIndex) + index));
        }
        dprintf("\r\n");
        dprintf("-------------------------------------------------------------\r\n");
        dprintf("\r\n\r\n");
        #endif
    }
    
    
    
    
    
    
    static void vFixed_Demar_Value(void)
    {
        SystemStoreParam.Demar.Header.HeaderTag = FLASH_STORE_DEMAR_PARM_HEADER_TAG;
    }
    
    static void vRestore_Demar_Parameter(void)
    {
        memset((void *)(&SystemStoreParam.Demar), 0, sizeof(DemarParam_TypeDef));
        vFixed_Demar_Value();
    }
    
    static void vRead_Demar_Parameter(void)
    {
        u16 index = usGet_Flash_Read_Index(FLASH_STORE_DEMAR_PARM_PAGE);
        if (index < FLASH_STORE_DEMAR_PARM_BLOCK_COUNT)
        {
            vFlash_Read_DoubleWord(FLASH_STORE_DEMAR_PARM_START_ADDRE + (FLASH_STORE_DEMAR_PARM_BLOCK_SIZE * index), (u64 *)(&SystemStoreParam.Demar), (FLASH_STORE_DEMAR_PARM_BLOCK_SIZE >> 3));
            vFixed_Demar_Value();
    
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Read Demar Param OK...%u\r\n", SystemStoreParam.Demar.Header.StoreIndex);
            #endif
        }
        else
        {
            vRestore_Demar_Parameter();
    
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Restore Demar Param...%u\r\n", SystemStoreParam.Demar.Header.StoreIndex);
            #endif
        }
    
    
        #if 1
        dprintf("--------------------- Demar Param Info ----------------------\r\n");
        dprintf("            00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  \r\n");
        dprintf("-------------------------------------------------------------\r\n");
        for (index = 0; index < FLASH_STORE_DEMAR_PARM_BLOCK_SIZE; ++index)
        {
            if (index && (index % 16 == 0)) dprintf("\r\n");
            if (index % 16 == 0) dprintf("0x%08X  ", (FLASH_STORE_DEMAR_PARM_START_ADDRE + (FLASH_STORE_DEMAR_PARM_BLOCK_SIZE * SystemStoreParam.Demar.Header.StoreIndex) + index));
            dprintf("%02X ", *(volatile u8 *)(FLASH_STORE_DEMAR_PARM_START_ADDRE + (FLASH_STORE_DEMAR_PARM_BLOCK_SIZE * SystemStoreParam.Demar.Header.StoreIndex) + index));
        }
        dprintf("\r\n");
        dprintf("-------------------------------------------------------------\r\n");
        dprintf("\r\n\r\n");
        #endif
    }
    
    
    static void vRead_GlobalSystem_Parameter(void)
    {
        vRead_Operat_Parameter();
        vRead_Demar_Parameter();
    }
    
    void vRead_System_Parameter(void)
    {
        #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
        dprintf("OperatParam_TypeDef Size: %u\r\n", sizeof(OperatParam_TypeDef));
        dprintf("DemarParam_TypeDef  Size: %u\r\n", sizeof(DemarParam_TypeDef));
    
        if (sizeof(OperatParam_TypeDef) != FLASH_STORE_OPERAT_PARM_BLOCK_SIZE)
        {
            dprintf("Operat Param Size Error......\r\n");
            while (1);
        }
    
        if (sizeof(DemarParam_TypeDef) != FLASH_STORE_DEMAR_PARM_BLOCK_SIZE)
        {
            dprintf("Demar Param Size Error......\r\n");
            while (1);
        }
        #endif
    
        pStoreSysDemar  = &SystemStoreParam.Demar;
        pStoreSysOperat = &SystemStoreParam.Operat;
        vRead_GlobalSystem_Parameter();
    }
    
    

    三、写入存储区数据

    
    static u16 usGet_Flash_Write_Index(u16 page)
    {
        u32 startAddr  = FLASH_STORE_DEMAR_PARM_START_ADDRE;
        u16 blackSize  = FLASH_STORE_DEMAR_PARM_BLOCK_SIZE;
        u8  blackCount = FLASH_STORE_DEMAR_PARM_BLOCK_COUNT;
        u16 dat = 0, i = 0, x = 0;
        u8  tmp = 0, uFlg = 0;
    
        if (page == FLASH_STORE_OPERAT_PARM_PAGE)
        {
            startAddr  = FLASH_STORE_OPERAT_PARM_START_ADDRE;
            blackSize  = FLASH_STORE_OPERAT_PARM_BLOCK_SIZE;
            blackCount = FLASH_STORE_OPERAT_PARM_BLOCK_COUNT;
        }
    
        #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
        dprintf("W-startAddr:%X blackSize:%u blackCount:%u\r\n", startAddr, blackSize, blackCount);
        #endif
    
        for (i = 0; i < blackCount; ++i)
        {
            dat = *(volatile u16 *)(startAddr + (blackSize * i));
            if (dat == 0xFFFFU)
            {
                uFlg = 0;
                for (x = 0; x < blackSize; ++x)
                {
                    tmp = *(volatile u8 *)(startAddr + (blackSize * i) + x);
                    if (tmp != 0xFFU)
                    {
                        uFlg = 1;
                        break;
                    }
                }
    
                if (!uFlg) 
                {
                    return i;
                }
            }
        }
    
        return FLASH_STORE_OPERAT_PARM_BLOCK_COUNT;
    }
    
    
    
    
    
    
    static void vSave_System_Parameter(u16 page)
    {
        u32 startAddr   = FLASH_STORE_DEMAR_PARM_START_ADDRE;
        u16 blackSize   = FLASH_STORE_DEMAR_PARM_BLOCK_SIZE;
        u8  blackCount  = FLASH_STORE_DEMAR_PARM_BLOCK_COUNT;
        u16 StoreIndex  = SystemStoreParam.Demar.Header.StoreIndex;
        u64 * pSaveDest = (u64 *)(&SystemStoreParam.Demar);
        u8  * pSrc      = (u8 *)(&SystemStoreParam.Demar);
        u8   mode = 0, dat = 0;
        u16  index = 0;
    
    
        if (page == FLASH_STORE_OPERAT_PARM_PAGE)
        {
            startAddr  = FLASH_STORE_OPERAT_PARM_START_ADDRE;
            blackSize  = FLASH_STORE_OPERAT_PARM_BLOCK_SIZE;
            blackCount = FLASH_STORE_OPERAT_PARM_BLOCK_COUNT;
            StoreIndex = SystemStoreParam.Operat.Header.StoreIndex;
            pSaveDest  = (u64 *)(&SystemStoreParam.Operat);
            pSrc       = (u8 *)(&SystemStoreParam.Operat);
        }
    
        for (index = 0; index < blackSize; ++index)
        {
            dat = *(volatile u8 *)(startAddr + (blackSize * StoreIndex) + index);
            if (dat != *pSrc++)
            {
                mode = 1;
                break;
            }
        }
    
        if (!mode)
        {
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Save Pram Same......Index:%02u  Page:%u\r\n", StoreIndex, page);
            #endif
    
            return;
        }
    
        mode  = 0;
        index = usGet_Flash_Write_Index(page);
        if (index >= blackCount)
        {
            index = 0; 
            mode  = 1;
        }
    
        if (page == FLASH_STORE_DEMAR_PARM_PAGE) 
        {
            SystemStoreParam.Demar.Header.StoreIndex = index;
            SystemStoreParam.Demar.ubCRC8  = ubCheckSum_CRC8((void *)(&SystemStoreParam.Demar),  XOFS(DemarParam_TypeDef , ubCRC8));
        }
        else
        {
            SystemStoreParam.Operat.Header.StoreIndex = index;
            SystemStoreParam.Operat.ubCRC8 = ubCheckSum_CRC8((void *)(&SystemStoreParam.Operat), XOFS(OperatParam_TypeDef, ubCRC8));
        }
        
        if (ubFlash_Write_DoubleWord_EreasePage((startAddr + (blackSize * index)), pSaveDest, (blackSize >> 3), mode))
        {
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Save Pram Error...%u\r\n", index);
            #endif
        }
        else
        {
            #if defined(DEBUG_RELEASE_VERSION_ENABLE) && (DEBUG_RELEASE_VERSION_ENABLE == 0)
            dprintf("Save Pram OK...%u  CRC-Demar:%02X  Operat:%02X\r\n", index, SystemStoreParam.Demar.ubCRC8, SystemStoreParam.Operat.ubCRC8);
            #endif
        }
    }
    
    
    
    
    
    static void vSynSave_Demar_Parameter(void)
    {
    }
    void vSave_Demar_Parameter(void)
    {
        vSynSave_Demar_Parameter();
        vSave_System_Parameter(FLASH_STORE_DEMAR_PARM_PAGE);
    }
    
    
    static void vSynSave_Operat_Parameter(void)
    {
    }
    void vSave_Operat_Parameter(void)
    {
        vSynSave_Operat_Parameter();
        vSave_System_Parameter(FLASH_STORE_OPERAT_PARM_PAGE);
    }
    
    
    

    四、测试函数

  • 读取数据:
    void vRead_System_Parameter(void); //读取数据 操作存储区+标定存储区

  • 保存数据:
    void vSave_Operat_Parameter(void); //操作存储区
    void vSave_Demar_Parameter(void); //标定存储区

  • 五、测试结果

    作者:凌盛羽

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32G070xx系列MCU的Flash页分块存储技术解析:固定数据块存储与一次擦除多次写入实现方法

    发表回复