;AssumesACCVIE=NMIIE=OFIE=0.
MOV#32,R5;Useaswritecounter
MOV#0F000h,R6;Writepointer
MOV#WDTPW+WDTHOLD,&WDTCTL;DisableWDT
DINT;Disableinterrupts
L1BIT#BUSY,&FCTL3;TestBUSY
JNZL1;Loopwhilebusy
MOV#FWKEY+FSSEL1+FN0,&FCTL2;SMCLK/2
MOV#FWKEY,&FCTL3;ClearLOCK
MOV#FWKEY+BLKWRT+WRT,&FCTL1;Enableblockwrite
L2MOVWrite_Value,0(R6);Writelocation
L3BIT#WAIT,&FCTL3;TestWAIT
JZL3;LoopwhileWAIT=0
INCDR6;Pointtonextword
DECR5;Decrementwritecounter
JNZL2;Endofblock?
MOV#FWKEY,&FCTL1;ClearWRT,BLKWRT
L4BIT#BUSY,&FCTL3;TestBUSY
JNZL4;Loopwhilebusy
MOV#FWKEY+LOCK,&FCTL3;SetLOCK
...;Re-enableWDTifneeded
EINT;Enableinterrupts
当任何写或擦除操作是从RAM启动,而BUSY=1,CPU不能读取或写入或从任何Flash位置。
否则,发生访问冲突,ACCVIFG设置,结果是不可预知的。
此外,如果闪存写入让WRT=0,ACCVIFG中断标志设置,Flash不受影响。
如果写入或擦除操作时从Flash启动的,CPU访问下一条指令时(从Flash读取指令),Flash控制器返回03FFFH给CPU;03FFFH是指令JMPPC,这让CPU一直循环直到Flash操作完成。
Flash写入或擦除操作完成后,允许CPU继续访问接下来的指令。
当BUSY=1时,Flash访问时:
在开始Flash操作之前,需要停止所有的中断源。
如果在Flash操作期间有中断响应,读中断服务程序的地址时,将收到03FFFH作为中断服务程序的地址。
如果BUSY=1;CPU将一直执行难IMPPC指令;Flash操作完成后,将从03FFFH执行中断服务程序而不是正确的中断程序的地址。
停止写入或擦除:
任何写入和擦除操作都可以在正常完成之前,通过设置紧急退出位EMEX退出操作。
设置EMEX时,立即停止当前活动的操作,停止Flash控制器;所有的Flash操作停止,Flash返回可读模式,FCTL1的所有位复位;操作的结果不可预料。
设置和访问Flash控制器:
FCTLx是16位的、密码保护的、可读写的寄存器。
写入这些寄存器都必须在高位包含密码0A5H,如果写入的不是0A5H,将会引起复位。
读寄存器时高位读出的是96H。
在擦除或写入字或字节时写FCTL1寄存器将会引起访问冲突,置位ACCVIFG.块写入时,WAIT=1时可以写FCTL1寄存器,当WAIT=0时写FCTL1寄存器是访问冲突,置位ACCVIFG。
BUSY=1时,所有写入FCTL2寄存器都是访问冲突。
BUSY=1时,所有的FCTLx都可以读操作,不会引起访问冲突。
Flash的中断:
Flash控制器有两个中断源:
KEYV,和ACCVIFG。
ACCVIFG在访问冲突的时候被置位。
当ACCVIE在Flash操作完成后被重新使能后ACCVIFG会引起中断请求。
ACCIFG和NMI同样的中断向量,所以这个中断不需要GIE位允许即可产生中断请求。
必须通过软件检测ACCVIFG位,以确定发生了访问冲突;ACCVIFG位必须软件复位。
KEYV是关键值错误当写Flash的寄存器时没有写正确的高位密码时被置位,这是会立刻引起PUC信号复位整个硬件。
编程Flash的硬件:
编程430的Flash内容有三种选择,通过JTAG、通过BSL和用户定制。
用户定制即是通过单片机的程序访问自己的Flash。
Flash的寄存器列表如下:
RegisterShortFormRegisterTypeAddressInitialState
Flashmemorycontrolregister1FCTL1Read/write0128h09600hwithPUC
Flashmemorycontrolregister2FCTL2Read/write012Ah09642hwithPUC
Flashmemorycontrolregister3FCTL3Read/write012Ch09618hwithPUC
InterruptEnable1IE1Read/write000hResetwithPUC
Flash的硬件部分就介绍这么多了,有什么不大懂的地方请参考TI提供的用户指南。
∙程序实现:
首先设置Flash的时钟,初始化Flash控制器:
voidFlashInit()
{
FCTL2=FWKEY+FSSEL_2+FN1;//默认SMCLK/3=333KHz
}
这个函数仅仅设置了时钟。
擦除函数:
voidFlashErase(unsignedintAddr)
{
char*FlashPtr;
FlashPtr=(char*)Addr;
FCTL1=FWKEY+ERASE;//SetErasebit
FCTL3=FWKEY;//ClearLockbit
DINT;
*FlashPtr=0;//DummywritetoeraseFlashsegmentB
WaitForEnable();//Busy
EINT;
FCTL1=FWKEY;//Lock
FCTL3=FWKEY+LOCK;//SetLockbit
}
这个和上面给出的流程一样,参数是要被擦除的段的首地址。
WaitForEnable函数等等待BUSY标志变回零即操作完成。
voidWaitForEnable()
{
while((FCTL3&BUSY)==BUSY);//Busy
}
写入字节:
voidFlashWriteChar(unsignedintaddr,charData)
{
char*FlashPtr=(char*)addr;//SegmentApointer
FCTL1=FWKEY+WRT;//SetWRTbitforwriteoperation
FCTL3=FWKEY;//ClearLockbit
DINT;
*FlashPtr=Data;//SaveData
WaitForEnable();//Busy
EINT;
FCTL1=FWKEY;//ClearWRTbit
FCTL3=FWKEY+LOCK;//SetLOCKbit
}
写入字:
voidFlashWriteWord(unsignedintaddr,unsignedintData)
{
unsignedint*FlashPtr=(unsignedint*)addr;
FCTL1=FWKEY+WRT;//SetWRTbitforwriteoperation
FCTL3=FWKEY;//ClearLockbit
DINT;
*FlashPtr=Data;//SaveData
WaitForEnable();//Busy
EINT;
FCTL1=FWKEY;//ClearWRTbit
FCTL3=FWKEY+LOCK;//SetLOCKbit
}
写入字或字节两个函数差别仅仅是指针类型不同。
读取字或字节:
charFlashReadChar(unsignedintAddr)
{
charData;
char*FlashPtr=(char*)Addr;
Data=*FlashPtr;
return(Data);
}
unsignedintFlashReadWord(unsignedintAddr)
{
unsignedintData;
unsignedint*FlashPtr=(unsignedint*)Addr;
Data=*FlashPtr;
return(Data);
}
这两个函数的差别也是仅仅指针类型不同。
这些函数和前面硬件介绍部分的程序流程相同,这里不再详细说明。
∙使用示例:
使用方法和之前的一样,工程中加入C文件,源代码文件中文件包含H文件,即可使用,具体参考示例项目:
演示主要程序主要如下:
#include
#include"Flash.h"
inta;
voidmain(void)
{
//Stopwatchdogtimertopreventtimeoutreset
WDTCTL=WDTPW+WDTHOLD;
ClkInit();
FlashInit();
FlashWriteChar(InfoB,0x25);
a=FlashReadChar(InfoB);//InfoB在H文件中有宏定义
FlashWriteWord(InfoB+2,0x5669);
a=FlashReadWord(InfoB+2);
FlashErase(InfoB);
LPM0;
}
这里向InfoB(1000h)首地址开始写数据,先写一个字节再写入一个字(注意写入字时,必须是偶数地址,奇数地址会写在这个地址所在的前一个偶数地址),读出,然后擦除。
这里的程序都是在Flash中运行的,没有演示RAM中运行的程序。
如果在RAM运行程序,则需要先把程序从Fla