本应用笔记介绍如何使用内置实用程序ROM擦除/写入MAXQ7665微控制器(μC)中的程序和数据闪存。此信息仅适用于带扇形可擦除(SE)闪存的基于MAXQ7665闪存的微控制器(μC)。
介绍
本应用笔记介绍如何管理带有扇形可擦除(SE)闪存的MAXQ7665闪存微控制器(μC)中的内部数据和程序闪存。此讨论包括有关执行程序闪存的应用程序内编程 (IAP) 的一般信息。
内存映射
本节详细介绍MAXQ7665器件各种存储器大小的一般闪存信息和存储器组织。MAX7665器件提供两种类型的闪存。本文档仅介绍带SE闪存的MAXQ7665器件,不适用于寻页(PE)器件。有关MAXQ7665 PE器件的信息,请参考应用笔记“MAXQ7665页面可擦除(PE)程序和数据闪存的应用内编程(IAP)”。
表 1 显示了 128KB、64KB、48KB 和 32KB 设备的闪存映射。可能存在其它闪存选项,因此请参考MAXQ7665数据资料以获取完整列表。
表 1.闪存映射
使用闪存存储数据
闪存可用于可靠地存储系统数据,这些数据需要在系统运行期间进行一次或定期编程。虽然闪存的任何扇区都可用于存储数据,但两个4K x 16扇区通常提供最佳选择。与EEPROM不同,MAXQ7665上的闪存不能被文字擦除。必须一次擦除完整的扇区。擦除扇区通常需要 0.7 秒,但在最坏的情况下可能需要长达 15 秒的时间。在此期间,用户代码将停止,因此不会发生其他处理。在选择适合系统要求的软件技术时,必须仔细考虑这些限制。对于大多数周期性数据存储需求,有界队列和/或银行交换技术将满足系统的可靠性要求和需求。下面是这两种技术的简单示例。
有界队列
有界队列是受固定数量的项目限制的队列。每当处理定期数据时,通常使用此技术。例如,4K x 16闪存扇区可以分为64个64字条目,这将导致表2中128kB部分的内存映射。
初始化后,启动例程可以扫描队列条目以确定队列中的下一个可用条目。队列已满后,必须先擦除该队列,然后才能写入另一个条目。(注意:如果需要所有条目,则还必须使用库切换来维护所有数据。擦除闪存后,可以写入新条目。这种方法的缺点是,如果在擦除过程中功率下降,则所有数据都可能丢失。如果有界队列技术不符合系统的要求,则还需要进行银行切换。
图 1 说明了进入有界队列的条目流。
有关简单的 C 源代码示例,请参阅附录 A。
表 2.有界队列内存映射示例
FLASHQueue[ ] | |
Queue Index | Data Flash Address |
63 | 0xFFC0-0xFFFF |
62 | 0xFF80-0xFFBF |
61 | 0xFF40-0xFF7F |
. . . . | . . . . |
2 | 0xF080-0xF0BF |
1 | 0xF040-0xF07F |
0 | 0xF000-0xF03F |
图1.有界队列流。
银行切换
组交换是在长扇区擦除周期中防止数据丢失或损坏的有效方法。当扇区大小仅略大于总数据大小时,此方法非常有效。组切换的缺点是它至少需要两个闪存扇区。当要写入的总数据大小远小于扇区大小时,最佳方法将库交换和有界队列技术结合起来。如果应用需要组切换,MAXQ4的两个16K x 7665闪存扇区可以用作数据存储。
表3是使用两个4K x 16闪存扇区时的内存映射示例。图 2 显示了组交换写入/擦除流程。
有关简单的 C 源代码示例,请参阅附录 A。
表 3.组切换存储器映射示例
闪存扇区 | |
扇区编号 | 数据闪存地址 |
0 | 0xF000-0xFFFF |
1 | 0xE000-0xEFFF |
图2.银行切换流程。
有界队列和银行交换
同时使用有界队列和银行交换技术是最可靠和灵活的方法。当需要存储少量数据以定期刷新时,以及必须保持数据完整性时,这种组合方法非常有效。表 4 显示了使用划分为 4 个相等条目的两个 16K x 64 扇区的内存映射示例。图 3 说明了两个扇区之间有界队列中的数据流。
这种组合技术的编码仅比单独的有界队列稍微复杂一些。有关简单的 C 源代码示例,请参阅附录 A。
表 4.有界队列内存映射示例
FQueueBank0[ ] | |
Queue Index | Data Flash Address |
63 | 0xFFC0-0xFFFF |
62 | 0xFF80-0xFFBF |
61 | 0xFF40-0xFF7F |
. . . . | . . . . |
2 | 0xF080-0xF0BF |
1 | 0xF040-0xF07F |
0 | 0xF000-0xF03F |
FQueueBank1[ ] | |
Queue Index | Data Flash Address |
63 | 0xEFC0-0xEFFF |
62 | 0xEF80-0xEFBF |
61 | 0xEF40-0xEF7F |
. . . . | . . . . |
2 | 0xE080-0xE0BF |
1 | 0xE040-0xE07F |
0 | 0xE000-0xE03F |
图3.有界队列和银行切换的流程图。
实用程序 ROM 闪存例程
为了编程、擦除和验证闪存,MAXQ7665微控制器在ROM (只读存储器)中提供了片内闪存支持例程。有两种方法可以访问这些例程。第一种也是最快的方法是直接访问,即直接调用例程。为此,请提供包含以下行的头文件:
u16 flashEraseSector(void *); u16 flashEraseAll(void); u16 flashWrite(void *pAddress, u16 iData);
接下来,添加链接器定义以为每个例程分配适当的地址。对于 IAR 链接器文件,添加的行如下所示:
-DflashEraseSector=0x8XXX -DflashEraseAll=0x8XXX -DflashWrite=0x8XXX
将 0x8XXX 替换为每个例程的相应内存地址。其他编译器可能会使用不同的方法来添加这些引用。
注意:直接访问方法不提供与未来 ROM 版本的向前兼容性。
间接寻址的第二种方法使用表查找。虽然此方法提供了与未来ROM版本更好的兼容性,但它消耗了更多的执行时间。在下面描述的每个例程之后,程序集例程使用表查找方法来获取 ROM 实用程序例程的地址。表 5 显示了实用程序 ROM 提供的闪存例程。有关ROM实用程序的完整列表,请参考MAXQ7665用户指南,该指南可在Maxim网站上找到。
表 5.闪存实用程序 ROM 例程
例程编号 | 例程名称 | 入口点可 ROMTable = ROM[800Dh] | 入口点物理地址 |
2 | 闪存擦除扇区 | 罗姆[可浪漫 + 1] | 0x8XXX |
3 | 闪光擦除全部 | 罗姆[可浪漫 + 2] | 0x8XXX |
15 | 闪写 | 罗姆[可浪漫 + 14] | 0x8XXX |
闪写
常规: | u16 flashWrite(void *pAddress, u16 iData) |
总结: | 对单个字的闪存进行编程。 |
输入: |
A[0] - 闪存中要写入的字地址。 A[1] - 要写入闪存的字值。 |
输出: |
携带:错误时设置,成功时清除。如果设置,则 A[0] 包含以下错误代码之一: 1:由于软件超时而导致的故障 2:硬件 (DQ5/FERR) 报告故障 4: 不支持 命令 SW_FERR - 出错时设置,成功时清除。 |
笔记: | 监视器不得处于活动状态,或者监视器超时必须设置足够长的时间才能在不触发重置的情况下完成此例程。 |
下面的汇编代码示例使用间接寻址方法(查找表)调用 flashWrite() 实用例程。此例程可由 C 代码调用。
; This routine is callable by C code using the following prototype ; u16 flashWrite(void *pAddress, u16 iData); ; flashWrite: move APC, #0 ; No auto inc/dec of accumulator. move DP[0], #0800Dh ; This is where the address of the table is ; stored. move ACC, @DP[0] ; Get the location of the routine table. add #14 ; Add the index to the flashWrite routine. move DP[0], ACC move ACC, @DP[0] ; Retrieve the address of the routine. call ACC ; Execute the routine. ret ; Status returned in A[0].
常规: | u16 闪存擦除扇区(无效 *pAddress) |
总结: | 擦除闪存的单个扇区。 |
输入: | A[0] - 位于要擦除的扇区中的地址。 |
输出: |
携带:错误时设置,成功时清除。如果设置,则 A[0] 包含以下错误代码之一: 1:由于软件超时而导致的故障 2:硬件 (DQ5/FERR) 报告故障 4: 不支持 命令 SW_FERR - 出错时设置,成功时清除。 |
笔记: | |
监视器不得处于活动状态,或者监视器超时必须设置足够长的时间才能在不触发重置的情况下完成此例程。 |
; This routine is callable by C code using the following prototype ; u16 flashEraseSector(void *pAddress); ; flashEraseSector: move APC, #0 ; No auto inc/dec of accumulator. move DP[0], #0800Dh ; This is where the address of the table is ; stored. move ACC, @DP[0] ; Get the location of the routine table. add #1 ; Add the index to the flashEraseSector routine. move DP[0], ACC move ACC, @DP[0] ; Retrieve the address of the routine. call ACC ; Execute the routine. ret ; Status returned in A[0]
常规: | 虚空闪光擦除全部(虚空) |
总结: | 擦除整个程序和数据闪存,包括引导加载程序扇区。此例程通常不用于 IAP,因为必须非常小心以确保擦除/编程序列不会中断。 |
输入: | 没有 |
输出: |
携带:错误时设置,成功时清除。 SW_FERR - 出错时设置,成功时清除。 |
笔记: | 监视器不得处于活动状态,或者监视器超时必须设置足够长的时间才能在不触发重置的情况下完成此例程。 |
; This routine is callable by C code using the following prototype ; void flashEraseAll(void); ; flashEraseAll: move APC, #0 ; No auto inc/dec of accumulator. move DP[0], #0800Dh ; This is where the address of the table is ; stored. move ACC, @DP[0] ; Get the location of the routine table. add #2 ; Add the index to the flashEraseAll routine. move DP[0], ACC move ACC, @DP[0] ; Retrieve the address of the routine. call ACC ; Execute the routine. ret
应用程序内编程 (IAP)
大多数基于闪存的系统必须能够在系统安装在最终产品中时更新固件。此过程称为应用程序内编程 (IAP)。以下讨论概述了创建 IAP 应用程序的一般准则。
上一节中概述的实用程序 ROM 闪存例程执行擦除和写入闪存 ROM 所需的所有操作。因此,最终用户应用程序可以在闪存上执行操作。与任何其他子例程调用一样,控件将在例程完成后返回到最终用户的代码。
在MAXQ7665的仅扇区擦除版本上执行IAP序列时必须小心,因为不存在专用的引导加载程序闪存扇区。要设计完全容错的 IAP,引导加载程序应用程序必须与主应用程序分开。这确保了即使在发生不完整的重编程序列后,也可以重试重编程过程。如果IAP必须容忍重编程过程中的断电等故障,则选择具有页面擦除功能的MAXQ7665版本。这将允许引导加载程序应用程序从0x0000(重置入口点)启动,并与主应用程序代码完全分开。对于不需要完全容错 IAP 的应用程序,可以使用基于 RAM 的重新刷新例程来完成 IAP。
使用基于 RAM 的闪存例程的 IAP
当不需要故障恢复时,可以使用基于RAM的闪存例程重新刷新MAXQ7665。此方法要求主应用程序将一个小的可重定位闪存编程例程复制到 RAM 中,然后跳转到该例程。从 RAM 执行代码时,必须考虑几个限制。
通常,闪存例程将通过UART或CAN接口进行通信。通常最好接收小数据包并发送确认,以允许更强大的错误恢复机制。图 4 是一个流程图,显示了重新刷新例程的工作原理。如果在断电前未成功完成重新编程,请记住,微控制器需要通过JTAG端口重新编程。
图4.简化的 RAM 重新刷新例程的流程图。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !