您当前的位置:五五电子网电子知识单片机-工控设备DSP/FPGA技术利用基于闪存的MCU实现用户数据存储 正文
利用基于闪存的MCU实现用户数据存储

利用基于闪存的MCU实现用户数据存储

点击数:7267 次   录入时间:03-04 11:48:07   整理:http://www.55dianzi.com   DSP/FPGA技术

  采用微控制器的大多数设备还需要某种机制来存储在断电时仍要被记住的那些设置数据。例如,在更换电池后记不住预设电台的收音机肯定不会在市场上取得很大的成功。用户希望喜爱的电台、预设温度、参数选择和其他永久性信息能长久保存下来供每次开机时直接取用。

  为了满足这种用户需求,设计师一般使用串行EEPROM。这些器件又小又便宜,具有很长的历史,设计工程师用起来得心应手。但在今天对成本极其敏感的市场下,即使这样一个廉价的器件也可能突破成本预算。因此许多设计师试图寻求并利用已经包含在微控制器芯片中的资源:程序 闪存 中剩余的空间。

  过去,许多微控制器使用ROM或可紫外线擦除的EPROM来存储程序指令。但现在越来越多的微控制器转用闪存技术存储代码。选择闪存的主要理由是,如果在程序代码中发现错误,闪存数据很容易被擦除和更新。

  大多数微控制器具有读取程序空间中存储数据的机制。基于冯·诺伊曼架构的处理器,如TI MSP430,可以使用任何寻址模式读取程序闪存。哈佛架构处理器一般利用特殊的机制将数据从程序空间传送到数据空间。具有闪存管理功能的其他 MCU 包括:

  1. 包含MOVEC(移动常数)指令的非常流行的8051处理器系列;

  2. 包含TBLRD和TBLWR(表读和表写)指令的MICroChip PIC18系列;

  3. 具有伪冯·诺伊曼架构的美信MAXQ微控制器系列,它们允许通过简单的MOVE指令访问闪存程序存储空间(见图1)。

在像美信MAXQ2000这样的伪冯

图1:在像美信MAXQ2000这样的伪冯·诺伊曼MCU中采用的数据交换允许任何存储器块被用作代码或 数据存储 器。

  但即使能够从随机闪存位置读取数据,完整的非易失性存储器子系统也必须能够随机修改闪存中的数据。这意味着需要解决两个问题:首先,一旦某个闪存位置被写入,那个位置的数据只能通过擦除整个闪存块(通常128字节或以上)进行修改;其次,闪存的读写次数非常有限。

  本文将介绍如何构建一个能够解决这些问题、并使用闪存块模拟随机写入的机制。虽然本文的用例是MAX2000,但原理适用于支持读写和擦除闪存的用户代码的任何处理器。本文讨论的方案已经被用于采用MAXQ3180三相模拟前端和MAXQ2000的三相电表参考设计。

  闪存管理的基本知识

  闪存是一种电可擦除的存储器,通常主要用于读操作,也就是说,虽然是可写的,但它不希望很频繁地更新数据,因此对这种存储器的操作大部分是读操作。大多数闪存器件是以字(word)为单位写入数据的,但一次只能擦除整个块。这使得它们不适用于频繁变化的存储应用,只适合存储那些永远不变的常数表。

  一共有两种闪存:NAND闪存和NOR闪存。NAND闪存经常用于存储卡和闪盘。一般来说,从NAND器件读取数据需要几个周期,并且大部分是用串行方式完成的。

  因此NAND闪存不适于存储程序代码,因为存取时间太长。而NOR闪存更像是传统的字节或字宽的存储器。可以像读ROM器件那样读NOR闪存中的数据:使片选和地址线有效,然后等待一段访问时间后从总线上读取数据。

  闪存块通常被擦除到“1”状态,因此经过擦除后,块中的每个位置都是0xFFFF。“编程”一个闪存位置是把某些位从“1”状态改变为“0”状态。为了使编程过的位返回到“1”状态,整个块必须被擦除。

  任何电可擦除的存储器件都面临寿命的问题。根据所用技术的不同,一个闪存单元在永久失效以前可以承受的擦除-编程次数少则1000次,多则100万次。使用闪存存储数据的任何方案都必须确保写入次数在整个单元阵列上获得均匀分布,没有一个位置会出现太多的擦除和编程次数。

  大多数闪存器件都允许将前次编程中那些未被编程的位从“1”改为“0”状态。例如,大多数器件允许用0xFFFE编程过的那个位置再用0x7FFE进行编程,因为这种操作不会将任何位从“0”改变到“1”。然而如图1所示的处理器架构中使用的闪存不允许这样做。这种写入操作的结果是失败,内存中的数据仍然是0xFFFE。

  理由很简单:因为要被编程的存储块主要用作代码空间,通常禁止对前面写过的位置作任何写操作。因为指令0xFFFF代表的是无效的源子译码(source sub-decode),不可能出现在有效的代码块中。这样,阻止向以前编过程的位置写入数据有助于保持代码块的完整性。

  提供非易失性存储器服务

  以下是提供非易失性存储器服务的两种方案。第一种方案侧重于简单性,第二种方案比较灵活,但代价是较复杂。



