【问题标题】:How to prevent "partial write" data corruption during power loss?断电时如何防止“部分写入”数据损坏?
【发布时间】:2014-01-29 20:33:59
【问题描述】:

在嵌入式环境中(使用 MSP430),我看到一些数据损坏是由于部分写入非易失性内存而导致的。这似乎是由于写入期间的功率损耗(写入 FRAM 或信息段)造成的。

我正在使用 CRC 验证存储在这些位置的数据。

我的问题是,防止这种“部分写入”损坏的正确方法是什么?目前,我已修改我的代码以写入两个单独的 FRAM 位置。因此,如果一个写入中断导致无效的 CRC,则另一个位置应保持有效。这是一种常见的做法吗?我是否需要为任何非易失性内存实现这种双重写入行为?

【问题讨论】:

    标签: memory embedded msp430 non-volatile


    【解决方案1】:

    一个简单的解决方案是维护 两个 版本的数据(在闪存的不同页面中),当前版本和以前的版本。每个版本都有一个标题,其中包含一个序列号和一个验证序列号的单词 - 只是序列号的 1 的补码,例如:

    ---------
    |  seq  |
    ---------
    | ~seq  |
    ---------
    |       |
    | data  |
    |       |
    ---------
    

    关键是当写入数据时,seq~seq 两个词都写在最后

    在启动时,您读取具有最高有效序列编号的数据(可能考虑回绕——尤其是对于短序列词)。当您写入数据时,您会覆盖并验证 最旧的块。

    只要最后写入 CRC,您已经使用的解决方案就是有效的,但它缺乏简单性并且会产生不必要或不希望的 CRC 计算开销。

    在 FRAM 上,您不必担心耐用性,但这是闪存和 EEPROM 的问题。在这种情况下,我使用回写式缓存方法,其中数据保存在 RAM 中,并且在修改时启动或重新启动计时器(如果它已经在运行) - 当计时器到期时,数据被写入 - 这可以防止突发写入避免破坏内存,甚至在 FRAM 上也很有用,因为它最大限度地减少了数据写入的软件开销。

    【讨论】:

    • 我看到在某些情况下使用 seq 和 ~seq 代替 CRC 可能是有利的。但是对于 Flash,在我看来,CRC 在内存块坏的情况下会有所帮助?
    • 当然,除非您可以在写入时检测到由于内存块损坏而导致的写入失败,这将阻止写入 seq 和 ~seq 并阻止在开始时读取该数据-起来。
    • 在我的实现中,单独验证了各个数据项;重要的是,单个数据项故障不会导致所有数据都被丢弃。这里要解决的问题是不完整的写入检测,而不是数据损坏。如果您想将整块数据验证和不完整的写保护结合起来,那么 CRC 是可行的方法。
    【解决方案2】:

    我们的工程团队对这些问题采取了两种方法:通过硬件和软件解决问题!

    第一个是二极管和电容器布置,可在欠压期间提供几毫秒的电力。如果我们注意到我们失去了外部电源,我们会阻止代码进入任何非违规写入。

    其次,我们的数据对操作尤为关键,它经常更新,我们不想耗尽我们的非违规闪存存储(它只支持这么多的写入。)所以我们实际上在闪存中存储了 16 次数据并用 CRC 码保护每条记录。在启动时,我们会找到最新的有效写入,然后开始我们的擦除/写入周期。

    自实施我们坦率的偏执系统以来,我们从未见过数据损坏。

    更新:

    我应该注意,我们的闪存在 CPU 外部,因此如果 CPU 和闪存芯片之间存在通信故障,CRC 有助于验证数据。此外,如果我们连续遇到多个故障,则多次写入可以防止数据丢失。

    【讨论】:

    • 多个副本可能对 Flash 很重要,但在 FRAM 设备上只需要两个副本,因为它具有无限的耐用性。即使在 Flash 上,根据更新模式和频率,回写式缓存可能就足够了。
    • 硬件方面的好建议。不幸的是,我目前的项目太远了,无法请求更改,但这绝对是未来项目需要考虑的问题。
    • 对不起,我的经验不足,但是在您的硬件设置中,当外部电源丢失时,您会收到中断吗?
    • @schumacher574:具体查看 MSP430,根据变体,您可能有“掉电复位 (BOR)”和“电源电压监控器 (SVS)”中的零个、一个或两个。后者可以产生复位或中断,尽管您是否有足够的时间做任何有用的事情将取决于您的电源设计和断电时的电流消耗。如果您没有 SVS,则可以使用外部主管。见:ti.com/lit/ml/slap126/slap126.pdf
    • @schumacher574,我们的硬件设置用于电机控制,它要求我们监控大约 40 伏的主系统电压。如果系统电压降至零,我们知道我们有几毫秒的时间直到我们的逻辑电压变低,所以我们基本上可以免费获得断电事件。
    【解决方案3】:

    我们使用了与 Clifford 的答案类似的东西,但用一次写入操作编写。您需要两个数据副本并在它们之间交替。使用递增的序列号,以便有效地一个位置具有偶数序列号而一个位置具有奇数。

    像这样写数据(如果可以的话,在一个写命令中):

    ---------
    |  seq  |
    ---------
    |       |
    | data  |
    |       |
    ---------
    | seq   |
    ---------
    

    当您回读它时,请确保两个序列号相同 - 如果它们不同,则数据无效。在启动时读取两个位置并确定哪个位置更新(考虑到序列号翻转)。

    【讨论】:

      【解决方案4】:

      始终将数据存储在某种协议中,例如 START_BYTE、要写入的总字节数、数据、END BYTE。 在写入外部/内部存储器之前,请务必检查 POWER Monitor 寄存器/ADC。 如果无论如何您的数据损坏,END 字节也会损坏。因此,在整个协议验证后,该条目将无效。 校验和不是一个好主意,如果你想在你的协议中包含 CRC,你可以选择 CRC16 而不是那个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多