我需要将不同长度的项目存储在闪存芯片中的循环队列中。每个项目都有其封装,因此我可以弄清楚它的大小以及下一个项目的开始位置。当缓冲区中有足够的项目时,它将包装到开头。
在闪存芯片中存储循环队列的好方法是什么?
我可能要存储成千上万的物品。因此,从缓冲区的开头开始到缓冲区的末尾读取是不理想的,因为搜索缓冲区的末尾会花费一些时间。
另外,由于它是圆形的,因此我需要能够区分第一个项目和最后一个项目。
最后一个问题是将其存储在闪存中,因此擦除每个块既耗时,又只能为每个块设置一定次数。
最佳答案
首先,块管理:
在每个块的开头放置一个较小的标题。要跟踪“最旧的”和“最新的”,最主要的是块号,只需增加和模的模数即可。 k 必须大于您的总块数。理想情况下,使 k 小于您的MAX值(例如0xFFFF),以便您可以轻松分辨出什么是已擦除的块。
在启动时,您的代码依次读取每个块的标题,并按ni + 1 =(ni + 1)MODULO k的顺序查找第一个和最后一个块。注意不要被已擦除的块(块号为0xFFFF)或以某种方式损坏的数据(例如不完全擦除)混淆。
在每个块内
每个块最初都是空的(每个字节为0xFF)。每个记录都简单地一个接一个地写。如果您有固定大小的记录,则可以使用简单的索引对其进行访问。如果您有可变大小的记录,那么要读取它,您必须从块链表样式的开头开始进行扫描。
如果要具有可变大小的记录,但避免线性扫描,则可以在每个记录上具有定义良好的标题。例如。使用0作为记录定界符,并使用COBS -encode(或COBS/R -encode)每个记录。或使用您选择的字节作为分隔符,并在每个记录中都出现该字节时对其进行“转义”(类似于PPP protocol)。
在启动时,一旦知道最新的块,就可以对最新的记录进行线性扫描。或者,如果您有固定大小的记录或记录定界符,则可以进行二进制搜索。
擦除计划
对于某些闪存芯片,擦除一个块可能要花费大量时间-例如5秒。考虑将擦除安排为“提前”进行的后台任务。例如。当当前块已满x%时,则开始擦除下一个块。
记录编号
您可能想对记录进行编号。我过去做的方法是在每个块的标题中放入第一条记录的记录号。然后,软件必须对块中每个记录的数量进行计数。
校验和或CRC
如果要检测损坏的数据(例如,由于意外电源故障而导致写入或擦除不完整),则可以向每个记录甚至块 header 添加校验和或CRC。请注意,块标题CRC仅覆盖标题本身,而不覆盖记录,因为在写入每个新记录时无法将其重写。
关于embedded - Flash中的循环缓冲区,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1669245/