是否有微控制器EEPROM磨损均衡一般的算法?(Is there a general algorit

2019-07-29 11:39发布

我工作的一个Arduino库,将最大限度地AVR的EEPROM的寿命。 它需要的要存储的变量数和没有休息。 这是我的尝试,这并不适用于所有情况。

背景资料

爱特梅尔说每个存储器单元的额定100000写入/擦除周期。 他们还提供了一个应用指南 ,其中介绍了如何执行磨损均衡。 下面是应用笔记摘要。

通过交替在两个内存地址写,我们可以增加擦除/写入20万次。 三个内存地址给你30万擦/写周期等。 要自动执行此过程中,一个状态缓冲区用于跟踪的下一个写应该是。 状态缓冲器还必须是相同的长度参数缓冲器,因为磨损均衡,必须在其上,以及执行。 既然我们不能存储下一个写的指数,我们递增状态缓冲器对应的索引。

下面是一个例子。

   <------------------- EEPROM -------------------->  
   0                                               N
   -------------------------------------------------
       Parameter Buffer    |     Status Buffer     |
   -------------------------------------------------

   Initial state.
   [ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 ]

   First write is a 7. The corresponding position
   in the status buffer is changed to previous value + 1.
   Both buffers are circular.
   [ 7 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 ]

   A second value, 4, is written to the parameter buffer 
   and the second element in the status buffer becomes
   the previous element, 1 in this case, plus 1.
   [ 7 | 4 | 0 | 0 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 ]

   And so on
   [ 7 | 4 | 9 | 0 | 0 | 0 | 1 | 2 | 3 | 0 | 0 | 0 ]

要确定进行下一次写,我们来看看要素间的差异。 如果前一个元素+ 1不等于下一个元素则是应该在哪里发生下一次写。 例如:

   Compute the differences by starting at the first
   element in the status buffer and wrapping around. 
   General algo: previous element + 1 = current element
   1st element:  0 + 1 = 1 = 1st element (move on)
   2nd element:  1 + 1 = 2 = 2nd element (move on)
   3rd element:  2 + 1 = 3 = 3rd element (move on)
   4th element:  3 + 1 = 4 != 4th element (next write occurs here)

   [ 7 | 4 | 9 | 0 | 0 | 0 | 1 | 2 | 3 | 0 | 0 | 0 ]
                 ^                       ^
                 |                       |

   Another edge case to consider is when the incrementing values
   wrap around at 256 because we are writing bytes. With the
   following buffer we know the next write is at the 3rd element 
   because 255 + 1 = 0 != 250 assuming we are using byte arithmetic.

   [ x | x | x | x | x | x | 254 | 255 | 250 | 251 | 252 | 253 ]
                                          ^
                                          | 

   After we write at element 3 the status buffer is incremented 
   to the next value using byte arithmetic and looks like this.
   255 + 1 = 0 (wrap around)
   0 + 1 != 251 (next write is here)

   [ x | x | x | x | x | x | 254 | 255 |  0  | 251 | 252 | 253 ]
                                                ^
                                                | 

上述这些实施例表明如何延长EEPROM的寿命为一个变量。 对于多变量想象EEPROM分割成多个段具有相同的数据结构,但较小的缓冲区。

问题

我有什么上述工作我的代码。 我的问题是,当缓冲区长度> = 256这里是什么情况算法不起作用

   Buffer length of 256. The last zero is from
   the initial state of the buffer. At every index
   previous element + 1 == next element. No way to
   know where the next write should be.

   <-------------- Status Buffer ------------>
   [  1  |  2  | ... | 253 | 254 | 255 |  0  ]


   A similar problem occurs when the buffer length
   is greater than 256. A lookup for a read will think
   the next element is at the first 0 when it should be at 
   255.
   <-------------------- Status Buffer ------------------>
   [  1  |  2  | ... | 253 | 254 | 255 |  0  |  0  |  0  ]

我该如何解决上述问题? 有没有更好的方法来追踪下一个元素应该被写的?

Answer 1:

有关一般EEPROM寿命延长的几点思考:

  1. EEPROM单元通常在两步操作写入(由硬件):首先,将单元被擦除,即,设置为全1(0b11111111 = 0xff的),则该位被写入(有效只有那些0)在实际写入。 位只能通过实际的写操作设置为0。 改变从0到1的位需要整个小区要被擦除,然后重新写入新的值。

  2. 如果EEPROM单元已经包含将要被写入到它的值相同 - 其可以是用于数据的或多或少是这种情况(重新)写 - 没有必要写入到细胞在所有,减少穿的是写操作0一可能要检查的内容,以决定该细胞是否需要写入的所有,而不是总是写一个新的值给它吧。

  3. 上述导致的方法,其中的小区被写入之前,如果有在新的值,其中所存储的值具有0位的任何1位仅擦除,所述的组合(即,如果StoredValue & NewValue != NewValue )。 没有必要以擦除细胞如果没有0 -为新值(所需> 1位转换StoredValue & NewValue == NewValue )。

  4. AVR具有用于擦除和写入,分别,EEPROM单元,以支持上面提到的机制单独的指令。

  5. 的数据传送到EEPROM的最坏情况下的速度将执行时当然降的读 - 比较 - 擦除 - 写而不是仅仅擦除 - 写操作。 然而,这完全跳过擦除 - 写操作对可能降低相对速度损失一些/最细胞的潜力。

对于您目前的问题,想想以上几点:为什么不使用单个位来存储你的下一个写位置?

例:

状态缓冲区被初始化为所有的人:

Bit number: 0123 4567 89AB CDEF
Value:      1111 1111 1111 1111

访问EEPROM中的值之前,找到你的状态缓冲区中的第1位。 该位的数字代表你(圆)参数缓存的当前“头”的地址。

每次提前参数缓冲时间,在你的状态缓冲器中的下位设置为0:

Bit number: 0123 4567 89AB CDEF
Value:      0111 1111 1111 1111

然后

Value:      0011 1111 1111 1111

然后

Value:      0001 1111 1111 1111

等等。

这可以在删除整个小区进行,并会只有这样,“穿”的每次更新您的状态缓冲区的单个位-如果写入的数据只有一个0位,太。
要打开,例如,一个存储值0111到新值0011要写入的数据应该是1011data = ( newValue XOR oldValue ) XOR 0xff ),剩下的所有位除了单一个我们真正想改变不变。

