闪存芯片的数据处理
Data handling for a flash chip
我正在复制 here
的摘录
闪存擦除周期很长 - 真的很长 - 擦除闪存扇区可能需要几秒钟。此外,由于保证擦除/重写循环的次数通常是有限的(通常约为 10,000 次或最多 100,000 次),我们不能仅仅因为一个变量发生变化就擦除整个扇区。
做法是"sacrifice"一整扇区用于变量存储。在这个扇区中,变量存储在table中。如果变量发生变化,它不会被覆盖,而是旧值被丢弃并生成 table 中的新条目。
我不明白上面的说法。
为什么我们将要修改的数据添加为新数据项而不是修改现有数据时,不必擦除扇区"in-place"?是不是因为我们要存储新数据的扇区中的空闲区域被预先擦除为0x00或0xFF?
如果上述问题的答案是"Yes",是否可以在下面提到的情况下避免擦除循环?
我正在将系统日志写入闪存。一旦闪存区域完全被系统日志填满,我需要擦除最早的日志条目并用最新的日志条目替换它。在这种情况下,我想不出可以避免擦除的情况。我以前从未使用过闪存驱动程序。任何帮助将不胜感激。我不是以英语为母语的人,希望这个问题不含糊。谢谢。
当您在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。你会调用你的闪存编程驱动程序,它会在下一个可用的闪存位置写入新变量的副本。您的闪光灯现在看起来像这样:
Address Key Value
0x0000 0x01 0xAA
0x0002 0x02 0xBB
0x0004 0x01 0xCC
所以你有变量的两个副本x
,但程序会将指针更新为仅指向它最近一次出现的位置。前一个只是以 "dead space" 的形式出现在闪光灯中。您始终可以找出哪个是最新的,方法是从闪存块的末尾向后搜索开头,查找搜索键 0x01 的第一次出现。
这意味着在开机时,查找变量将不是随机访问,而是相当缓慢的线性搜索。
这个算法有几个问题:
- 不是随机访问,但搜索速度很慢。
- 实施起来有很多额外的复杂性,这会增加出现错误的机会并占用资源。
- 存在相同数据的重复项。这对于关键任务系统来说是不可接受的。假设一个搜索键被损坏 - 而不是什么都找不到并报告错误,程序将取而代之的是获取旧数据。
- 根据闪存的性质,您可能希望在闪存中包含校验和。使用上述算法,每个变量都必须有一个单独的校验和,这是对 space.
的巨大浪费
- 当flash扇区满了,无论如何都要擦除它。然后你必须想出一种方法将变量临时存储在 RAM 中。它变得复杂。
但最重要的是,该行业可能会在任何给定时间被填满,而且很难预测何时。您的程序必须能够处理这种特殊情况,并在这种情况发生时应对较长的擦除时间。这是最坏的情况,实时嵌入式系统必须总是在最坏的情况之后设计。
这是主要的逻辑缺陷:如果您的程序可以处理扇区被填满而您必须擦除的特殊情况,那么为什么它不能每次都处理相同的情况?也就是说,由于您的程序无论如何都必须能够处理此问题,因此您也可以每次都擦除整个扇区。
事实证明,该算法只能在最好的情况下节省时间,这是毫无用处的,因为无论如何都必须将其编写为在最坏的情况下运行。在最坏的情况下,这是您必须设计的,它根本不会节省任何时间。事实上,算法引入的额外复杂性使得最坏情况需要更多时间。
这就是为什么这些算法在每个设计中都有些混乱。在设计得当的实时系统中,它们只节省闪存写入周期,没有别的。
所以总而言之,我建议不要使用这些算法。相反,选择具有适当数据闪存的 MCU。它将具有更小的扇区、更快的擦除时间和更多的写入周期。
我正在复制 here
的摘录闪存擦除周期很长 - 真的很长 - 擦除闪存扇区可能需要几秒钟。此外,由于保证擦除/重写循环的次数通常是有限的(通常约为 10,000 次或最多 100,000 次),我们不能仅仅因为一个变量发生变化就擦除整个扇区。 做法是"sacrifice"一整扇区用于变量存储。在这个扇区中,变量存储在table中。如果变量发生变化,它不会被覆盖,而是旧值被丢弃并生成 table 中的新条目。
我不明白上面的说法。
为什么我们将要修改的数据添加为新数据项而不是修改现有数据时,不必擦除扇区"in-place"?是不是因为我们要存储新数据的扇区中的空闲区域被预先擦除为0x00或0xFF?
如果上述问题的答案是"Yes",是否可以在下面提到的情况下避免擦除循环?
我正在将系统日志写入闪存。一旦闪存区域完全被系统日志填满,我需要擦除最早的日志条目并用最新的日志条目替换它。在这种情况下,我想不出可以避免擦除的情况。我以前从未使用过闪存驱动程序。任何帮助将不胜感激。我不是以英语为母语的人,希望这个问题不含糊。谢谢。
当您在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。你会调用你的闪存编程驱动程序,它会在下一个可用的闪存位置写入新变量的副本。您的闪光灯现在看起来像这样:
Address Key Value
0x0000 0x01 0xAA
0x0002 0x02 0xBB
0x0004 0x01 0xCC
所以你有变量的两个副本x
,但程序会将指针更新为仅指向它最近一次出现的位置。前一个只是以 "dead space" 的形式出现在闪光灯中。您始终可以找出哪个是最新的,方法是从闪存块的末尾向后搜索开头,查找搜索键 0x01 的第一次出现。
这意味着在开机时,查找变量将不是随机访问,而是相当缓慢的线性搜索。
这个算法有几个问题:
- 不是随机访问,但搜索速度很慢。
- 实施起来有很多额外的复杂性,这会增加出现错误的机会并占用资源。
- 存在相同数据的重复项。这对于关键任务系统来说是不可接受的。假设一个搜索键被损坏 - 而不是什么都找不到并报告错误,程序将取而代之的是获取旧数据。
- 根据闪存的性质,您可能希望在闪存中包含校验和。使用上述算法,每个变量都必须有一个单独的校验和,这是对 space. 的巨大浪费
- 当flash扇区满了,无论如何都要擦除它。然后你必须想出一种方法将变量临时存储在 RAM 中。它变得复杂。
但最重要的是,该行业可能会在任何给定时间被填满,而且很难预测何时。您的程序必须能够处理这种特殊情况,并在这种情况发生时应对较长的擦除时间。这是最坏的情况,实时嵌入式系统必须总是在最坏的情况之后设计。
这是主要的逻辑缺陷:如果您的程序可以处理扇区被填满而您必须擦除的特殊情况,那么为什么它不能每次都处理相同的情况?也就是说,由于您的程序无论如何都必须能够处理此问题,因此您也可以每次都擦除整个扇区。
事实证明,该算法只能在最好的情况下节省时间,这是毫无用处的,因为无论如何都必须将其编写为在最坏的情况下运行。在最坏的情况下,这是您必须设计的,它根本不会节省任何时间。事实上,算法引入的额外复杂性使得最坏情况需要更多时间。
这就是为什么这些算法在每个设计中都有些混乱。在设计得当的实时系统中,它们只节省闪存写入周期,没有别的。
所以总而言之,我建议不要使用这些算法。相反,选择具有适当数据闪存的 MCU。它将具有更小的扇区、更快的擦除时间和更多的写入周期。