www.55dianzi.com

  方案1

  问题:校准信息、MAC地址或制造数据等配置数据必须要存储在产品中。虽然这些通常是固定不变的信息,但在整个产品生命周期内配置数据需要多次更新的可能性还是存在的。

  解决方案:下面是实际中最容易想到的例子。有两个块,一个块在字地址0x7E00处,另一个在0x7F00处,都用于 数据存储 。在第一次收到保存配置数据的命令时,处理器会检查这两个块,在发现它们都是空块后,配置数据被就存入第一个块。

  保存配置数据的第二条命令同样会使处理器再一次检查这两个块。当发现块0已经有数据后,它就将配置数据拷贝到块1,然后擦除块0中的数据。

  当收到恢复配置的请求时(比如在上电时),处理器会同时读取两个块的数据并确定哪个块在用。只要是没被擦除的块就是在用块。

  这种方案的主要优点是简单:如果设备在上电(或其他配置恢复事件)时需要块中的配置数据,这是很好的一种方案。读数程序会接受一个字长的指针,返回该地址的数值,写入程序则接受一个字长的指针,然后尝试向该地址进行写入操作。擦除程序只是同时擦除两个块。

  这种方案的主要缺点就是主要优点的反面:程序的思路太过简单。没有操作去判断写入数据是否成功—在发出写入命令后,如果写入失败,处理器不会做任何事去解决问题。这也是为什么这个方案只是用来写入已知是空的 闪存 块的原因。

  方案2

  问题:要求用非易失性存储技术来跟踪用电量和其他经常变化的数据。更新经常是一周数次或一天数次发生。

  解决方案:这是即使传统EEPROM也需要寻求帮助的场合。问题是:更新的频率和所有非易失性存储器有限的写入寿命这样的事实不允许反复写入和擦除单个EEPROM单元。考虑一个小时更新一次的情况,具有1万次写入-擦除次数限制的EEPROM只需一年时间就会失效,这个时间比电表所需的十年设计目标少得太多了。

  解决这个问题的方法之一是实现某种形式的“损耗均衡”。这意味着不会有单个位置被反复写数据。相反,写入操作将呈类似合理指数分布的方式分散到整个存储器阵列。

  损耗均衡是一种很好理解的技术,在闪存器件中使用就是出于这个目的。但它的算法非常复杂和难以理解,不过对我们来说,一个更简单的原理介绍就足够了。

  存储阵列中的数据项是由数据单元(data element)号引用的,而不是地址。

  数据单元号是一个唯一识别数据单元的任意8位数,因此在这种方案中,最多有255个数据单元(数据单元0是保留单元)。

  每个数据单元有一个双字节的头部(见图2),包含了数据单元号和数据单元长度以及留给差错管理使用的足够空间,其中长度是一个两位代码,可表示1个、2个、3个或4个16位的字。

数据单元的头部结构

图2:数据单元的头部结构

  写一个数据单元需要知道写入数据的地址、写入数据的单元号和长度。写函数先寻找阵列结尾,然后紧跟最后一个记录之后写入新的数据单元。

  如果闪存页中没有足够的空间容纳指定长度的记录,一个表示结尾的页标记将被写入,并会打开一个新的页。有关典型数据页的结构请见图3。

典型的数据页

图3:典型的数据页

  在展开的数据页中,先写入经常要更新的数据单元1,再写入从不更新的数据单元4,然后写入需要多次更新的数据单元3。最后,写入从不更新的数据单元2。

  出现页的结尾标记表明过进行过一次数据写入尝试,但由于数据单元太长而无法将数据单元装进该页,因此打开了一个新页来容纳该数据单元。整个数据结构的结尾设定为空白单元,这个位置有望成为单元头部。

  值得注意的是,我还没有说明重复记录的问题。这是因为在这种方案中重复记录不是问题。事实上,读写程序是完全忽略重复记录的。

  在写数据时,新的记录会写在阵列的最后,而不管是否有相同号码的记录存在。在读数据时,只有匹配请求记录号的最后,也就是最近的记录被读出来。

  从阵列中读出一个数据单元要比写入稍微复杂一些。读函数首先接受应被写入数据单元内容的单元号码和地址。当被调用时,读函数从头开始搜索阵列。

[1] [2]  下一页


本文关键字:用户  DSP/FPGA技术单片机-工控设备 - DSP/FPGA技术

《利用基于闪存的MCU实现用户数据存储》相关文章>>>