利用MAXQ处理器中的非易失性存储器服务

描述

需要非易失性数据存储的应用几乎总是使用外部串行EEPROM。本文介绍如何仅使用MAXQ微控制器中已有的闪存来提供非易失性数据存储。

介绍

大多数需要微控制器的应用还需要一些机制来存储设置,即使断电也会被记住。例如,在更换电池时忘记其电台预设的收音机在当今的市场上不会成功。客户希望将喜爱的电台、温度预设、首选项和其他持久性信息从一次使用保存到下一次使用。

为了满足客户对非易失性数据存储的期望,设计人员传统上使用串行EEPROM。这些EEPROM器件体积小,价格低廉,历史悠久,使设计工程师能够放心使用。但在当今对成本敏感的市场中,即使是在设计中添加廉价的EEPROM器件也会超出预算。

许多处理器使用闪存来存储程序代码,并使用静态RAM来存储数据。虽然利用闪存的未使用部分进行非易失性数据存储可能很有吸引力,但传统的哈佛架构排除了这种用途。但MAXQ架构是一台具有独立代码和数据路径的哈佛机器。MAXQ器件包含实现伪冯诺依曼架构的硬件,允许方便地访问代码空间作为数据存储器。这种额外的多功能性,结合MAXQ提供存储器写和擦除服务的实用功能,为完整的读写、非易失性存储器子系统提供了背景。

有关闪存的基本注意事项

闪存是一种电可擦除存储器。它通常被认为是“大部分阅读”。简单来说,虽然闪存是可写的,但它的使用假设数据更新将不频繁,并且大部分操作将是读取操作。大多数闪存设备在字级别是可写的,但一次只能擦除整个块。这使得这些存储设备通常不适合可变存储,并且仅适用于永不改变的常量数据表。

闪存有两种:NAND闪存和NOR闪存。NAND闪存用于存储卡和闪存驱动器。通常,从NAND设备读取数据需要几个周期,因为数据是串行从设备中输出的。这种顺序操作使NAND闪存不适合存储程序代码,因为访问时间太长。相比之下,NOR闪存类似于传统的字节或字范围内存。NOR闪存可以像读取ROM器件一样读取:断言器件选择和地址,并在从总线读取数据之前等待访问时间。 NOR闪存用于MAXQ处理器系列。

MAXQ处理器中的闪存

MAXQ处理器中使用的闪存块擦除为“1”状态。因此,擦除后,块中的每个位置都将包含0xFFFF。对闪存位置进行编程会将一些位从“1”状态更改为“0”状态。要将编程位返回到“1”状态,必须擦除整个块。

任何电动可擦除存储设备都必须面对的问题是耐用性。根据具体技术的不同,闪存单元在永久失效之前可以承受低至 1,000 次或多达 1,000,000 次擦除程序周期。因此,任何使用闪存进行数据存储的方案都必须确保写入周期在阵列中均匀分布,并且没有一组位置比另一组位置更频繁地被擦除和编程。

大多数闪存设备将允许先前编程位置中的任何未编程位从“1”更改为“0”状态。例如,大多数设备允许使用值0xFFFE编程的位置随后使用值0x7FFE进行编程,因为这不会将任何位值从“0”更改为“1”。然而,MAXQ系列器件中使用的闪存不允许对先前编程的位置进行重新编程,即使没有尝试将“0”位改回“1”。此类写入尝试将失败,使值保持在 0xFFFE。

在MAXQ器件中存在这种编程限制是有充分理由的。正在编程的内存块主要用作代码空间,因此谨慎的做法是禁止对先前写入的位置进行任何写入操作。由于指令0xFFFF指定了无效的源子解码,因此它不太可能出现在有效的代码块中。因此,阻止写入先前编程的位置有助于保持代码块的完整性。

使用MAXQ2000的设计方案

本文重点介绍MAXQ器件:MAXQ2000。该微控制器具有 64kB 的程序存储,由 128 个块组成,每个块 256 个 16 位字。下面介绍两种设计方案。第一种方案适用于只写入一次,然后在产品生命周期内不经常更改的信息,例如校准数据、版本信息和功能字符串。第二种方案是一种更通用的机制,旨在容纳更频繁更改的数据,例如使用信息或详细记录。

方案 1