一旦状态缓冲耗尽(全部为0),它是在完全清除,而这一切又重新开始。

这里一个明确的好处是,仅状态的单个位需要每参数缓冲器,相比爱特梅尔应用手册仅消耗1/8的存储器的单位得以维持。 此外,找到下一个写入位置也将更快,因为只有在状态缓冲区的读取操作的1/8是必要的。 (编辑:不正确的,因为EEPROM读取来在几乎为零的性能价格比,明智的,而所需的比特移位可能需要一些几十周期。)

另外要注意,虽然:你是否认为这是真正有用的使用256+参数缓冲单元? 有问题时,例如,1024个字节的总可用EEPROM的设备上的单位将变得非常小。 - 和100000个周期乘以256是写操作相当庞大的数目,如果那么大的一个数似乎是必需的,但可能是不应该被用于此目的不惜一切不对劲的算法或EEPROM。 作为替代,外部NVRAM会在某些情况下是不错的选择。

访问时间可能是一个方面也在这里:当试图查找,并在参数缓冲器具有256字节的状态缓冲区,256(+3)读取,也就是说,3个字节大小的元素读操作会在最坏的需要案例 - 一个巨大的开销!

有一个关于EEPROM单元的运作一个很能说明问题的文件,计有该怎么和 - 为何恶化:

意法半导体:“如何设计人员可以充分利用意法半导体串行EEPROM的”,应用笔记AN2014



Answer 2:

我建议你用一个简单的“脏”位上的数据元素,而不是柜台。 除非扫描最后写入元素是太慢了,或者你想要做的事复杂的像跟踪坏EEPROM单元的,有一个在其柜台和目录没有任何意义。

该算法很简单:在你写的每单元设置一个“脏”位,并扫描该位,当你需要阅读的最后一个元素或写一个新的。 当你用完了干净点,要么删除所有元素或(在Arduino的情况下),只需扳动“脏”位的值,并从头开始。 我写了一个详细的解释在这里 ,如果你需要一个。



文章来源: Is there a general algorithm for microcontroller EEPROM wear leveling?