【问题标题】:Data handling for a flash chip闪存芯片的数据处理
【发布时间】:2016-05-26 06:47:22
【问题描述】:

我正在复制here的摘录

Flash 擦除周期很长——非常长——擦除一个 Flash 扇区可能需要几秒钟。此外,由于保证擦除/重写周期的数量通常是有限的(通常约为 10,000 或最多 100,000),我们不能仅仅因为一个变量发生变化而擦除整个扇区。 该方法是“牺牲”整个扇区用于可变存储。在这个扇区中,变量存储在一个表中。如果变量发生更改,它不会被覆盖,而是丢弃旧值并生成表中的新条目。

我不明白上面的说法。

为什么当我们将要修改的数据添加为新数据项而不是“就地”修改现有数据时,我们不必擦除扇区?是不是因为我们要存储新数据的扇区中的空闲区域被0x00或0xFF预擦除了?

如果上述问题的答案是“是”,是否有可能在下面提到的情况下避免擦除循环?

我正在将系统日志写入闪存。一旦 flash 区域被系统日志完全填满,我需要擦除最早的日志条目并用最新的日志条目替换它。在这种情况下,我想不出可以避免擦除的情况。我以前从未使用过闪存驱动程序。任何帮助将不胜感激。我不是以英语为母语的人,希望这个问题不是含糊的。谢谢。

【问题讨论】:

  • 通常但并非总是如此,擦除设置软件将数据位视为 1。当我们编写时,我们将其中一些设为零(或未擦除状态)。写入只能以一种方式进行,例如零,您可以制作更多零,但要再次使它们成为零,您必须执行块擦除周期。写入或擦除需要很长时间,不是几秒钟,而是很长时间。所有有问题的闪存都有很好的记录。

标签: embedded flash-memory


【解决方案1】:

当您在 MCU 上没有适当的数据闪存(或 eeprom)时会弹出此类问题,因此您需要使用程序闪存来存储数据。程序闪存的工作方式与数据闪存相同,但由于它不应该经常被擦除,因此您可以使用物理上更小的电路。因为,通常:物理电路越小,擦除扇区越大。

问题是擦除大闪存扇区需要很长时间。但是一旦整个扇区被擦除(通常所有单元都设置为 1),您可以一次写入任何擦除的内存位置。基本上,您总是可以将 1 变为 0,但不能在不擦除的情况下将 0 变为 1。因此,您确实可以进行写入,因为该区域已被预先擦除。这样的写入几乎不需要擦除时间。

因此存在各种或多或少混淆的算法来利用这一点。这不是我真正推荐的解决方案,但我可以解释一下,因为不幸的是它有点常见:

假设您在闪存扇区中有两个变量,您需要不时更新它们。它们每个都有 1 个字节的数据。然后,您还可以为每个变量提供一个唯一的搜索键(不能是已擦除闪存单元的值)并像这样存储它们:

Address  Key   Value
0x0000   0x01  0xAA
0x0002   0x02  0xBB

你会有一些类似的程序结构

typedef struct
{
  uint8_t key;
  uint8_t val;
} flash_var;

const flash_var* x = (flash_var*)0x0001;
const flash_var* y = (flash_var*)0x0002;

接下来您要将x 的值更改为0xCC。您将调用您的闪存编程驱动程序,它将在下一个可用闪存位置写入新变量的副本。您的 Flash 现在看起来像这样:

Address  Key   Value
0x0000   0x01  0xAA
0x0002   0x02  0xBB
0x0004   0x01  0xCC

所以你有变量x 的两个副本,但程序将更新指针,使其仅指向它最近出现的位置。前一个只是作为“死区”存在于闪存中。通过从 flash 块的末尾向后搜索开头,查找第一次出现的搜索键 0x01,您始终可以找出哪个是最新的。

这意味着在开机时,查找变量将不是随机访问,而是相当缓慢的线性搜索。

这个算法有几个问题:

  • 不是随机访问,而是很慢的搜索。
  • 要实现很多额外的复杂性,这会增加出现错误的机会并占用资源。
  • 存在相同数据的重复项。这对于任务关键型系统是不可接受的。假设搜索键损坏 - 程序不会一无所获并报告错误,而是会抓取旧数据。
  • 根据闪存的性质,您可能希望在闪存中包含校验和。使用上述算法,每个变量都必须有一个单独的校验和,这是对空间的巨大浪费。
  • 当闪存扇区已满时,无论如何您都必须擦除它。然后,您必须想出一种将变量临时存储在 RAM 中的方法。它变得复杂。
  • 但最重要的是,该行业可能会在任何给定时间被填满,而且很难预测何时。您的程序必须能够处理这种特殊情况,并在它发生时应对较长的擦除时间。这是最坏的情况,实时嵌入式系统必须始终在最坏的情况之后进行设计。

    这是一个主要的逻辑缺陷:如果您的程序可以在扇区被填充并且您必须擦除时处理特殊情况,那么为什么它不能每次都处理相同的情况呢?也就是说,由于您的程序无论如何都必须能够处理这个问题,因此您也可以每次都擦除整个扇区。

    因此结果表明,该算法只在最好的情况下节省时间,这是毫无用处的,因为无论如何都必须编写它才能在最坏的情况下运行。在最坏的情况下,这是您必须设计的,它根本不会节省任何时间。事实上,算法引入的额外复杂性使得最坏情况需要更多时间。

    这就是为什么这些算法在设计上有些混乱。在设计合理的实时系统中,它们只节省闪存写入周期,没有别的。

所以总结一下,我建议不要使用这些算法。相反,选择具有适当数据闪存的 MCU。它将具有更小的扇区、更快的擦除时间和更多的写入周期。

【讨论】:

  • 我认为这是一种常见的情况,会有通用的解决方案可用。但令我惊讶的是,找到合适的解决方案非常困难。您提供的信息非常有用。非常感谢您的详细解释。
  • 你当然可以使用二分搜索,但是在启动时间线性搜索一个典型的擦除块大小并没有那么糟糕。此外,如果需要,您可以通过将旧记录覆盖到“所有位已写入”状态来销毁旧记录,但保留多个有效记录作为后备可能很有用。
  • @ChrisStratton 不,你不能进行二分搜索,因为数据不会被排序。除了我想你可以做二进制搜索来找到有效数据的结束位置。最好的算法确实取决于段的大小。
  • 您似乎已经开始理解那里了 - 您只需要找到结尾,因此它与任何其他类型的可搜索一样可二进制搜索。
  • @ChrisStratton 但是要找到存储的每种类型的数据,您必须从最后开始进行线性搜索......在最坏的情况下,您必须对整个段进行线性搜索。这实际上是该算法不好的另一个原因:如果一种数据的更改频率低于其他数据(这很可能),它将减慢搜索速度。
猜你喜欢
  • 2012-03-29
  • 1970-01-01
  • 2019-09-11
  • 1970-01-01
  • 2015-11-09
  • 2014-04-21
  • 1970-01-01
  • 2017-12-07
  • 2013-02-02
相关资源
最近更新 更多