在嵌入式环境中(使用 MSP430),我看到一些数据损坏是由部分写入非易失性存储器引起的。这似乎是由写入期间的功率损耗引起的(写入 FRAM 或信息段)。
我正在使用 CRC 验证存储在这些位置的数据。
我的问题是,防止这种“部分写入”损坏的正确方法是什么?目前,我已修改我的代码以写入两个单独的 FRAM 位置。因此,如果一个写入中断导致无效 CRC,则另一个位置应保持有效。这是一种常见的做法吗?我是否需要为任何非易失性存储器实现这种双重写入行为?
在嵌入式环境中(使用 MSP430),我看到一些数据损坏是由部分写入非易失性存储器引起的。这似乎是由写入期间的功率损耗引起的(写入 FRAM 或信息段)。
我正在使用 CRC 验证存储在这些位置的数据。
我的问题是,防止这种“部分写入”损坏的正确方法是什么?目前,我已修改我的代码以写入两个单独的 FRAM 位置。因此,如果一个写入中断导致无效 CRC,则另一个位置应保持有效。这是一种常见的做法吗?我是否需要为任何非易失性存储器实现这种双重写入行为?
一个简单的解决方案是维护两个版本的数据(在闪存的不同页面中),当前版本和以前的版本。每个版本都有一个包含序列号和验证序列号的单词的标题 - 只是序列号的 1 的补码,例如:
---------
| seq |
---------
| ~seq |
---------
| |
| data |
| |
---------
关键是当数据被写入时seq
,~seq
单词最后被写入。
在启动时,您读取具有最高有效序列号的数据(可能考虑回绕 - 特别是对于短序列字)。当您写入数据时,您会覆盖并验证最旧的块。
只要最后写入 CRC,您已经使用的解决方案是有效的,但它缺乏简单性,并且会产生可能不必要或不需要的 CRC 计算开销。
在 FRAM 上,您不必担心耐用性,但这是闪存和 EEPROM 的问题。在这种情况下,我使用回写式缓存方法,其中数据保存在 RAM 中,并且在修改时启动或重新启动计时器(如果它已经在运行) - 当计时器到期时,数据被写入 - 这可以防止突发写入内存,甚至在 FRAM 上也很有用,因为它最大限度地减少了数据写入的软件开销。
我们的工程团队对这些问题采取两管齐下的方法:用硬件和软件解决它!
第一个是二极管和电容器布置,可在欠压期间提供几毫秒的电力。如果我们注意到我们失去了外部电源,我们会阻止代码进入任何非违规写入。
其次,我们的数据对操作特别重要,它经常更新,我们不想磨损我们的非违规闪存存储(它只支持这么多的写入。)所以我们实际上在闪存中存储了 16 次数据并保护每个用 CRC 码记录。在启动时,我们找到最新的有效写入,然后开始我们的擦除/写入周期。
自从实施我们坦率的偏执系统以来,我们从未见过数据损坏。
更新:
我应该注意,我们的闪存在我们的 CPU 外部,因此如果 CPU 和闪存芯片之间存在通信故障,CRC 有助于验证数据。此外,如果我们连续遇到多个故障,则多次写入可以防止数据丢失。
我们使用了类似于 Clifford 的答案,但使用一次写入操作编写。您需要两个数据副本并在它们之间交替。使用递增的序列号,以便有效地一个位置具有偶数序列号而一个位置具有奇数。
像这样写数据(如果可以的话,在一个写命令中):
---------
| seq |
---------
| |
| data |
| |
---------
| seq |
---------
当您回读时,请确保两个序列号相同 - 如果它们不同,则数据无效。在启动时读取两个位置并确定哪个位置更新(考虑到序列号翻转)。
始终将数据存储在某种协议中,例如 START_BYTE、要写入的总字节数、数据、END BYTE。在写入外部/内部存储器之前,请务必检查 POWER Monitor 寄存器/ADC。如果无论如何您的数据损坏,END 字节也会损坏。因此,在整个协议验证后,该条目将无效。校验和不是一个好主意,如果你想在你的协议中包含 CRC,你可以选择 CRC16 而不是那个。