2010-08-23 98 views
9

我最近确定需要将不经常更新的配置变量存储在微控制器的EEPROM中。添加状态,本程序将立即迫使人们担心安全地存储和访问EEPROM

  • 检测EEPROM未初始化的数据(即第一次启动),
  • 转换或无效旧固件版本的数据,并
  • 解决多重结构,每个固件更新都可能会增长。

广泛的谷歌搜索只发现了一篇文章,地址keeping your EEPROM data valid through firmware updates。有没有人使用过这篇文章中讨论的方法?有更好的替代方法吗?

回答

7

就我个人而言,我更喜欢“标签表格”格式。

在这种格式中,您的数据被分成一系列“表格”。每个表格都有一个标题,它遵循可预测的格式和可根据需要更改的正文。

这里是什么样的一个表看起来像一个例子:

Byte 0: Table Length (in 16-bit words) 
Byte 1: Table ID  (used by firmware to determine what this data is) 
Byte 2: Format Version (incremented every time the format of this table changes) 
Byte 3: Checksum  (simple sum-to-zero checksum) 
Byte 4: Start of body 
... 
Byte N: End of body 

我不是存储大量的数据,所以我用一个字节在标题中的每个领域。只要你不改变它,你可以使用任何你需要的尺寸。数据表被一个接一个地写入EEPROM中。

当您的固件需要从EEPROM读取数据时,它会从第一个表开始读取。如果固件识别了表ID并且支持列出的表格版本,则它将数据加载到表格的主体之外(当然,在验证校验和之后)。如果ID,版本或校验和不检出,则简单地跳过该表。长度字段用于查找链中的下一个表。当固件发现长度为零的表时,它知道它已经达到数据的末尾,并且没有更多的表要处理。我发现这种格式很灵活(我可以将任何类型的数据添加到表格主体中)和健壮的(保持头部格式不变,数据表格将兼容前向和后向)。

有几个注意事项,尽管它们不是太繁重。首先,您需要确保您的固件可以处理重要数据不在表格中或正在使用不受支持的格式版本的情况。您还需要将EEPROM存储区的第一个字节初始化为零(以便在第一次启动时,您不会开始加载垃圾,认为它是数据)。由于每个表格都知道它的长度,所以可以扩大或缩小表格;但是,为了确保没有“漏洞”(如果整个表链不适合您设备的内存,那么这个过程可能很烦人),您必须移动表格存储区的其余部分。就我个人而言,我并没有发现任何这些问题是很大的问题,而且使用其他一些数据存储方法可以省去很多麻烦。

+0

这听起来像是一个很好的解决方案来处理固件版本之间表格大小的变化。除了复制数据之外,您是否有任何建议让它能够容忍中间写入功耗? – 2010-08-23 22:45:44

+2

用无效校验和写整个表,然后(在单独的事务中)返回并写入正确的校验和。如果在写入过程中出现问题,读取数据时校验和就会出错。 – bta 2010-08-24 18:23:59

+0

这是一个优雅的解决方案,实现起来微不足道:谢谢你的跟进。 – 2010-08-24 22:27:07

3

奈杰尔琼斯已经介绍了一些在您的参考基础知识。有很多选择。

一个替代方案,你有很多空间,存储键值对而不是结构。然后,您可以更新一个值(通过附加它)而不擦除所有内容。这在擦除周期数量有限的设备中非常有用。您的读取例程将需要从头开始扫描,每次遇到密钥时更新值。当然,你的更新例程需要有一个“垃圾回收器”,当内存已满时启动。

要处理更新过程中的设备错误和电源故障,我们通常会存储多份数据。最简单的方法是使用序列号在设备的两半之间ping通以确定哪一个更新。每个部分的CRC都用于验证它。这也解决了未初始化的数据问题。

对于键值版本,您需要在每次写入后追加新的CRC。

+0

我真的很喜欢这种方法的理论上的声音,但不幸的是,没有足够的EEPROM来使其可行:ATmega328p上只有1 kB。感谢您的描述! – 2010-08-23 22:46:32