大部分FLASH性质存储器都有很多相似的操作规则,比如擦除方式就很特殊,最小擦出单位必须按照扇区来操作,而数据的写入地址的内容必须是擦除状态。这也是为什么EEPROM还能存在的一方面的原因吧(可以字节擦除)。由于这种特殊的性质,导致我们在利用FLASH存储数据的时候必须注意对扇区擦除的操作。这里我总结个人的两个操作技巧(以下内容是针对不带文件系统的存储器说明的,带文件系统的也可以参考)。
技巧1:如果可以,尽可能将协议长度定义为2的N次方,这样的话能保证每次要操作的一个新的扇区的时候地址刚好是新扇区的起始位置,那么这种擦除方式就很简单了,方式如下(假设扇区大小4KB):
if(wrAddr%4096 == 0)//刚好上次写到了上个扇区的末尾
{
wrAddrCmp = wrAddr;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr +4096))
break;
}
if(wrAddrCmp <(wrAddr +4096))
Sst25_EraseSector(wrAddr);
}
讲解:先判断是不是新的扇区地址,是的情况下读出扇区数据,判断是否都在擦除状态,否的情况下擦除该扇区。
技巧2:如果我们定义的协议长度不是2的N次方,或者写入长度完全不是固定的,那就可以参考下列方式来处理:
if((wrAddr%4096 == 0) || ((4096 - (wrAddr%4096)) < RecordLength))
{
if(wrAddr%4096 == 0)//刚好上次写到了上个扇区的末尾
{
wrAddrCmp = wrAddr;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr +4096))
break;
}
if(wrAddrCmp <(wrAddr +4096))
Sst25_EraseSector(wrAddr);
}
else if((4096 - (wrAddr%4096)) < RecordLength)//这次写入的数据会占用一个新的扇区
{
wrAddrCmp = wrAddr%4096 + 4096;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr%4096 + 4096 + 4096))
break;
}
if(wrAddrCmp <(wrAddr%4096 + 4096 + 4096))
Sst25_EraseSector(wrAddr%4096 + 4096);
}
}
讲解:这里同样添加了技巧1的计算方式是因为会有技巧1的情况出现比如40960(每次写40B,40960%40==0)。后面的思路是
先判断这次写入的数据从开始写入的地址算起到写入的长度结束,是不是超过了原先的扇区,如果超过了,就需要在写入之前对下一个扇区
做擦除处理。先获取下一个扇区的首地址,然后从首地址开始读取该扇区所有数据,是否都在擦除状态,如果有数据不在擦除状态就对下一个扇区
进行一次擦除操作。
技巧1:如果可以,尽可能将协议长度定义为2的N次方,这样的话能保证每次要操作的一个新的扇区的时候地址刚好是新扇区的起始位置,那么这种擦除方式就很简单了,方式如下(假设扇区大小4KB):
if(wrAddr%4096 == 0)//刚好上次写到了上个扇区的末尾
{
wrAddrCmp = wrAddr;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr +4096))
break;
}
if(wrAddrCmp <(wrAddr +4096))
Sst25_EraseSector(wrAddr);
}
讲解:先判断是不是新的扇区地址,是的情况下读出扇区数据,判断是否都在擦除状态,否的情况下擦除该扇区。
技巧2:如果我们定义的协议长度不是2的N次方,或者写入长度完全不是固定的,那就可以参考下列方式来处理:
if((wrAddr%4096 == 0) || ((4096 - (wrAddr%4096)) < RecordLength))
{
if(wrAddr%4096 == 0)//刚好上次写到了上个扇区的末尾
{
wrAddrCmp = wrAddr;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr +4096))
break;
}
if(wrAddrCmp <(wrAddr +4096))
Sst25_EraseSector(wrAddr);
}
else if((4096 - (wrAddr%4096)) < RecordLength)//这次写入的数据会占用一个新的扇区
{
wrAddrCmp = wrAddr%4096 + 4096;
while(Sst25_RdOneByte(wrAddrCmp++) == 0xFF)
{
if(wrAddrCmp ==(wrAddr%4096 + 4096 + 4096))
break;
}
if(wrAddrCmp <(wrAddr%4096 + 4096 + 4096))
Sst25_EraseSector(wrAddr%4096 + 4096);
}
}
讲解:这里同样添加了技巧1的计算方式是因为会有技巧1的情况出现比如40960(每次写40B,40960%40==0)。后面的思路是
先判断这次写入的数据从开始写入的地址算起到写入的长度结束,是不是超过了原先的扇区,如果超过了,就需要在写入之前对下一个扇区
做擦除处理。先获取下一个扇区的首地址,然后从首地址开始读取该扇区所有数据,是否都在擦除状态,如果有数据不在擦除状态就对下一个扇区
进行一次擦除操作。
后续需要考虑的问题就是,存储器数据存满的处理方式,一般会选择回绕,将最旧的数据删除掉,再开始存储新的数据,有时间再考虑。