英文网站建设网站,免费空间访客,家电网站建设费用,福田网站建设费用明细#FLASH平衡擦写#
一、概述
简易示意图如下#xff1a; 写参数前要擦除对应的扇区 全为0XFFFFFFFF操作的最小单位为32位 uint32_t; 当一块扇区写完时#xff0c;将所有有用参数复制到第二块扇区#xff0c;开始写新的参数#xff0c;如果所有参数写完#xff0c;又重第…#FLASH平衡擦写#
一、概述
简易示意图如下 写参数前要擦除对应的扇区 全为0XFFFFFFFF操作的最小单位为32位 uint32_t; 当一块扇区写完时将所有有用参数复制到第二块扇区开始写新的参数如果所有参数写完又重第一块参数开始写这样就能实现平衡写的目的所以要实现这个功能至少需要分配2个扇区实现均衡擦写。 /* 储存扇区信息的结构体 */
struct SSCT_HDR
{uint32_t st; // 状态uint32_t cnt; // 标号uint32_t version; // 版本
}; // 扇区HEAD结构typedef struct
{uint16_t len:16; uint16_t alen:16; /* data */
}VARLEN;
struct VAR_ST //Flash数据存储结构
{uint32_t status; //数据当前状态uint32_t key; //数据keyunion {uint32_t len; //数据长度 len alen 数据实际长度所在内存长度 内存长度必须是4的整数倍VARLEN len_b;/* data */};}; 扇区1 扇区使用状态 扇区 标号 扇区版本号 数据状态ad1 数据key 长度 len alen1 D1 D1 D1 D1 D1 D1 数据状态ad1 alen1/4 数据key 长度 Len2 Alen2 D2 D2 D2 D2 D2 D2 数据状态ad2 Alen2/4 数据key 长度 Len3 Alen3 D3 D3 D3 D3 D3 D3 D3 D3 D3 D3 D3 D3 ... ... ... ... ... ... ... ... ... 二、源码 #include stdbool.h
#include stdint.h //引用框架配置文件#define MAX_CVAR_NUM (200) //数据存储最大个数typedef struct
{uint16_t len:16; uint16_t alen:16; /* data */
}VARLEN;
struct VAR_ST //Flash数据存储结构
{uint32_t status; //数据当前状态uint32_t key; //数据keyunion {uint32_t len; //数据长度 len alen 数据实际长度所在内存长度 内存长度必须是4的整数倍VARLEN len_b;/* data */};};struct SFVAR_POINT
{uint32_t key; //数据keyuint8_t* flashAddr; //数据地址
};typedef struct
{uint8_t* sectorBaseAdr;uint32_t sectorSize;uint8_t sectorNum;void (*FlashInit_Cbk)(void); // Flash初始化函数bool (*FlashErase_Cbk)(uint8_t* addr, uint32_t size); // Flash擦除函数uint32_t (*FlashWrite_Cbk)(void* addr, const void* buf, uint32_t size); // Flash写入函数uint32_t (*FlashRead_Cbk)(void* addr, void* buf, uint32_t size); /// flash读函数// privatestruct{uint32_t makeTime;uint8_t* sectorUseBaseAdr; // flash 参数存储区基地址uint8_t sectorUseCnt; // Flash 所有的序号uint32_t varNum; // Flash存储数据个数uint32_t tail; // Flash当前地址uint32_t head; // 有效头部位置uint8_t swSctFlag; //扇区切换flaguint8_t* rmAdr; //需要删除的 地址struct VAR_ST pCVar; //单个参数的头部结构struct SFVAR_POINT varList[MAX_CVAR_NUM]; //数据Z指针数组} pri;}FlashPar_Prop;typedef struct
{void (* const Create)(FlashPar_Prop* self); // FlashVarvoid (*Init)(FlashPar_Prop* self,uint32_t makeTime,uint8_t* sectorBaseAdr, // FLASH基地址uint32_t sectorSize, // flash大小uint32_t sectorNum, // flash块的个数void (*FlashInit_Cbk)(void), // flash初始化函数bool (*FlashErase_Cbk)(uint8_t* addr, uint32_t size), // flash擦除函数uint32_t (*FlashWrite_Cbk)(void* addr, const void* buf, uint32_t size), // flash写入函数uint32_t (*FlashRead_Cbk)(void* addr, void* buf, uint32_t size) // flash读函数);// APIuint32_t (*RdPar)(FlashPar_Prop* self, uint32_t key, uint8_t* pRdBuf, uint32_t bufLen); ///数据读取函数MOBJ_BOOL (*WtPar)(FlashPar_Prop* self, uint32_t key, uint8_t* pWtDat, uint32_t datLen); //数据写入函数MOBJ_BOOL (*DelPar)(FlashPar_Prop* self, uint32_t key); //数据删除函数}FlashPar_Func;extern const FlashPar_Func FlashPar; #include MFlashVar.h
#include string.h
#include MTime.h
/* 扇区使用情况 表示各个扇区状态*/#define SSCT_UNUSE (0xFFFFFFFF) // 未使用
#define SSCT_USE (0xBBBBBBBB) // 使用中
#define SSCT_DEL (0x00000000) // 删除状状态/* 某区域保存参数的状态 */#define SCVAR_UNUSE (0xFFFFFFFF) // 未使用#define SCVAR_USE (0xAAAAAAAA) // 使用中#define SCVAR_DEL (0x00000000) // 删除状状态// 表示各个数据状态/* 储存扇区信息的结构体 */
struct SSCT_HDR
{uint32_t st; // 状态uint32_t cnt; // 标号uint32_t version; // 版本}; // 扇区HEAD结构static int32_t FindVarAddr(FlashPar_Prop *self, uint32_t key);
static uint32_t AllocVar(FlashPar_Prop *self, uint32_t len, uint32_t key);
static void DelVar(FlashPar_Prop *self, uint8_t *addr);
static void PrgVar(FlashPar_Prop *self, void *flashAddr, uint32_t key, uint8_t *pWtDat, uint32_t dataLen);
static void LoadSector(FlashPar_Prop *self);
static void LoadFVar(FlashPar_Prop *self);
static void SwitchSct(FlashPar_Prop *self);/*** brief FlashPar**/
static void FlashPar_Init(FlashPar_Prop *self,uint32_t makeTime,uint8_t *sectorBaseAdr,uint32_t sectorSize,uint32_t sectorNum,void (*FlashInit_Cbk)(void),bool (*FlashErase_Cbk)(uint8_t *addr, uint32_t size),uint32_t (*FlashWrite_Cbk)(void *addr, const void *buf, uint32_t size),uint32_t (*FlashRead_Cbk)(void *addr, void *buf, uint32_t size) // flash读函数
)
{self-pri.varNum 0;self-sectorBaseAdr sectorBaseAdr;self-sectorSize sectorSize;self-sectorNum sectorNum;self-pri.makeTime makeTime;self-FlashInit_Cbk FlashInit_Cbk;self-FlashErase_Cbk FlashErase_Cbk;self-FlashWrite_Cbk FlashWrite_Cbk;self-FlashRead_Cbk FlashRead_Cbk;// step1: load useing sectorLoadSector(self);// step2 : load flash variableLoadFVar(self);}/*** brief 申请地址并检查剩余地址是否足够**/
static uint32_t AllocVar(FlashPar_Prop *self, uint32_t len, uint32_t key)
{uint32_t pFVarAddress;uint8_t tmp, actLen;uint16_t index;/******step1 :Caculate the actual space***/tmp len % 4;if (tmp ! 0)actLen sizeof(struct VAR_ST) len (4 - tmp);elseactLen sizeof(struct VAR_ST) len;/*step2: check current sector has enough sapace*/if (self-pri.tail actLen self-sectorSize){SwitchSct(self);index FindVarAddr(self, key);self-pri.rmAdr self-pri.varList[index].flashAddr;}else {}/*step3: current sector has enough sapace*/if (self-pri.tail actLen self-sectorSize){pFVarAddress (uint32_t)(self-pri.sectorUseBaseAdr self-pri.tail);self-pri.tail actLen;}else{pFVarAddress 0;}return pFVarAddress;
}
/*** brief 删除原有变量函数**/
static void DelVar(FlashPar_Prop *self, uint8_t *addr)
{uint32_t st;st SCVAR_DEL;self-FlashWrite_Cbk(addr, st, sizeof(st));
}
/*** brief 写入参数**/
static void PrgVar(FlashPar_Prop *self, void *flashAddr, uint32_t key, uint8_t *pWtDat, uint32_t dataLen)
{struct VAR_ST tmpVar;uint32_t tmp;uint32_t dtActLen;uint8_t *pHead (uint8_t *)flashAddr;uint8_t *pData (uint8_t *)flashAddr sizeof(struct VAR_ST);tmp dataLen % 4;if (tmp ! 0)dtActLen dataLen (4 - tmp);elsedtActLen dataLen;tmpVar.status SCVAR_USE;tmpVar.key key;tmpVar.len_b.len dataLen;tmpVar.len_b.alen dtActLen;self-FlashWrite_Cbk(pHead, (uint8_t *)tmpVar, sizeof(struct VAR_ST));self-FlashWrite_Cbk(pData, pWtDat, dtActLen);}/*** brief 根据关键字查询变量**/
static uint32_t FlashPar_RdPar(FlashPar_Prop *self, uint32_t key, uint8_t *pRdBuf, uint32_t bufLen)
{struct VAR_ST pFVar;uint32_t ret 0;uint8_t *pData;uint32_t len;int32_t index;// find var in ramindex FindVarAddr(self, key);if (index 0){return ret;}self-FlashRead_Cbk(self-pri.varList[index].flashAddr, pFVar, sizeof(struct VAR_ST));len pFVar.len_b.len;if (bufLen len){len bufLen;}pData self-pri.varList[index].flashAddr sizeof(struct VAR_ST);self-FlashRead_Cbk(pData, pRdBuf, len);ret len;return ret;
}
/* 根据KEY 删除一个参数 */
static MOBJ_BOOL FlashPar_DelPar(FlashPar_Prop *self, uint32_t key)
{uint8_t *pFVar;int32_t index;uint32_t MvDataNum;// find var in ramindex FindVarAddr(self, key);if (index 0){return NOT;}pFVar self-pri.varList[index].flashAddr;MvDataNum self-pri.varNum - (index 1);while (MvDataNum--){self-pri.varList[index].flashAddr self-pri.varList[index 1].flashAddr;self-pri.varList[index].key self-pri.varList[index 1].key;index;}self-pri.varList[index].flashAddr 0;self-pri.varList[index].key 0;self-pri.varNum--;DelVar(self, pFVar);return YES;
}/*** brief 根据key保存一个参数**/
static MOBJ_BOOL FlashPar_WtPar(FlashPar_Prop *self, uint32_t key, uint8_t *pWtDat, uint32_t datLen)
{uint8_t *pNewVar;uint8_t tempdata[258] {0};struct VAR_ST pOldVar;int32_t index;MOBJ_BOOL ret;if (datLen 256){}/******step1 :find old var ***/index FindVarAddr(self, key);/******step2 :wite new var*/if (index 0) // step2.1 old var not exist{if (self-pri.varNum MAX_CVAR_NUM) // check number{ret NOT;}else if (0 (pNewVar (uint8_t *)AllocVar(self, datLen, key))) // alloc space{ret NOT;}else{PrgVar(self, pNewVar, key, pWtDat, datLen);self-pri.varList[self-pri.varNum].key key;self-pri.varList[self-pri.varNum].flashAddr pNewVar;self-pri.varNum;ret YES;}}else // step2.2 old var exist{self-pri.rmAdr self-pri.varList[index].flashAddr;self-FlashRead_Cbk(self-pri.rmAdr, pOldVar, sizeof(struct VAR_ST));if (pOldVar.key key){self-FlashRead_Cbk(self-pri.rmAdr sizeof(struct VAR_ST), tempdata, pOldVar.len_b.len);if ((pOldVar.len_b.len datLen) (0 memcmp(tempdata, pWtDat, datLen))){ret YES;}else{pNewVar (uint8_t *)AllocVar(self, datLen, key);if (0 pNewVar) // alloc space{// EINT;ret NOT;}else{PrgVar(self, pNewVar, key, pWtDat, datLen); // write new varDelVar(self, self-pri.rmAdr); // 完全删除ret YES;}self-pri.varList[index].flashAddr pNewVar;}}}return ret;
}
static int32_t FindVarAddr(FlashPar_Prop *self, uint32_t key)
{int32_t i;for (i 0; i self-pri.varNum; i){if (self-pri.varList[i].key key)return i;}return -1;
}/*** brief 加载各个扇区的状态信息**/static void LoadSector(FlashPar_Prop *self)
{int32_t i;int32_t maxSctCnt 0;uint8_t *useadd 0;struct SSCT_HDR pSctHdr, newSctHdr;// step1 : find using sectorfor (i 0; i self-sectorNum; i){useadd self-sectorBaseAdr i * self-sectorSize;self-FlashRead_Cbk(useadd, pSctHdr, sizeof(struct SSCT_HDR));// check the version,if ((pSctHdr.version ! 0xFFFFFFFF) (pSctHdr.version ! self-pri.makeTime)){self-FlashErase_Cbk(useadd, self-sectorSize);}else{switch (pSctHdr.st){case SSCT_UNUSE: {break;}case SSCT_USE: {if (pSctHdr.cnt maxSctCnt){self-pri.sectorUseBaseAdr useadd;self-pri.sectorUseCnt i;maxSctCnt pSctHdr.cnt;}break;}case SSCT_DEL: {break;}}}}// step2 : if dont find using sector them set sector0 is usedif (maxSctCnt 0){self-pri.sectorUseBaseAdr self-sectorBaseAdr;self-pri.sectorUseCnt 0;self-FlashErase_Cbk(self-pri.sectorUseBaseAdr, self-sectorSize); // 擦除 实际地址需newSctHdr.st SSCT_USE;newSctHdr.cnt 1;newSctHdr.version self-pri.makeTime;self-FlashWrite_Cbk(self-pri.sectorUseBaseAdr, (uint8_t *)newSctHdr, sizeof(struct SSCT_HDR));}self-pri.tail sizeof(struct SSCT_HDR);
}
/*** brief 加载flash 区的参数信息**/
static void LoadFVar(FlashPar_Prop *self)
{uint8_t rFlag 1;struct VAR_ST *pErrVar 0;struct VAR_ST nowVar;uint32_t errNo 0;uint8_t *pFVarAddress 0;// uint8_t* pFVarAddress 0;while ((self-pri.tail self-sectorSize) rFlag){pFVarAddress self-pri.sectorUseBaseAdr self-pri.tail;self-FlashRead_Cbk(pFVarAddress, nowVar, sizeof(struct VAR_ST));switch (nowVar.status){// if the data was unused than over build processcase SCVAR_UNUSE: {rFlag 0; // stop researchbreak;}case SCVAR_USE: {if ((pErrVar ! 0) (nowVar.key pErrVar-key)){self-pri.tail sizeof(struct VAR_ST) nowVar.len_b.alen;DelVar(self, self-pri.varList[errNo].flashAddr); // 删除原有错误数据self-pri.varList[errNo].flashAddr pFVarAddress;}else // nomal{self-pri.tail sizeof(struct VAR_ST) nowVar.len_b.alen;self-pri.varList[self-pri.varNum].key nowVar.key;self-pri.varList[self-pri.varNum].flashAddr pFVarAddress;self-pri.varNum;}break;}// if deleted than jumpcase SCVAR_DEL: {self-pri.tail sizeof(struct VAR_ST) nowVar.len_b.alen;}default: // 参数报错{// self-pri.tail sizeof(struct VAR_ST) dtActLen;}}} // end while
}/*** brief Flash扇区切换 (暂时未确认是否ok)**/
static void SwitchSct(FlashPar_Prop *self)
{uint8_t data[256];struct VAR_ST pOldVar;struct SSCT_HDR pOldSctHD;uint8_t *oldSct self-pri.sectorUseBaseAdr;self-FlashRead_Cbk(oldSct, pOldSctHD, sizeof(struct SSCT_HDR));/********step1: find next sector******/self-pri.sectorUseCnt;if (self-pri.sectorUseCnt self-sectorNum){self-pri.sectorUseCnt 0;}uint8_t *newSct self-sectorBaseAdr self-pri.sectorUseCnt * self-sectorSize;self-FlashErase_Cbk(newSct, self-sectorSize); // 擦除即将切换到的扇区 擦除地址开始后的1个扇区/********step2 : produce sector header*******/struct SSCT_HDR newSctHD {.st SSCT_USE,.cnt pOldSctHD.cnt 1,.version self-pri.makeTime,};self-pri.sectorUseBaseAdr (uint8_t *)newSct;self-pri.tail sizeof(struct SSCT_HDR);// sector write preself-FlashWrite_Cbk(newSct, (uint8_t *)newSctHD, sizeof(struct SSCT_HDR));/********step3 :将原有参数移动到新区*************/int32_t i;uint8_t *newvaraddr;for (i 0; i self-pri.varNum; i){self-FlashRead_Cbk(self-pri.varList[i].flashAddr, pOldVar, sizeof(struct VAR_ST));newvaraddr (uint8_t *)((uint32_t)self-pri.sectorUseBaseAdr self-pri.tail);self-FlashRead_Cbk(self-pri.varList[i].flashAddr sizeof(struct VAR_ST), data, pOldVar.len_b.len); // 读数据PrgVar(self, newvaraddr, pOldVar.key, data, pOldVar.len_b.len); // 保存数据self-pri.varList[i].flashAddr newvaraddr;self-pri.tail sizeof(struct VAR_ST) pOldVar.len_b.alen;if (self-pri.tail self-sectorSize){//扇区溢出return;}}pOldSctHD.st SSCT_DEL;// sector write preself-FlashWrite_Cbk(oldSct, (uint8_t *)pOldSctHD, sizeof(struct SSCT_HDR));
}
/*** brief FlashPar**/
void FlashPar_Create(FlashPar_Prop *self) { memset(self, 0, sizeof(FlashPar_Prop)); }const FlashPar_Func FlashPar {.Create FlashPar_Create,.Init FlashPar_Init,.RdPar FlashPar_RdPar,.WtPar FlashPar_WtPar,.DelPar FlashPar_DelPar};平衡擦写的流程主要涉及到扇区的选择和切换以及变量的写入和删除。 1. 首先在FlashPar_Init函数中通过调用LoadSector函数加载扇区的状态信息。该函数会遍历所有扇区检查状态并选择使用中的扇区作为当前扇区。
2. 接下来在LoadFVar函数中会加载当前扇区中的flash变量。函数会遍历当前扇区中的每个flash变量将其存储到pri.varList数组中。同时将当前扇区中的tail指针指向下一个可用的地址。
3. 当需要写入一个新的flash变量时首先通过AllocVar函数申请一个地址并检查当前扇区是否有足够的空间。如果空间不足则需要切换到下一个扇区并重新分配地址。然后通过PrgVar函数将变量写入到flash中并更新pri.varList数组和pri.varNum变量。如果找到了相同关键字的旧变量则会先删除旧变量。
4. 当需要删除一个flash变量时通过FlashPar_DelPar函数根据关键字找到变量的地址并调用DelVar函数删除变量。
5. 当需要读取一个flash变量时通过FlashPar_RdPar函数根据关键字找到变量的地址并将变量的数据读取出来。 在上述流程中如果当前扇区的空间不足以容纳新的flash变量就会触发扇区切换。在SwitchSct函数中先找到下一个可用的扇区并将其标记为使用状态。然后将当前扇区中的变量逐个移动到新的扇区并更新变量的地址。同时将当前扇区的状态设置为删除状态并将新的扇区的状态设置为使用状态。 通过这样的流程可以实现对flash的平衡擦写避免频繁的擦写操作延长flash的使用寿命。同时可以方便地存储和读取变量提供了一种简单有效的持久化存储解决方案。