承蒙项目和同事的要求,因Flash擦除、写入太过于频繁,所以需要更换Flash地址写数据。
背景简介:嵌入式开发,需要关机保存数据,C语言写。用512K Byte Flash。
看了一篇网上文章后,借鉴前人的做法,写了以下代码,本人是运用前人原理中的一种(一部分),所以来说,应该看起来更加简单明了。前人源链接如下https://blog.csdn.net/baidu_37541954/article/details/64122655
代码简介:用容量512k Byte的Flash,在0x20000 Byte起始的地址,在0x20000~0x3FFFF之间(总共128k Byte)进行循环存储数据。因Flash每次擦除最小单位为4K Byte的扇区,所以在0x20000~0x3FFFF之间一个周期总共能存储32次。
存储数据原理简介:每个扇区的第一个32位数据,存储数据有效标志位(比如我写入1),第二个32位,保存我想要存储的数据。循环读取32个扇区的第一个32位,查询时如果不是0xFFFFFFFF,则认为此段扇区已经写入,则进行擦除此段,进而在下一段扇区写入数据。
读取数据原理简介:循环读取32个扇区的第一个32位,查询时如果不是0xFFFFFFFF,则认为此段扇区中是有效数据,进行读取。(当然读取时防止出错,加上出错时返回默认值)
本人写尚处于学习进步阶段,写此博客记录所学。且尚有很多不足,往多多指教。欢迎添加QQ进一步学习探讨1742037504.
#define POWEROFF_SAVE_ADDR 0x10020000
#define POWEROFF_SAVE_LENGTH 0x20000
void flashOperation( UINT32 erushAddress , UINT32 erushNumber, UINT32 * writeData)
{
//保存相关参数
UINT32 argv[5];
UINT32 saveData[2]; //保存数据仅2个
saveData[0] = 1; //第一个数据位有效位标志
saveData[1] = * writeData; //第二个数据位存储的数据
argv[0] = 0;
argv[1] = 0;
argv[2] = erushAddress&0x0FFFFFFF;
argv[3] = erushNumber*4; //Erasure POWEROFF_SAVE_NUMBER Bit32 data,so Mul 4.
FTSPI020_xip_port_sel(0); //cmd port
SpiFlashErase(4, argv); //如果擦除失败,重新进行擦除
erushAddress += 4096;//擦除上一个扇区,给下一个扇区写入。相隔一个扇区(4KByte)
if( erushAddress >= (POWEROFF_SAVE_ADDR + POWEROFF_SAVE_LENGTH))
{//如果保存数据地址已经到末尾,则循环至开头。进行写操作
erushAddress = POWEROFF_SAVE_ADDR;
}
argv[0] = 0;
argv[1] = 0;
argv[2] = erushAddress&0x0FFFFFFF;
argv[3] = erushNumber*4; //Save POWEROFF_SAVE_NUMBER Bit32 data,so Mul 4.
argv[4] = (UINT32)&saveData[0];
SpiFlashWrite(5, argv);
FTSPI020_xip_port_sel(1); //cmd port
}
UINT8 SaveEffModeProcess(UINT32* address, UINT32* data, UINT32 saveDataNumber)//比如,0x10020000,32,data
{
UINT32 availFlag;
UINT8 i;
UINT8 saveCheckLoopNum = (POWEROFF_SAVE_LENGTH/4096); //长度除以4KByte
UINT32 curDataNumber = (saveDataNumber + 1); //因还有第一个标志数据,所以长度+1;
for( i = 0; i < saveCheckLoopNum ; i++ )
{//循环检查看哪个地址有保存过数据
availFlag = *address;
if( availFlag != 0xFFFFFFFF )
{//找到已经写过的地址,进行擦除当前数据,写入保存数据操作
flashOperation((UINT32)address , curDataNumber, data);
return 1;
}
address += (4096>>2);//因此数据为32位,所以所加数据要除以4
}
//在存储范围内未检查到有存储数据记录,则进行对起始空间进行保存操作
address = (UINT32*)POWEROFF_SAVE_ADDR;
flashOperation((UINT32)address , curDataNumber, data);
return 0;
}
UINT8 ReadEffModeProcess(UINT32* address )
{
UINT32 availFlag;
UINT8 readEffMode;
UINT8 i;
UINT8 saveCheckLoopNum = (POWEROFF_SAVE_LENGTH/4096); //长度除以4KByte
for( i = 0; i < saveCheckLoopNum ; i++ )
{//循环检查看哪个地址有保存过数据
availFlag = *address;
if( availFlag != 0xFFFFFFFF )
{//找到已经写过的地址,读取数据
readEffMode = *(address+1);//因第一个是存储数据标志位,第二个数据是存储的有效值
if( readEffMode > 2)//防止读到的数据出错,出错时置为默认值
{
readEffMode = 0;//这里我默认值为0
}
return readEffMode;
}
address += (4096>>2);//因此数据为32位,所以所加数据要除以4
}
//在存储范围内未检查到有存储数据记录,则返回默认值
readEffMode = 0; //这里我默认值为0
return readEffMode;
}
//调用读取函数入口
eqModeNum = ReadEffModeProcess((UINT32*)POWEROFF_SAVE_ADDR);
//调用写入入口
address = (UINT32*) POWEROFF_SAVE_ADDR;
SaveData = (UINT32)eqModeNum;
saveDataNumber = 1;
SaveEffModeProcess(address, (UINT32*)&SaveData, saveDataNumber);