第13章 Flash存储器
第13章 Flash存储器
Flash存储器具有电可擦除、无需后备电源来保护数据、可在线编程、存储密度高、低功耗、成本较低等特点,这使得Flash存储器在嵌入式系统中的使用迅速增长。
本章主要以HC08系列中的GP32为例阐述Flash存储器的在线编程方法,也简要阐述了HCS08系列中GB60的在线编程方法。本章首先概述了Flash存储器的基本特点,并介绍其编程模式,随后给出M68HC908GP32的Flash存储器编程的基本操作及汇编语言和C语言的在线编程实例。最后讨论MC9S08GB60的Flash存储器编程方法。
Flash存储器编程方法有写入器模式与在线模式两种,本章讨论的是在线模式。有的芯片内部ROM中,包含了Flash擦除与写入子程序,在本章的进一步讨论中给出了调用方法,使Flash编程相对方便。有的芯片内部ROM中没有固化Flash擦除与写入子程序,只能自己编写Flash擦除与写入子程序。而编写Flash擦除与写入子程序需要较严格的规范,所以这是比较细致的工作,读者应仔细
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
本章的例程,并参照例程编程。掌握了GP32芯片的Flash编程方法后,可以把此方法应用于整个系列的Flash编程。Flash在线编程对初学者有一定难度,希望通过实例分析学习。本章给出Flash在线编程的C语言实例,对于训练C语言与汇编联合编程技巧很有帮助。
13.1 Flash存储器概述与编程模式
理想的存储器应该具备存取速度快、不易失、存储密度高(单位体积存储容量大)、价格低等特点,但一般的存储器只具有这些特点中的一个或几个。近几年Flash存储器(有的译为:闪速存储器或快擦型存储器)技术趋于成熟,它结合了OTP存储器的成本优势和EEPROM的可再编程性能,是目前比较理想的存储器。Flash存储器具有电可擦除、无需后备电源来保护数据、可在线编程、存储密度高、低功耗、成本较低等特点。这些特点使得Flash存储器在嵌入式系统中获得广泛使用。从软件角度来看,Flash和EEPROM技术十分相似,主要的差别是Flash存储器一次只能擦除一个扇区,而不是EEPROM存储器的1个字节1个字节地擦除,典型的扇区大小是128B~16KB。尽管如此,因为Flash存储器的总体性价比,它还是比EEPROM更加流行,并且迅速取代了很多ROM器件。
嵌入式系统中使用Flash存储器有两种形式:一种是嵌入式处理器上集成了Flash,另一种是片外扩展Flash。
目前,许多MCU内部都集成了Flash存储器。Freescale公司在Flash存储器技术相当成熟的时候,在HC08系列单片机内集成了Flash存储器。该系列内部的Flash存储器不但可用编程器对其编程,而且可以由内部程序在线写入(编程),给嵌入式系统
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
与编程提供了方便。存储器是MCU的重要组成部分,存储器技术的发展对MCU的发展起到了极大的推动作用。对于Freescale公司新推出的HCS08系列MCU采用第三代0.25微米的闪存技术,其擦写速度更快,性能更稳定。
本节首先简要概述Flash存储器普遍具有的基本特点、Flash存储器的两种编程模式,然后介绍Freescale的HC08系列单片机内的Flash存储器的主要特点,最后对M68HC908GP32单片机的Flash存储器在两种编程模式下的基本情况作简要介绍。
13.1.1 Flash存储器的基本特点与编程模式
(1) Flash存储器的基本特点
Flash存储器是一种高密度、真正不挥发的高性能读写存储器,兼有功耗低、可靠性高等优点。与传统的固态存储器相比,Flash存储器的主要特点如下。
①固有不挥发性:这一特点与磁存储器相似,Flash存储器不需要后备电源来保持数据。所以,它具有磁存储器无需电能保持数据的优点。
②易更新性:Flash存储器具有电可擦除特点。相对于EPROM(电可编程只读存储器)的紫外线擦除
工艺
钢结构制作工艺流程车尿素生产工艺流程自动玻璃钢生产工艺2工艺纪律检查制度q345焊接工艺规程
,Flash存储器的电擦除功能为开发者节省了时间,也为最终用户更新存储器
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
提供了可能。
③成本低、密度高、可靠性好:与EEPROM(电可擦除可编程的只读存储器)相比较,Flash存储器的成本更低、密度更高、可靠性更好。
(2) Flash存储器的两种编程模式
从Flash存储器的基本特点可以看出,在单片机中,可以利用Flash存储器固化程序,一般情况下通过编程器来完成,Flash存储器工作于这种情况,叫监控模式(Monitor Mode)或写入器模式,这与一般的EPROM、OTP、EEPROM装入程序的含义相似。另一方面,由于Flash存储器具有电可擦除功能,因此,在程序运行过程中,有可能对Flash存储区的数据或程序进行更新,Flash存储器工作于这种情况,叫用户模式(User Mode)或在线编程模式。但是,并不是所有类型的单片机内Flash存储器都具有在线编程功能,目前,有的公司出品的单片机,还不能够支持Flash存储器在线编程模式。Freescale的HC908系列单片机的片内Flash支持这两种编程模式。一般来说,两种模式对Flash存储器的编程操作的程序是一致的,差别在于调用这些程序的方式和环境。
13.1.2 HC08系列单片机Flash存储器的特点与编程模式
(1) MC908系列单片机Flash存储器的特点
早期的片内Flash技术与ROM或EPROM相比较,其可靠性和稳定性存在一些不足。Freescale公司在Flash存储器技术相当成熟的时候才推出片内带有Flash存储器的8位单片机,在应用方便性和可靠性等方面有自己的特点,主要有:
第一,编程速度快及可靠性高。Freescale HC08系列单片机的片内Flash的整体擦除时间可以控制在5ms以内,对单字节的编程时间也在40ns以内。片内Flash的存储数据可以保持10年以上,可擦写次数也在1万次以上。
第二,单一电源电压供电。一般的Flash存储器,在正常的只读情况下,只需要用户为其提供普通的工作电压即可,而要对其写入(编程),则需要同时提供高于正常工作电压的编程电压。但是,Freescale HC08系列单片机通过在片内集成电荷泵,可由单一工作电压在片内产生出编程电压。这样,可实现单一电源供电的在线编程,不需要为Flash的编程而在目标板上增加多余的硬件模块。正因为Flash的读写电压要求不同,一些公司的内置Flash存储器便放弃了在线擦除写入功能,而仅有通过编程器的写入功能。
第三,支持在线编程。Freescale HC08系列单片机的片内Flash支持在线编程(In-Circuit Program),允许单片机内部运行的程序去改写Flash存储内容,这样可以代替外部电可擦除存储芯片,减少外围部件,增加了嵌入式系统开发的方便性。
基于以上这些特点,掌握Freescale HC08系列单片机的Flash存储器的编程技术,充分利用Freescale HC08系列单片机Flash存储器的功能,对基于Freescale HC08系列单片机的嵌入式系统的开发是十分必要的。但是,与一般程序相比,Flash存储器的编程技术相对比较复杂,有一些特殊之处,本章将在实际应用基础上,总结Freescale的 MC908GP32单片机的Flash编程方法,给出编程实例。
(2) MC908系列单片机Flash存储器的编程模式
MC908系列单片机中绝大多数型号在其内部带有监控ROM(Monitor ROM),其地址和大小取决于芯片型号。Flash存储器工作于监控模式的条件是:
①复位向量($FFFE~$FFFF)内容为“空”($FFFF)。
②单片机复位时在IRQ引脚上加上高电压(1.4~2Vdd),并给某些I/O脚置适当值(与芯片型号有关,设计时,参考芯片手册)。
只要满足上面条件之一,就可以使单片机在复位后进入监控工作方式。前者适用于单片机芯片已经安装在用户PCB板上,可以实现在线编程(ICP)。初始时,芯片为“空”,用户以这种方式装入程序后,以后的复位将执行用户装入的程序,不再进入监控模式。后者一般用于通过编程器进行程序装入。
在监控方式下,单片机内部的监控ROM程序开始工作,首先进行初始化,随后进入串行输入命令状态。监控ROM通过一根I/O口线与主机进行串行通信,该I/O口线的指定与芯片型号有关,例如,对MC908GP32,它为PTA0;对MC68HC908JL3,它为PTB0,该I/O口线在使用时需外接上拉电阻。主机程序可以利用监控ROM提供的少数几条指令对单片机内部地址进行读取、写入等基本操作,包括下载程序到RAM中并执行。在此基础上,主机可以通过主机程序或是下载到RAM中的程序完成对Flash存储器编程所需的一系列操作。
M68HC908系列单片机的Flash存储器工作于用户模式不需要特别的条件,在单片机正常工作的过程中,程序可以随时转入对Flash存储器进行编程操作。这种情况下对Flash存储器的擦除与写入不需要用户提供其它外部硬件条件。
两种模式各有优缺点:监控模式需要外部硬件支持,但不需要单片机内部程序的存在,所以适合对新出厂芯片进行编程写入,或是对芯片进行整体擦除与写入;用户模式可以在单片机正常工作时进入,所以常用在程序运行过程中对部分Flash存储器的一些单元内容进行修改,特别适合于目标系统的动态程序更新和运行数据的存储。目前监控模式常被仿真器和编程器采用,而在实际的
工程
路基工程安全技术交底工程项目施工成本控制工程量增项单年度零星工程技术标正投影法基本原理
应用中,开发者往往只需要考虑和实现用户模式下的Flash存储器在线编程。本章只讨论用户模式下的Flash存储器的编程方法,给出具体的实例。要进行编程器研制或仿真器研制的技术人员需掌握有关监控模式的Flash存储器的编程方法,请参考Freescale的有关手册或其它文献。
13.2 MC908GP32单片机Flash存储器编程方法
Flash存储器一般作为程序存储器使用,不能在运行时随时擦除、写入。当然,由于物理结构方面的原因,对Flash存储器的写操作,更不能像对待一般RAM那样方便。在许多嵌入式产品开发中,需要使用掉电仍能保存数据的存储器来保存一些参数或重要数据,目前一般使用EEPROM来实现。HC08的Flash存储器提供了用户模式下的在线编程功能,可以使用Flash存储器的一些区域来实现EEPROM的功能,这样简化了电路设计,节约了成本。但是,Flash存储器的在线编程不同于一般的RAM读写,需要专门的过程,本节介绍HC08的Flash存储器的基本操作方法。
13.2.1 Flash存储器编程的基本概念
虽然Flash存储器是一种快速的电可擦除、电可编程(写入)的只读存储器,但是基于其物理结构原因,对Flash存储器的擦除及写入一般需要高于电源的电压,Freescale HC08系列单片机的片内Flash存储器内含有“升压电路”,使其能够在单一电源供电情况下进行擦除与写入。对Flash编程的基本操作有两种:擦除(Erase)和写入(Program)。擦除操作的含义是将存储单元的内容由二进制的0变成1,而写入操作的含义,是将存储单元的内容由二进制的1变成0。擦除及写入操作都是通过设置或清除Flash存储器的控制寄存器(FLCR)中的某个或某些位来完成的。
Flash存储器在片内是以页(Page)和行(Row)为单位组织的。页和行的大小(字节数)随整个Flash存储器的大小变化而变化,但页的大小始终为行的两倍。例如MC908GP32内含32K的Flash存储器(地址为$8000~$FDFF),每页的大小为128字节,每行的大小为64字节;而MC68HC908JL3片内Flash存储器仅有4K,每页和每行的大小也分别变为64字节和32字节。
对于GP32单片机来说,对Flash存储器的擦除操作可以进行整体擦除也可以仅擦除某一起始地址开始的一页(128字节)。也就是说,不能仅擦除某一字节或一次擦除小于128字节。注意这一特点,在数据安排时尤为重要。GP32单片机的写入操作以行(64字节)为基础,一次连续写入数据个数只能在一行之内。当然,不经过擦除的区域,不能进行写入,这一点需特别注意。
从这里可以看出,对Flash存储器的写入,必须将一组数据准备好后,放入RAM区,然后擦除Flash存储器的相应区域并进行写入。我们要考虑到对Flash存储器的某一字节擦除与写入会影响其后的一页,所以,在进行擦除与写入操作之前,把与擦除区域相关的数据安排好十分必要。
13.2.2 Flash存储器的编程寄存器
在MC908GP32单片机中,与Flash编程有关的寄存器有2个,它们是Flash控制寄存器(FLCR)和Flash块保护寄存器(FLBPR)。对应的地址分别为$FE08和$FF7E,下面分别阐述这些寄存器的功能及用法。
(1) Flash控制寄存器(FLash Control Register — FLCR)
FLCR的地址:$FE08,定义为:
数据位
D7
D6
D5
D4
D3
D2
D1
D0
定义
未定义
未定义
未定义
未定义
HVEN
MASS
ERASE
PGM
复位
0
0
0
0
0
0
0
0
D7~D4位:未定义。
D3 — HVEN位:高压允许位(High-Voltage Enable Bit)。 HVEN=1,打开电荷泵并将高电平加到Flash阵列上;HVEN=0,撤除Flash阵列上的高电平并关闭电荷泵。当PGM=1或ERASE=1时,可以通过设置HVEN将来自片内电荷泵的高压加到Flash阵列上。
D2 — MASS位:整体擦除控制位(Mass Erase Control Bit)。该位在ERASE=1时有效,用于选择Flash擦除操作方式:整体擦除或页擦除。MASS=1,选择整体擦除方式;MASS=0,选择页擦除方式。
D1 — ERASE位:擦除控制位(Erase Control Bit)。该位用于设置Flash编程操作为擦除操作。ERASE位与PGM位之间存在互锁关系,无法同时被设置为1。ERASE=1,选择擦除操作;ERASE=0,不选择擦除操作。
D0 — PGM位:编程(写入)控制位(Program Control Bit)。该位用于设置Flash编程操作为编程(写入)操作,且无法与ERASE位同时为1。PGM=1,选择写入操作;PGM=0,不选择写入操作。
(2) Flash块保护寄存器(FLash Block Protect Register — FLBPR)
FLBPR的地址:$FF7E,它的内容为Flash保护区域的起始地址的14~7位,保护区域的起始地址的最高位始终为1,而保护区域的起始地址的低7位(位6~0)始终为0。对FLBPR写入,可以设定被保护的Flash区域,它本身也是一个Flash字节。当Flash处于保护状态时,擦除和写入操作都是受限制的,HVEN将无法被正常置起。Flash块保护寄存器设定的只是保护区域的起始地址,保护区域的结束地址始终为Flash存储区的结束地址($FFFF)。例如,设定FLBPR的值为$02(%0000 0010),则保护区域为$8100~$FFFF(%1000 0001 0000 0000 ~ %1111 1111 1111 1111)。
特别情况是:FLBPR的存储内容为$00,整个Flash存储区都受到保护;如果FLBPR的存储内容为$FF,则整个Flash存储区都可以被擦除或写入。
只有当单片机处于运行用户程序时,对FLBPR本身和Flash保护区域的擦写操作保护才是有效的。复位不影响FLBPR。
需要注意的是,FLBPR的8位数据所代表的地址取决于具体型号的芯片的Flash容量。以上是对MC908GP32而言的,FLBPR设定的是16位起始地址的第14~7位(第15位恒为1);而对MC68HC908JL3而言,它们设定的是16位起始地址的第12~5位(第15~13位恒为1)。这两种情况见表13-1。具体设定时可以根据相应芯片手册结合要保护的区域进行计算得到。
表13-1 GP32与JL3芯片 Flash块保护寄存器设置比较
GP32
JL3
FLBPR内容
受保护的Flash区域
FLBPR内容
受保护的Flash区域
$00(%0000 0000)
$8000 ~ $FFFF
$00 ~ $60
$EC00 ~ $FFFF
$01(%0000 0001)
$8080 ~ $FFFF
$62(%0110 0010)
$EC40 ~ $FFFF
$02(%0000 0010)
$8100 ~ $FFFF
$64(%0110 0100)
$EC80 ~ $FFFF
……
……
$68(%0110 1000)
$ED00 ~ $FFFF
$FE(%1111 1110)
$FF00 ~ $FFFF
……
……
$FF(%1111 1111)
Flash区不被保护
$FE(%1111 1110)
$FFC0 ~ $FFFF
13.2.3 Flash存储器的编程过程
在HC08系列单片机中,对Flash进行擦除或写入操作需要遵循一定的时序和步骤。对于整个MC68HC908系列的各个型号,这些步骤是一样的,但时序要求可能略有不同,针对具体型号的Flash进行编程时应参考相应的芯片手册。同时需要注意的是,一些型号的监控ROM内含有Flash编程子程序,用户可直接调用,例如MC68HC908JL3;有的型号则没有,例如MC908GP32,这种情况需自行编制子程序。下面介绍MC908GP32的Flash编程的基本操作。
(1) 页擦除操作
下面过程可以擦除GP32的Flash存储器的一页(128字节):
①$2→FLCR(1→ERASE位,0→MASS位):进行页面擦除。
②读Flash块保护寄存器FLBPR。
③向被擦除的Flash页内任意一个地址写入任意值,为方便起见,一般向待擦除页首地址写入0。
④延时tnvs(>10µs)。
⑤$A→FLCR(1→HVEN位)。
⑥延时terase(>1ms)。
⑦$8→FLCR(0→ERASE位)。
⑧延时tnvh(>5µs)。
⑨$0→FLCR(0→HVEN位)。
⑩延时trcv(>1µs),完成一页的擦除操作。
(2) 整体擦除操作
下面过程擦除GP32的整个Flash区域,以便把新的程序装入Flash存储器,这是应用系统研制过程中开发工具对GP32编程的准备工作。
①$6→FLCR(1→ERASE位,1→MASS位):进行整体擦除。
②读Flash块保护寄存器FLBPR。
③向被擦除的Flash任意一个地址写入任意值,为方便起见,一般向首地址写入0。
④延时tnvs(>10µs)。
⑤$E→FLCR(1→HVEN位、MASS位、ERASE位)。
⑥延时tMerase(>4ms)。
⑦$C→FLCR(0→ERASE位)。
⑧延时tnvhl(>100µs)。
⑨$0→FLCR(0→HVEN位、MASS位)。
⑩延时trcv(>1µs),完成整体擦除操作。
(3) 编程操作
MC908GP32的Flash编程操作以行(64字节)为单位进行的。当然,一次写入可以小于一行,但不能大于一行。对于已经写过的部分,未经擦除不能重新写入变更其数据,否则将引起数据出错。写入过程如下:
①$1→FLCR(1→PGM位)。
②读Flash块保护寄存器FLBPR。
③向将要写入的Flash行内任意一个地址写入任意值,为方便起见,一般向行首地址写入0,这一步选定了所要编程的行,以下的目标地址必须在这一行中。
④先延时tnvs(>10µs);再将$9→FLCR(1→HVEN位)。
⑤先延时tpgs(>5µs);再将待写数据写入对应的Flash地址。
⑥延时tprog(>30µs),完成一个字节的写入(编程)工作。
⑦重复⑤、⑥,直至同一行内各字节写入完毕。
⑧$8→FLCR(0→PGM位)。
⑨先延时tnvh(>5µs);再将$0→FLCR(0→HVEN位)。
⑩延时trcv(>1µs)以后,完成本行写入工作,可以读出校验。
表13-2对上述过程出现的参数进行说明,这是MC908GP32的Flash编程的各项参数,其他型号的单片机的参数数值请参阅相应的芯片手册。
表13-2 MC908GP32的Flash编程参数
参数
符号
最小值
最大值
单位
Flash行大小
—
64
64
字节
Flash页大小
—
128
128
字节
Flash读写周期
tread
32K
8.4M
Hz
Flash页擦除时间
terase
1
—
ms
Flash整体擦除时间
TMerase
4
—
ms
Flash从设置PGM或ERASE位到HVEN建立时间
tnvs
10
—
µs
Flash高电平维持时间(页擦除时)
tnvh
5
—
µs
Flash高电平维持时间(整体擦除时)
tnvhl
100
—
µs
Flash写入编程维持时间
tpgs
5
—
µs
Flash写入编程时间
tprog
30
40
µs
Flash返回只读状态时间
trcv
1
—
µs
Flash累积高电平时间
thv
—
25
ms
Flash行擦除次数
—
10K
—
次数
Flash行写入次数
—
10K
—
次数
Flash数据保持时间
—
10
—
年
注:①terase和tMerase的最小时间也是擦除操作的最佳时间,如果擦除时间长于该最小值,Flash的寿命会受到影响。
②thv指的是在下一次擦除操作执行以前,该Flash行在写入编程操作中被加上高电平的累积时间。
13.3 GP32单片机Flash在线编程汇编语言实例
本节首先给出GP32单片机的Flash编程子程序,随后给出在用户模式下进行Flash在线编程的实例,并通过与PC机串行通信方式进行验证,PC方采用VB语言编程。
13.3.1 Flash存储器的擦除及写入汇编子程序
由于GP32单片机内部的监控ROM中没有固化Flash编程子程序,要在运行中能对Flash进行在线编程,初始装入的用户程序,必须包含对Flash的擦除及写入子程序。由于程序驻留Flash区,在运行擦除及写入子程序时,整个Flash区会被加上高于普通工作电压的编程电压,致使对Flash区读取不稳定,可能导致程序不能正常执行。为了使擦除、写入程序正常执行,需将擦除、写入子程序移入RAM中并转入RAM区执行。为此,需在RAM区开辟一个缓冲区,供程序移入使用。表13-3给出了Flash在线编程的汇编工程的文件组织情况。
表13-3 Flash汇编工程文件
工程文件名
Flash.prj
所在路径
MC08Ex2007\GP32\GP32S\S14_Flash
文件类型
文件名
功能简述
讲解章节
头文件
GP32ASM.h
芯片头文件
[汇编工程文件组织]4.3
Includes.h
总头文件
[汇编工程文件组织]4.3
SCI.h
串行通信头文件
[串行通信子函数]7.4
汇编语言
子程序文件
MCUInit.s
芯片初始化文件
[初始化及PLL编程实例] 14.2.5
Flash.s
Flash擦写文件
[本章]
SCI.s
串行通信文件
[串行通信子函数]7.4.1
Vectors08.s
中断处理子程序与中断向量表文件
[汇编工程文件组织]8.2
汇编语言
主程序文件
Main.s
主程序文件
[本章]
(1) 擦除、写入子程序(Flash.s)
//ErasePage:擦除Flash存储区的一页-----------------------*
//功能:擦除Flash区中以HX为首地址的一页 *
//入口:HX = 要擦除的Flash页首地址(供DoErasePage使用) *
//出口:无 *
//堆栈深度:11 *
//内部调用:DoErasePage *
//全局变量:PrgInRAM *
//说 明:本程序的实际工作程序,在执行前被移入RAM区,移 *
// 到RAM区的起始地址为PrgInRAM *
//------------------------------------------------------*
ErasePage::
PSHA //保护A
PSHH //保护HX
PSHX
AIS #-1 //开辟临时变量
//1. 将擦除程序从FLASH移到RAM中
//1.1计算需要移入RAM区PrgInRAM的程序字节数
LDA #0 //[SP+1]存放移入RAM区的程序字节数,初始为0
STA 1,SP
LDHX #DoErasePage //擦除程序首地址->HX
ErasePage_1:
INC 1,SP
AIX #0x1
CPHX #EraseEnd //判断是否到了擦除程序的末地址
BLO ErasePage_1 //否,继续
//1.2计算完程序长度,将程序移入RAM区PrgInRAM开始的地址中
LDHX #0x0000
MoveToRAM:
LDA DoErasePage,X //(Erase1Page + HX) -> A
STA PrgInRAM,X //A -> (PrgInRAM + HX)
INCX
DBNZ 1,SP,MoveToRAM //程序是否移入完毕?否,继续
//程序移入完毕
AIS #1 //释放临时变量
PULX //恢复HX(HX中存放要擦除的Flash初始地址)
PULH
//2. 执行RAM中的擦除程序PrgInRAM
JSR PrgInRAM
PULA //恢复A
RTS
//DoErasePage:flash页擦除执行程序-----------------------*
//功能:设置flash控制寄存器和块保护寄存器,按照flash的擦时*
// 序,擦除指定页 *
//入口:HX(要擦除的Flash页首地址) *
//出口:无 *
//堆栈深度:5 *
//内部调用:Delay_usA(延时一定时间) *
//------------------------------------------------------*
DoErasePage::
PSHA //保护A
LDA #%00000010 //(1) 置FLCR的ERASE=1,MASS=0
STA FLCR
LDA FLBPR //(2) 读出块保护寄存器(FLBPR)
LDA #$68 //(3) 任意值->被擦除Flash首地址
STA ,X
LDA #6 //(4) 延时 > 10us
BSR Delay_usA
LDA #%00001010 //(5) 置HVEN位为1
STA FLCR // (打开电荷泵高电压到Flash阵列)
LDA #248 //(6) 延时 > 1ms(每次500us,共2次)
BSR Delay_usA
LDA #248
BSR Delay_usA
LDA #%00001000 //(7) 清Erase位为0
STA FLCR
LDA #3 //(8) 延时 > 5us
BSR Delay_usA
CLRA //(9) 清HVEN位为0
STA FLCR
LDA #3 //(10) 延时 > 1us
BSR Delay_usA
PULA //恢复A
RTS
//Delay_usA:延时一定时间--------------------------------*
//功能:延时一定时间,供flash页擦除执行程序调用,和其一并移*
// 入内存 *
//入口:A(0-255) *
//出口:无 *
//堆栈深度:2 *
//------------------------------------------------------*
Delay_usA::
NOP //1个时钟周期
NOP //1个时钟周期
DBNZA Delay_usA //3个时钟周期
RTS //4个时钟周期
//------------------------------------------------------*
EraseEnd: //擦除程序的末地址
NOP
//WriteFlash:向flash写入小于1行(64字节)的数据-----------*
//功能:移动写flash执行程序和相关延时程序到内存中,并调用 *
// 写flash执行程序 *
//入口:(1) A = 待写入的数据个数N *
// (2) RAMandFalsh[0-3] *
// [0-1] = RAM区首地址 [2-3]=Flash区首地址 *
//出口:无 *
//堆栈深度:13 *
//内部调用:DoWriteFlash *
//全局变量:RAMandFalsh[0-3],PrgInRAM *
//说 明:本程序的实际工作程序,在执行前被移入RAM区,移 *
// 到RAM区的起始地址为PrgInRAM *
//------------------------------------------------------*
WriteFlash::
PSHH //保护HX
PSHX
AIS #-2 //开辟2个临时变量
STA 2,SP //[SP+2]存放要写入的数据个数N
//1. 将程序从Flash中移到RAM中以PrgInRAM为始址的区域
//1.1计算需要移入RAM区PrgInRAM的程序字节数
LDA #0 //[SP+1]存放移入RAM区的程序字节数,初始为0
STA 1,SP
LDHX #DoWriteFlash //写入程序首地址 -> HX
WriteFlash_1:
INC 1,SP
AIX #$1
CPHX #WriteEnd //是否到了写入程序的末地址
BLO WriteFlash_1 //否,继续
//1.2算完程序长度,将其移入RAM区以PrgInRAM为始址的区域
LDHX #0x0000
WriteFlash_2:
LDA DoWriteFlash,X //(DoWriteFlash + HX) -> A
STA PrgInRAM,X //A -> (PrgInRAM + HX)
INCX
DBNZ 1,SP,WriteFlash_2 //程序是否移入完毕?否,继续
//程序移入完毕
LDA 2,SP //要写入的数据个数N -> A
AIS #2 //释放临时变量
//2. 转入内存,执行写入执行程序
JSR PrgInRAM
PULX //恢复HX
PULH
RTS
//DoWriteFlash:Flash写入执行程序------------------------*
//功能:设置Flash控制寄存器和块保护寄存器,按照Flash的写时*
// 序,在指定地址写入数据 *
//入口: *
// (1)A:要写入的数据个数 *
// (2)RAMandFalsh[0-3] *
// [0-1] = RAM区首地址 [2-3]=Flash区首地址 *
//出口:无 *
//堆栈深度:7 *
//内部调用:Delay_usB(延时一定时间) *
//全局变量:RAMandFalsh *
//------------------------------------------------------*
DoWriteFlash::
PSHH //保护HX
PSHX
AIS #-1 //开辟临时变量
STA 1,SP //[SP + 1]存放写入个数N
LDA #%00000001 //(1) 置FLCR的PGM位为1
STA FLCR
LDA FLBPR //(2) 读出Flash块保护寄存器
LDHX RAMandFlash+2 //(3) 任意数据 -> 所选块任意单元
STA ,X // 选中要写入的行
LDA #6 //(4) 延时 > 10us
BSR Delay_usB
LDA #%00001001 //(5) 置FLCR的HVEN位为1
STA FLCR
LDA #3 //(6) 延时 > 5us
BSR Delay_usB
//向页内目标地址写入N个数据
DoWriteFlash_1:
//(7) 逐个取RAM中一个数,并存放到目标Flash区
LDHX RAMandFlash //取RAM区(源)地址
LDA ,X //取RAM中一个数
AIX #1 //源地址 + 1
STHX RAMandFlash
LDHX RAMandFlash + 2 //取Flash区(目的)地址
STA ,X //将RAM中的数存入相应Flash区
AIX #1 //目的地址 + 1
STHX RAMandFlash+2
//(8) 延时 > 30us
LDA #9
BSR Delay_usB
//重复写入N个数据
DBNZ 1,SP,DoWriteFlash_1 //写入结束?否,继续
LDA #$8 //(9) 0 -> PGM
STA FLCR
LDA #3 //(10) 延时 > 5us
BSR Delay_usB
LDA #$00 //(11) 0 -> HVEN
STA FLCR
LDA #1 //(12) 延时 > 1us
BSR Delay_usB
AIS #1 //释放1一个字节临时变量
PULX //恢复HX
PULH
RTS
//Delay_usB:延时一定时间--------------------------------*
//功能:延时一定时间,供Flash写入执行程序调用,和其一并移入*
// 内存 *
//入口:A(0-255) *
//出口:无 *
//堆栈深度:2 *
//------------------------------------------------------*
Delay_usB::
NOP //1个周期
NOP //1个周期
DBNZA Delay_usB //3个周期
RTS //4个周期
//-------------------------------------------------------
WriteEnd: //写入程序的结束地址
NOP
(2) 擦除与写入子程序编程要点说明
使用Flash在线编程技术可以省去外接EEPROM,不仅简化了电路设计,也提高了系统稳定性。但是Flash在线编程的技术文献资料比较少,特别是实用程序目前还较少见到,涉及Flash在线编程的技术细节应仔细斟酌。由于擦除与写入子程序是复制到RAM中执行,我们给出的两个子程序已经包含了复制并转入RAM执行的程序过程,正是由于这个特殊的过程,根据实际编程调试与项目开发过程中积累的经验,提出以下注意点,供读者参考:
①RAM中要留有足够的缓冲区,以便存放复制到RAM中的子程序,具体值是取擦除与写入子程序中的大者即可。它们的大小可在编译后的.LST文件中查得。
②擦除及写入子程序中要调用的延时子程序均随其后,以便同时复制到RAM中,最后一个标号是为复制方便而加入,否则复制时要用其它方法得到结束地址,编程变得不规范。
③擦除及写入子程序中对延时子程序的调用必须使用“BSR 子程序名”,而不能使用 “JSR 子程序名”,因为这里的子程序是复制到RAM中执行的,程序地址已经发生了变化,所以只能用相对调用。
④擦除子程序与写入子程序及其中的延时子程序,若含有跳转语句,不能使用“JMP 地址”,只能使用“BRA 地址”。原因同上。
⑤使用不同型号芯片时,上述子程序中延时时间应根据芯片手册予以变动。延时子程序也应根据不同的总线频率加以变化,确保时间满足时序要求。
⑥一次擦除后未被写入过的区域可以再次调用写入子程序写入,但写入过的区域,未经擦除不能重写。
⑦由于擦除是每次擦除一页(128字节),所以数据应合理安排,避免误擦。
⑧页首地址的定义须遵照保护寄存器FLBPR定义的规则,即对GP32来说,页地址的低7位为0。
⑨在线编程时使用的Flash存储区域应在程序Flash存储区域之前,因为Flash保护区为FLBPR决定的地址至末尾。
13.3.2 Flash存储器在线编程汇编主程序及PC方程序
为了更清晰地了解Flash存储器在线编程总体轮廓,本节给出调用实例的编程框架。调用实例由单片机方程序与PC机方程序构成。单片机系统的硬件带有MAX232串行三线接口,与PC机的串行口相连,A口的PTA7过电阻接通信指示灯。总体思想是:通过PC机界面输入数据,将数据发向单片机,单片机接收数据写入Flash区域,同时读出返回给PC机,PC机接收该数据进行分解并显示,供比较校验,以可视化方式完成Flash擦除、写入、校验工作。
(1) 单片机方程序流程图
单片机方程序的主要功能是:
①不断地向PC机发出握手信号,并监测PC机返回的握手信号。可以看到串行通信指示灯闪烁,表明MCU在向PC机发送握手信号。
②若收到握手信号,表明PC机可以发送数据,设要写入数据的个数为N,则单片机首先将接收数据个数N放入内存(接收的数据在一行之内,N小于等于64),随后接收N个数据,放入内存缓冲区。
③擦除指定Flash区域,将收到的N个数据写入Flash区。
④读出该Flash区的数据,并发送到PC机。
其流程见图13-1。
图13-1 Flash在线编程例程单片机方程序流程图
(2) 单片机方主程序main.s
//------------------------------------------------------*
//工 程 名:Flash.prj *
//功 能: *
// (1) 等待接收N+1个数,并放入N和data数组中 *
// (2) 擦除以Fdata为首地址的Flash一页,将N个数据写入 *
// (3) 从以Fdata为首址的Flash区读取N个数据,串口发送 *
//说 明: *
// (1) 与Visual Basic 6.0 程序Flash_Test.vbp联合运行 *
// (2) 擦/写函数中用来暂存写入或擦除程序的首地址变量 *
// PrgInRAM,用来暂存待写入或擦除的Flash首地址变量*
// RAMandFlash,用来存放写入的数据个数N和写入的数 *
// 据首址Data,必须在main函数文件中定义为全局的,否*
// 则将出错 *
// (3) 调用擦/写子程序之前先将待擦/写页后一页以后的所*
// 有区域写保护 *
//--------清华2007版《嵌入式技术基础与实践》实例--------*
//总头文件
.include "Includes.h"
//主程序
.area flash(abs)
.org FlashStartAddr
//设写入区为$8000~$807F一页(几个初始值仅作比较)
Fdata: .byte 11,12,13,14,15,16,17,18,66
.area flash(abs)
.org PrgStartAddr
MainInit:: //复位后从此处执行(见Vectors08.s文件末尾处)
SEI //关总中断
//1. 堆栈初始化为RAM最高端
LDHX #RAMendAddr + 1 //HX = #RAMEndAddr + 1
TXS //HX - 1 -> SP
//2. 芯片初始化
JSR MCUinit //初学时跳过此处
//3. 模块初始化
JSR SCIinit //(1) 串行口初始化
//总循环
MainLoop:
LDA #86 //发送握手信号86
J