代码之家  ›  专栏  ›  技术社区  ›  Michael Koval

安全存储和访问EEPROM

  •  9
  • Michael Koval  · 技术社区  · 14 年前

    我最近确定需要在微控制器的EEPROM中存储不经常更新的配置变量。将状态添加到程序中会立即让人担心

    大量的谷歌搜索只找到了一篇 keeping your EEPROM data valid through firmware updates . 有人用过那篇文章中讨论的方法吗?有更好的替代方法吗?

    2 回复  |  直到 14 年前
        1
  •  8
  •   bta    14 年前

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

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

    下面是其中一张表的示例:

    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、version或checksum没有签出,则跳过该表。长度字段用于定位链中的下一个表。当固件看到一个长度为零的表时,它知道它已经到达了数据的末尾,并且没有更多的表要处理。

    我发现这种格式灵活(我可以将任何类型的数据添加到表体中)而且健壮(保持头格式不变,数据表将同时向前和向后兼容)。

    有几个注意事项,尽管它们不太麻烦。首先,您需要确保固件能够处理重要数据不在表中或使用不受支持的格式版本的情况。您还需要将EEPROM存储区的第一个字节初始化为零(这样,在第一次引导时,您就不会认为它是数据而开始在垃圾中加载)。因为每个表都知道它的长度,所以可以扩展或收缩一个表;但是,您必须移动表存储区域的其余部分,以确保没有“洞”(如果整个表链无法放入设备内存,那么这个过程可能会很烦人)。就我个人而言,我不觉得这些都是一个大问题,这是值得的麻烦,我节省了一些其他方法的数据存储。

        2
  •  3
  •   Doug Currie    14 年前

    奈杰尔·琼斯在你的参考资料中介绍了一些基本知识。有很多选择。

    另一种方法是存储键值对,而不是存储结构。然后您可以更新一个值(通过附加它),而不必删除所有内容。这在擦除周期数有限的设备中最有用。读取例程需要从头开始扫描,每次遇到键时更新值。当然,您的更新例程需要有一个“垃圾收集器”,在内存满时启动。

    为了在更新过程中处理设备错误和断电,我们通常存储多个数据副本。最简单的方法是使用序列号在两到两个设备之间进行乒乓球,以确定哪个较新。每个部分上的CRC用于验证它。这也解决了未初始化的数据问题。