首先,要明确的是,数据写的过程包括
-
擦除,下图为NAND FLASH一个block(128K+7K)的时间,若擦除时被打断,数据会残缺
-
写入,下图为NAND FLASH写入一个page(2K+112Byte)的时间,所以一个block的写入需要64 x 300us = 19.2ms 的时间,若写入时被打断,数据会残缺
数据读的过程时间不计,因为读过程被打断,并不会造成数据的损坏
综上所述,对擦除,写入的失败都要进行处理(会造成数据损坏)
接下来,对乒乓操作进行解释,对于擦除和写入的处理有两种方式,先介绍
第一种
对于读写都放在一个接口内
函数
{
//擦写为一个任务
擦除任务
写入任务
//读取为一个任务
读取任务
若读取校验失败,屏蔽擦写任务,读取另一个块
}
首先,使用两个块作为乒乓块
关于写操作: 写入数据时,先指向块A,对其进行擦除并写入的操作。其中,若擦除时断电,或者写入时断电了,不做处理。若擦除和写入都完成的话,将写指针指向另一个块。
关于读取: 读取时读取不是写指针所指的那块,比如写指针指向A,则读取B
- 第一次上电初始化时,先对AB块进行擦除
- 收到数据后,将数据写入A块(上电初始化时擦除了,所以现在不用擦),然后将写指针指向B块。(若此时要读取数据的话,就读取A块,即不是写指针指向的那块)
- 再次收到数据,将数据写入B块,同理,上电初始化的时候擦除过了,所以现在不擦,然后将写指针指向A块(若此时要读取数据的话,就读取B块,即不是写指针指向的那块)
现在假设两块都有数据,那么接下来分析各种失败的情况
4. 擦除时掉电,不做处理,因为还有另一块做备份,上电时读取另一块数据就好
5. 写入时掉电,不做处理,同上
6. 读取时掉电,此时对数据不会有影响,不处理
第二种
函数
{
写入任务 //和擦除为一个任务
读取任务 //读取为一个任务
若读取校验失败,屏蔽擦写操作,读取另一个块
擦除任务 //和写入为一个任务
}
关于写操作: 假设数据已经写入两块,现在写入数据时,先指向块A,将数据写入块A,然后擦除块B,然后将写指针指向块B
关于读取: 读取时读取不是写指针所指的那块,比如写指针指向A,则读取B
现在假设两块都有数据,那么接下来分析各种失败的情况
- 写入时掉电,不做处理,因为还有另一块做备份,上电时读取另一块数据就好
- 擦除时掉电,不做处理,因为还有另一块做备份,上电时读取另一块数据就好
- 读取时掉电,此时对数据不会有影响,不处理
那么以上两种方式有何区别?
首先,不讨论写操作时掉电的情况,因为两种方式,写操作掉电的话,都只能读取旧的备份数据。所以以下默认写操作没问题。
区别在擦除操作和写操作的顺序,
第一种方式,由于SPI_FLASH的擦除时间偏长,所以掉电时很大概率落在擦除中,所以当进行写入操作时,万一掉电了,最新的数据没有写入到FLASH中,重新上电后读取的是上次备份的数据
第二种方式,由于每次都是先写入再擦除另一块,所以写入最新数据后,擦除的是备份的数据,当擦除备份数据掉电后,重新上电读取的是最新的数据。
其他问题
读取和写入会冲突吗?
就算使用FREE_RTOS,要需要保证读取 和 写入不能被打断,擦除和读取同时只能有一个在进行
若两个块读取的数据都校验失败怎么办?
重新初始化,擦除两个块的数据