STM32L1xx 上的闪存 ECC 算法

Flash ECC algorithm on STM32L1xx

在STM32L1xx上实现的flash ECC算法(Flash Error Correction Code)是如何工作的?

背景: 我想对 STM32L151 MCU 程序闪存中的单个字进行多次增量写入,而不在其间进行页面擦除。没有 ECC,可以增量设置位,例如首先是 0x00,然后是 0x01,然后是 0x03(STM32L1 将位擦除为 0 而不是 1),等等。由于 STM32L1 每个字有 8 位 ECC,因此此方法不起作用。然而,如果我们知道 ECC 算法,我们可以很容易地找到一个短的值序列,可以在不违反 ECC 的情况下增量写入。

我们可以简单地尝试不同的值序列,看看哪些有效(一个这样的序列是 0x0000001、0x00000101、0x00030101、0x03030101),但如果我们不知道 ECC 算法,我们就无法检查,是否该序列违反了 ECC,在这种情况下,如果位被破坏,纠错将不起作用。

[编辑] 该功能应该用于使用 STM32L1 的内部程序存储器实现一个简单的文件系统。数据块用 header 标记,其中包含一个状态。多个块可以驻留在单个页面上。状态可以随时间改变(首先是 'new',然后是 'used',然后是 'deleted',等等)。状态的数量很少,但是如果我们可以覆盖以前的状态而不必先擦除整个页面,这将使事情变得容易得多。

感谢任何意见!由于到目前为止还没有答案,我将总结一下我到目前为止发现的内容(根据经验和对此答案的评论):

  • 根据 STM32L1 数据表 "The whole non-volatile memory embeds the error correction code (ECC) feature.",但参考手册并未说明有关程序存储器中 ECC 的任何内容。
  • 数据表符合我们在随后将多个单词写入同一程序内存位置而不擦除其间的页面时凭经验发现的内容。在这种情况下,某些值序列有效而其他值序列无效。

以下是我的个人结论,基于经验发现、有限的研究和来自该线程的评论。根据官方文档,不是。不要在上面做任何严肃的工作(我也不会)!

  • 看来,ECC 是按 32 位字计算和保存的。如果是这样,ECC 的长度必须至少为 7 位。
  • 每个单词的 ECC 可能与单词本身写入相同的非易失性内存。因此,同样的限制适用。 IE。在擦除之间,只能设置额外的位。正如斯塔克指出的那样,我们只能用以下值覆盖程序内存中的单词:

    • 仅设置附加位但不清除任何位
    • 拥有一个 ECC,与之前的 ECC 相比,它也只设置了额外的位。
  • 如果我们写入一个值,只设置额外的位,但 ECC 需要清除位(因此无法正确写入),那么:

    • 如果ECC有一位错误,通过ECC算法纠正错误,可以正确读取写入的值。但是,如果另一位失败,ECC 将不再起作用,因为 ECC 只能纠正单位错误。
    • 如果ECC错误超过一位,ECC算法无法纠正错误,读取的值将是错误的。
  • 我们不能(轻易地)凭经验找出哪些值序列可以正确写入,哪些不能。如果可以正确地写入和读回一系列值,我们就不知道,这是否是由于单比特错误的自动纠正。这方面是这个问题要求实际算法的全部原因。

  • ECC 算法本身似乎没有记录。汉明码似乎是 ECC 的常用算法,他们在 AN4750 中写道,汉明码实际上用于 SRAM 中的纠错。该算法可能会也可能不会用于STM32L1的程序存储器。

  • STM32L1 reference manual 似乎并没有明确禁止在不擦除的情况下多次写入程序内存,但是也没有文档说明相反的情况。为了不使用未记录的功能,我们将避免在我们的产品中使用此类功能并寻找解决方法。

有趣的问题。

首先我要说的是,即使你找到了 ECC 算法,你也不能依赖它,因为它没有文档,并且可以随时更改,恕不另行通知。

但是通过合理数量的测试找出算法似乎是可能的。
我会尝试构建以常量值开始然后仅清除一位的测试。
当您读取该值并且它是起始值时,您的位无法更改 ECC 中的所有必要位。

喜欢:

for <bitIdx>=0 to 31
  earse cell
  write start value, like 0xFFFFFFFF & ~(1<<testBit)
  clear bit <bitIdx> in the cell
  read the cell
next

如果您发现擦除测试适用于所有位的起始值,则该起始值可能设置了所有位的 ECC。
编辑:这对于任何 ECC 都应该是正确的,因为每个 ECC 总是需要至少两个位的差异来检测和修复,可靠的一个缺陷位。
由于第一个位的差异在于值本身,第二个变化需要在隐藏的 ECC 位中,隐藏位将非常有限。

如果您使用不同的起始值重复此测试,您应该能够收集到足够的数据来证明使用了哪种纠错。