目录
一、循环读写 flash 的相关接口和实现
1、FlashCycle.h 头文件
/* FlashCycle.h */
#ifndef __FLASH_CYCLE_H_
#define __FLASH_CYCLE_H_
#include "sys.h"
#include "Generaldef.h"
#include "flash.h"
//一个扇区的大小
#define FLASH_CYCLE_SECTOR_SIZE (uint32_t)(2*1024)
//写入数据的密码
#define FC_SYSTEM_PATA_PSW 0x4
//系统参数存储扇区,flash的最后一个扇区
#define FC_SYSTEM_PATA_ADDR ((u32)FLASH_BASE+255*FLASH_CYCLE_SECTOR_SIZE)
typedef struct
{
uint16_t psw;
uint32_t startAddr;
uint32_t size;
}FcDataType;
void Flash_InitCycle(FcDataType *FcData, uint16_t psw, uint32_t startAddr, uint32_t size);
BOOL Flash_ReadCycle(const FcDataType *FcData, uint8_t *rBuff);
BOOL Flash_WriteCycle(const FcDataType *FcData, const uint8_t *wBuff);
extern FcDataType FcSysData;
#endif
2、FlashCycle.c 文件
/* FlashCycle.c */
#include "FlashCycle.h"
#include <string.h>
#include <stdlib.h>
FcDataType FcSysData;
//擦除后FLASH状态,F系列为FFFF,L系列为0000
#define FC_RESET_HALF_WORD 0xFFFF
/**********************************************************************
* @brief 初始化一个数据结构
* @param FcData-数据结构存储
* @param psw-数据结构对应密码,如果密码被更改,用户数据将会被擦除永久丢失。
* @param startAddr-起始写入地址,最好是最小擦除单位首地址
* @param size-数据结构大小,建议适当增大,为后面增加参数预留位置
***********************************************************************/
void Flash_InitCycle(FcDataType *FcData, uint16_t psw, uint32_t startAddr, uint32_t size)
{
if(FcData==0 || psw==0 || psw==0xFFFF
|| startAddr<FLASH_BASE || startAddr>FLASH_END || size==0) return;
FcData->psw=psw;
FcData->startAddr = startAddr;
FcData->size=size;
}
/************************************************************
* @brief 写入数据到flash块中
* @param FcData-数据结构存储
* @param wBuff-需要写入的数据
* @retur 是否写入成功
**************************************************************/
BOOL Flash_WriteCycle(const FcDataType *FcData, const uint8_t *wBuff)
{
BOOL ret=FALSE;
if(FcData==0 || wBuff==0) return ret;
//密码一起写入
uint32_t rlen=FcData->size+2;
//数据存储四字节对齐
uint32_t len=0,wlen=rlen%4==0? rlen/4:rlen/4+1;
//每个数据块对应总字节数
uint32_t blen=4*wlen;
//申请一段内存,把密码也写入,用完之后要记得 free() 释放掉内存
uint8_t *buff = malloc(blen);
if(buff== 0) return ret;
*(uint16_t *)buff = FcData->psw;
memcpy(&buff[2], wBuff, FcData->size);
//遍历整个扇区,第一个密码为0xFFFF就是空区域,将数据写入。
while(1)
{
uint16_t psw=*(vu16 *)(FcData->startAddr+len); //直接取出flash中的值
//扇区写完了,或者出现了别的数据 不是规定的密码0x03 或者0xffff
if(len+blen > FLASH_CYCLE_SECTOR_SIZE || (FcData->psw!=psw && psw!=0xFFFF))
{
//擦除扇区需要时间,注意延长看门狗时间
fmc_erase_pages(FcData->startAddr, 1);
//在第一个区域写入
fmc_program(FcData->startAddr, (const uint32_t *)buff, wlen);
ret=TRUE;
break;
}
//第一个空区域,写入数据
else if(psw == 0xFFFF)
{
fmc_program(FcData->startAddr+len, (const uint32_t *)buff, wlen);
ret=TRUE;
break;
}
//密码正确,这里以已经写过数据,进入下一个区域
else if(psw == FcData->psw)
{
len+=blen;
}
}
free(buff);
return ret;
}
/***************************************************************
* @brief 在一段flash块中,读出最新存储的数据
* @param FcData-数据结构存储
* @param rBuff-读出缓存,将读出的数据放入这里
* @retur 是否读出成功
****************************************************************/
BOOL Flash_ReadCycle(const FcDataType *FcData, uint8_t *rBuff)
{
BOOL ret=FALSE;
if(FcData==0 || rBuff==0) return ret;
//数据里包含密码
uint32_t rlen=FcData->size+2;
//数据存储四字节对齐
uint32_t len=0, wlen=rlen%4==0 ? rlen/4:rlen/4+1;
//每个数据块对应总字节数
uint32_t blen=4*wlen;
//遍历整个扇区,第一个密码为0xFFFF或最后一个区域就是最后写入的数据
while(1)
{
uint16_t psw=*(vu16 *)(FcData->startAddr+len);
//密码为0xFFFF,这个区域没有被写入数据,或者已经达到扇区末尾,说明前一个扇区就是最后写入的数据
if(len+blen > FLASH_CYCLE_SECTOR_SIZE || psw==0xFFFF)
{
//第一个扇区,说明之前没有任何数据写入,不读取任何数据
if(len==0) break;
//返回上个区域,读出数据
else
{
len-=blen;
//写入的数据前2位是密码,不需要读出
fmc_read(FcData->startAddr+len+2, rBuff, FcData->size);
ret=TRUE;
break;
}
}
//密码正确,进入下一个区域
else if(psw == FcData->psw)
{
len+=blen;
}
//有别的数据(数据段非空,且密码不正确),不做任何操作
else
{
break;
}
}
return ret;
}
二、如何使用
1、初始化
/*在初始化的地方调用
*1、FC_SYSTEM_PATA_PSW:密码,一般不会随意更改;
*2、254:每次写入的字节数,还不包括密码的长度;
*/
Flash_InitCycle(&FcSysData, FC_SYSTEM_PATA_PSW, FC_SYSTEM_PATA_ADDR, 254);
2、循环写
//在需要保存的地方调用,比如掉电,修改某些参数之后
void WeitrAllParaToFlash(void)
{
memset(TempBuff,0,sizeof(TempBuff));
//SysRunPara.FalshPara,要写入的结构体数据
memcpy(TempBuff,&SysRunPara.FalshPara,sizeof(SysRunPara.FalshPara));
if(Flash_WriteCycle(&FcSysData, TempBuff) == FALSE)
{
Log_Printf("write error\r\n");
}
}
3、循环读
u8 BuffPointer[254]; //保存从 flash 读出的数据
void ReadAllParaFromFlash(void)
{
memset(BuffPointer,0,sizeof(BuffPointer));
if(Flash_ReadCycle(&FcSysData, BuffPointer))
{
Log_Printf("\r\nread success\r\n");
}
}