1 Flash器件的写入步骤如下:
- 读取扇区内所有数据到RAM中;
- 把需要写入的数据写到对应的RAM;
- 擦除FLASH扇区;
- 把RAM中的数据写入到flash中;
再将数据写入Flash时,必须对Flash进行擦除操作,否则写入数据会将此扇区清零或变成未知数据。
另一方面,擦除Flash并不是理想状态下一个字节一个字节的擦除而是需要按照一个block操作。Block作为最小操作单位一般不少于4个字节,当只需更改一个字节时就显得相当繁琐,并且会严重影响无关区域的使用寿命。
还有一方面就是Flash的擦写速度很慢,比如给飞思卡尔的g12芯片,擦除一个block大约需要4ms,如果需要擦除大量的block的话,强烈建议再系统比较空闲的情况下,分片去擦。
2 Flash器件的擦除重写
本文提供一种以容量换数量提高Flash使用寿命的方法。
Flash的擦写次数一般为10万次左右,在设计系统的时候,很多情况下10万次的擦除寿命不够用,但如果外加外部EEPROM的话往往成本增加的比较多,此时我们就需要再10万次的擦除次数提高数倍。
假如,我们有两个字节数据需要频繁存储的话,我们为此准备40个字节的FLASH空间供其使用,每四个字节为一个Block,共10个Block。
每一个block我们都按照上图的数据定义,数据占2个字节data[0]与data[1],
count值为计数值,没存储一次,count值都会加1,占一个字节data[2]
checksum是为了保证数据正确而做的校检和,占1个自己data[3]。data[3]=data[0]+data[1]+data[2];此数据仅仅作为校检和,不必考虑数据溢出问题。
1)写入过程
void Flash_Write_data()
{
uint8_t data[4]={0};
uint16_t address;
data[0]=data_Temp>>8;
data[1]=(uint8_t)data_Temp;
/Count_Temp上次有效值/
if(Count_Temp>=0xFE)
{
data[2] = 0; /Flash默认值为0xFF,所以0xFF默认为无效,不能使用/
}
else
{
data[2] =Count_Temp+1;
}
data[3]=data[0]+data[1]+data[2];
/address_count上次数据有效时的地址编号,address_temp起始地址数组/
if(address_count >= 10-1)
{
address = address_temp[0];
}
else
{
address = address_temp[address_count + 1];
}
Flash_Block_Write(address,data);
}
由此代码可以看出,通常情况下Count值数据大的是最后一次写的,为有效值。特殊情况下,到0xFF后会重新从0开始。则0或者是其他按顺序的最后一个数据有效。很容易可以区分有效无效。
1)读入过程
读出Flash的有效值,首先需要将所有的Flash值都读出来,首先进行Count值的比较。简单的来说就是将写入时的计算方式反过来再计算一次。
void Flash_Read_data()
{
uint8_t data_Temp1[4]={0};
uint8_t data_Temp2[4]={0};
uint8_t data[4]={0};
uint8_t i=0;
for(i=1;i<=9;i++)
{
Flash_Block_Read(address_temp[i-1],data1);
Flash_Block_Read(address_temp[i],data2);
if(((data2[2]-data[1]) >1)&&((data2[2]-data[1])<0))
{
data[0]=data1[0];
data[1]=data1[1];
data[2]=data1[2];
data[3]=data1[3];
address_count = i;
return;
}
else
{
Flash_Block_Read(address_temp[0],data1);
Flash_Block_Read(address_temp[9],data2);
if((data[2]=0xFE)&&((data[2]=0x00))
{
data[0]=data1[0];
data[1]=data1[1];
data[2]=data1[2];
data[3]=data1[3];
address_count = 1;
}
}
}
data_Temp = (data[0]<<8)+data[1];
Count_Temp = data[2];
}
若要使用此代码,需谨慎验证,若发现错误,请及时指出。