问题:校准数据需要存储在产品中。有时,产品需要重新校准,因此校准数据必须存储在可重写存储器中。

解决方案:这实际上是可以想象的最简单的情况。MAXQ2000程序闪存阵列中的两个模块保留用于校准数据存储,一个位于字地址0x7E00,另一个位于0x7F00。第一次收到保存校准数据的命令时,MAXQ2000检查两个模块,发现它们都是空白的。校准数据将保存到第一个模块中。

在保存校准数据的第二个命令中,MAXQ2000再次检查两个模块。当它发现块 0 正在使用时,它会将校准数据复制到块 1,然后擦除块 0。

当收到读取校准数据的请求时(例如上电时),MAXQ2000读取两个模块以确定哪个模块正在使用。无论哪个块未擦除,都用于将设备配置为其校准状态。

该方案的主要优点是简单。如果应用程序需要在上电(或其他配置还原事件)进行块配置,则此方法非常有效。read 例程接受单词指针并返回该地址处的值;写入例程接受字指针,并尝试在该地址处执行写入周期。擦除例程只是擦除两个块。

这种方案有一个缺点:例程非常简单。不会尝试确定写入是否会成功。尝试写入,如果写入失败,则不执行任何操作来尝试解决问题。这种限制就是该方案仅用于写入已知空白块的原因。

方案 2

问题:需要非易失性存储来跟踪能源使用情况和其他频繁变化的数据。更新从每周几次到每天几次不等。电表是挑战的一个很好的例子。

解决方案:在这种情况下,即使是传统的EEPROM也需要帮助。问题在于:频繁的更新以及所有电可擦除存储器技术都具有有限的写入寿命这一事实,因此无法一遍又一遍地写入和擦除单个EEPROM单元。考虑每小时更新的情况。具有 10,000 次写入擦除周期限制的 EEPROM 将在短短一年多内耗尽,远低于为电表制定的十年设计目标。

这个问题的解决方案是实现某种形式的“磨损均衡”。这种方法意味着不会一遍又一遍地写入单个位置。相反,写入周期分布在整个内存阵列上,适当的索引分布类似。

磨损均衡是一种众所周知的技术,仅用于此目的的闪存设备。算法可能很复杂且难以理解。但就我们的目的而言,一个更简单的机制就足够了。

在此实现中,存储数组中的数据项不是按地址引用,而是按数据元素编号引用。数据元素编号是唯一标识数据元素的任意 8 位值。因此,在此方案中最多可以有 255 个数据元素(保留数据元素 0)。每个数据元素都有:一个包含数据元素编号和数据元素长度的双字节标头(参见图 1);指示一个、两个、三个或四个 2 位字的 16 位代码,如果需要,还有足够的空间用于错误管理。

存储器


图1.数据元素标头的结构。

若要写入数据元素,写入子例程必须知道要写入的数据、数据元素的长度以及要写入数据的位置。确定数据将写入的地址很简单;数据元素(无论是新元素还是对现有元素的更新)都写入存储阵列的末尾。write 函数查找数组的末尾,然后紧跟在最后一条记录之后写入新的数据元素。如果 Flash 页面中没有足够的空间来包含指定长度的记录,则会写入页末标记并打开一个新页面。有关典型数据页的结构,请参见图 2

在此数据页中,数据元素 1 是首先写入的,并且经常更新。接下来编写了数据元素 4,并且从未更新过。然后写入数据元素 3,并已更新七次。最后,数据元素 2 已写入且从未更新。

页结束标记的存在表示进行了数据写入尝试,但数据元素太长,无法容纳在页面上。将打开一个新页面以容纳数据元素。整个数据结构的末尾由一个空白元素指定,其中的元素标头应位于该空白元素的位置。

存储器

数字2. 典型的数据页面。

请注意,此方案尚未解决重复记录的问题。这是因为重复记录不是问题。事实上,读取和写入例程完全忽略了重复记录。写入时,新记录位于数组的末尾,无论是否已存在相同编号的记录。读取时,仅检索与请求的记录编号匹配的最后一条(因此也是最新的)记录。

从数组中读取数据元素比写入更复杂。read 函数接受数据元素内容应写入的元素编号和地址。调用时,read 函数从头开始搜索数组。当它找到与请求的数据元素匹配的记录时,它会存储地址并继续搜索。如果找到另一个匹配的记录,则读取函数会将存储的地址替换为新地址。当到达数组的末尾时,存储的地址将指向所请求记录的最新写入副本。然后,read 函数将此数据复制到调用函数时传递的缓冲区。

