整个程序段分解为四个部分来分析,初始化NandFlash,读取NandFlash的ID号,NandFlash块擦洗,NandFlash的页数据读写;
在对代码进行分析之前需要把代码中的相应常量定义先列出来:
#define EnNandFlash() (rNFCONF |= 0x8000) //bit15=1 enable NANDflash controller
#define NFChipEn() (rNFCONF &= ~0x800) //bit11=0Nandflash nFCE = L (active)
#define EnNandFlash() (rNFCONF |= 0x8000) //bit15=1enable NAND flash controller
#define DsNandFlash() (rNFCONF &= ~0x8000) //bit15=1disable NAND flash controller
#define InitEcc() (rNFCONF |= 0x1000) //bit12=1initialize ECC
#define NoEcc() (rNFCONF &= ~0x1000) //bit12=0initialize ECC
#define NFChipEn() (rNFCONF &= ~0x800) //bit11=0NAND flash nFCE = L (active)
#define NFChipDs() (rNFCONF |= 0x800) //bit11=1NAND flash nFCE = H (inactive)
#define WrNFCmd(cmd) (rNFCMD = (cmd)) //writecommond to nand flash
#define WrNFAddr(addr) (rNFADDR = (addr)) //writeaddress to nand flash
#define WrNFDat(dat) (rNFDATA = (dat)) //writedata to nand flash
#define RdNFDat() (rNFDATA) //readdata from nand flash
#define RdNFStat() (rNFSTAT) //readstatus from nand flash
#define NFIsBusy() (!(rNFSTAT&1)) //whethernand flash is busy?
#define NFIsReady() (rNFSTAT&1) //whethernand flash is ready?
#define READCMD0 0 //Read0model command == Page addr 0~127
#define READCMD1 1 //Read1model command == Page addr 128~511
#define READCMD2 0x50 //Read2model command == Page addr 512~527
#define ERASECMD0 0x60 //Blockerase command 0
#define ERASECMD1 0xd0 //Blockerase command 1
#define PROGCMD0 0x80 //pagewrite command 0
#define PROGCMD1 0x10 //pagewrite command 1
#define QUERYCMD 0x70 //querycommand
#define RdIDCMD 0x90 //readid command
一、初始化NandFlash
初始化部分对NandFlash的控制寄存器进行初始化配置,而rNFCONF是NandFlash的配置寄存器;在初始化部分的代码基本上所以的Flash都可以公用的。
//**** 初始化 K9F1208U0M nand flash ****/
staticvoid InitNandCfg(void)
{
//enablenand flash control, initilize ecc, chip disable,
rNFCONF =(1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);
//对NandFlash的控制寄存器进行初始化配置,rNFCONF是NandFlash的配置寄存器
//使用控制器,使用ECC,不激活NandFlash,持续时间都设置为HCLK*8
}
二、读NandFlash的ID号
/**** K9F1208U0M nand flash 的ID ****/
staticU32 ReadChipId(void)
{
U32 id;
NFChipEn(); //选中NandFlash
WrNFCmd(RdIDCMD); //写入90h指令,这是读 ID的命令
WrNFAddr(0); //写入地址00h
while(NFIsBusy()); //等待前一步完成
id =RdNFDat()<<8; //8位的NandFlash,之前定义过RdNFDat()
id |= RdNFDat(); //读DeviceCode
NFChipDs();
return id;
}
三、NandFlash 块擦除
** K9F1208U0M nand flash 的块擦除操作 ****/
staticU32 EraseBlock(U32 addr)
{
U8 stat;
addr &= ~0x1f; //保留9-25位
NFChipEn(); //芯片使能,片选拉低,Nand Flash使能
WrNFCmd(ERASECMD0); //擦出的启动指令为60h
WrNFAddr(addr); //写入块地址1
WrNFAddr(addr>>8); //块地址2
if(NandAddr) //判断Flash的型号
WrNFAddr(addr>>16); //后传A17-A24,A25
WrNFCmd(ERASECMD1); //发出擦出命令0Xd0H
stat = WaitNFBusy(); //写完擦除命令后,执行等待过程
NFChipDs(); //失能
return stat; //返回到star
}
四、NandFlash的写、读操作
对于NandFlash而言,地址和命令只能在I/O[7:0]上传递,数据宽度为8位;由于地址只能在I/O[7:0]上传递,因此必须采用移位的方式进行。
写操作的过程为:
/**** K9F1208U0M nand flash 的页数据写 ****/
staticU32 WritePage(U32 addr, U8 *buf)
{
U16 i;
U8 stat, tmp[3];
NFChipEn(); //使能NandFlash
WrNFCmd(PROGCMD0); //写入串行数据输入指令(80h)
WrNFAddr(0); //写地址,即为第1个cycle
WrNFAddr(addr); //写地址的第2个cycle
WrNFAddr(addr>>8); //写地址的第3个cycle
if(NandAddr)
WrNFAddr(addr>>16); //写地址的第4个cycle
InitEcc(); //初始化ECC检测
for(i=0; i<512; i++)
WrNFDat(buf[i]); //循环写入1页数据
tmp[0] = rNFECC0; //产生3位校验码
tmp[1] = rNFECC1;
tmp[2] = rNFECC2;
WrNFDat(tmp[0]); //将校验码写入页面
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);
WrNFCmd(PROGCMD1); //正是开始写入数据
stat = WaitNFBusy();
NFChipDs();
if(stat)
printf("Write nand flash 0x%xfail\n", addr);
else {
U8 RdDat[512];
ReadPage(addr,RdDat);
for(i=0;i<512; i++)
if(RdDat[i]!=buf[i]){
printf("Checkdata at page 0x%x, offset 0x%x fail\n", addr, i);
stat= 1;
break;
}
}
return stat;
}
读操作的过程为:
/**** K9F1208U0M nand flash 的页数据读 ****/
staticvoid ReadPage(U32 addr, U8 *buf) //addr= page address 即是Flashd地址
{
U16 i;
NFChipEn(); //使能NandFlash
WrNFCmd(READCMD0); //发送读指令‘0x00’,整页读取
WrNFAddr(0); //读地址的第1个cycle, 读一个Page, addr=0
WrNFAddr(addr); //读地址的第2个cycle,即A[9:16]
WrNFAddr(addr>>8); //读地址的第3个cycle,即A[17:24]
if(NandAddr)
WrNFAddr(addr>>16); //读地址的第4个cycle,即A[25]。
InitEcc(); //初始化ECC
WaitNFBusy(); //等待系统不忙
for(i=0; i<512; i++)
buf[i] = RdNFDat(); //循环读出1页数据
NFChipDs(); //释放NandFlash
}