STM32G070xx系列MCU的Flash页分块存储技术解析:固定数据块存储与一次擦除多次写入实现方法
STM32G070xx将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); //标定存储区
五、测试结果
作者:凌盛羽