尽管已经提出了一种可行的只读机制来存储和检索存储阵列中的记录,但仍然存在一个问题:没有重用过时记录副本占用的空间的机制。(也没有删除记录的机制,但由于此方案的结构是在嵌入式应用程序中工作的,因此这可能不是一个关键功能。如果不恢复一些空间,分配的空间将很快耗尽。然而,恢复空间意味着擦除整个页面,因为闪存一次只能擦除一整页。这个问题更加复杂,因为Flash页面不能被任意删除而不会删除有用信息的风险。唯一的选择是在擦除旧页面之前将活动信息复制到新页面。

从过时的记录中恢复空间的过程分为三个阶段。首先,打开新的 Flash 页面,并将每个数据元素的最新版本复制到新页面中。其次,旧页面被擦除。最后,将页面标记放置在新页面上,以便读取例程可以找到它们。

第一阶段有些复杂,需要更详细地检查。执行此步骤的一种简单方法是将其分为两个子步骤:首先,使用 RAM 数组存储数组中最新记录的记录编号和地址;其次,逐步执行 RAM 阵列,将最新记录复制到新的闪存页面。这个过程将是快速且相对简单的。

这种双子步方案的问题在于MAXQ2000具有1k字的RAM。上述方案将可存储的唯一数据量限制为缓冲区可以保留的 RAM 大小。这显然是不可接受的。

解决这一难题非常耗时,但无论存储阵列变得多大(在合理范围内)都有效。与其在 RAM 中构建指针列表,不如为每个唯一条目通过源数组进行多次传递。因此,压缩算法变为:

从源数组中读取元素。

在目标数组中搜索元素。如果找到,则该元素已被写入。递增源指针并返回到 1。

扫描源数组以查找元素的最新副本。

将数据元素的最新副本写入目标数组。

递增源指针并返回到 1。

最后,目标数组中的每个唯一数据元素只有一个条目。

图 3

给出了打包页面的图示。现在可以安全地擦除源页面,并将页眉写入目标数组。

存储器


图3.空间恢复后,图 2 的数据页将如下所示。

此过程的结构对于存储的数据尽可能安全。但是,在使用闪存设备时必须面对一个危险:写入或擦除操作期间的电源故障。如果电源出现故障,则一个或多个页面可能会损坏(在写入的情况下)或未完全擦除(在擦除操作的情况下)。但紧凑的操作本质上是安全的。请考虑以下方案:

如果在打包操作期间发生电源故障,源页将保持完全完整。电源恢复后,可以轻松识别新写入的页面(它们没有页面标题)并擦除,并重新启动包操作。

如果在擦除旧页面时发生电源故障,则它们可能包含无效的标题。可以擦除这些页面,并将标题添加到新页面。

如果在将页眉写入新页时发生电源故障,则数据保持不变。可以重新启动页眉更新操作。

简而言之,不应存在任何机制,通过这种机制,意外事件可以不可挽回地损坏阵列数据。

方案 2 增强功能

此处介绍的存储子系统没有错误检测机制。数据元素标识符中存在未提交的可用位(如所示的六个位)。可以使用CRC6算法(x6+ x + 1) 计算跨数据元素的 CRC,以确保没有发生读取或写入错误。虽然这不是一个特别健壮的算法(它会错过 64 个多位错误中的一个),但它会检测可能发生的大多数实际错误。

系统的另一个限制是读取访问时间必然很长。对于每次读取,都必须读取数组中的每条记录才能找到最新的记录。有三种方法可以缩短访问时间:

在数据元素中为前向指针留一个空白字。更新值时,填写指向新条目的转发指针。这样,可以将表作为链表遍历。

向后遍历表。现在只需在请求元素第一次出现时停止。

如果只有少量唯一元素,请在启动时创建一个包含元素 ID 和指针的 RAM 数组。后续访问非常快。只需读取 RAM 数组即可确定从何处获取数据元素。

结论

非易失性数据存储是每个设计工程师迟早必须面对的一个因素。有了MAXQ处理器灵活的闪存,再也没有理由求助于小型串行存储器来存储配置数据。

审核编辑:郭婷

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分