NANDflash读写擦除操作本文主要介绍SAMSUNG公司的S3C2410处理器和K9F1208NANDflash的读写擦除操作。一、K9F1208NANDflash芯片介绍S3C2410处理器集成了8位NANDflash控制器。因NANDflashK9F1208、K9F1G08的数据页大小分别为512B、2KB,在寻址方式上有一定的差异,所以程序代码并不通用。K9F1208的器件存储容量为64M字节和2048K字节的spare存储区,8位I/O端口采用地址、数据和命令复用的方法。该器件的引脚图如下所示该器件的引脚功能描述如下表所示引脚名称英文描述描述I/O0~I/O7Datainput/outputs数据输入输出CLECommandlatchenable命令锁存使能ALEAddresslatchenable地址锁存使能CE#Chipenable片选RE#Readenable读使能WE#Writeenable写使能WP#Writeprotect写保护R/B#Ready/Busyoutput准备好/忙碌输出VCCPower(+2.7V~3.6V)电源(+2.7V~3.6V)VSSGround地N.CNoconnection空引脚NANDflash的数据是以bit的方式保存在memorycell。一般一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(X8)/word(X16),这就是NANDdevice的位宽。这些line组成page,page再组织形成一个block。K9F1208的相关数据如下:1block=32page;1page=528byte=512byte(mainarea)+16byte(sparearea)总容量为=4096(block)*32(page/block)*512(byte/page)=64MBNANDflash以页为单位读写数据,而以块为单位擦除数据。按照K9F1208的组织方式可以分为4类地址:columnaddress、halfpagepointer、pageaddress、blockaddress。A[0:25]表示数据在64MB空间中的地址。Columnaddress:表示数据在半页中的地址,大小范围0~255,用A[0:7]表示。Halfpageaddress:表示半页在整页中的位置,即在0~255空间还是在256~511空间,用A[8]表示。Pageaddress:表示页在块中的地址,大小范围0~31,用A[9:13]表示。Blockaddress:表示块在flash中的位置,大小范围为0~4095,用A[14:25]表示。对NANDflash的操作主要包括读操作、写操作、擦除操作、坏块识别和坏块标示等。KF1208由4个操作周期组成,分别为A[0:7]、A[9:16]、A[17:24]、A[25],具体如下表所示I/O0I/O1I/O2I/O3I/O4I/O5I/O6I/O71stcycleA0A1A2A3A4A5A6A72stcycleA9A10A11A12A13A14A15A163stcycleA17A18A19A20A21A22A23A244stcycleA25LLLLLLL1、读操作过程读操作的过程:发送读取指令发送第1个周期地址(A0~A7)发送第2个周期地址(A9~A16)④发送第3个周期地址(A17~A24)⑤发送第4个周期地址(A25)⑥读取数据至页末K9F1208提供了两个读指令:“0x00”、“0x01”,用于选中上半页还是下半页。为0x00可以将A[8]置为0,为0x01可以将A[8]置为1。读操作的对象为一个页面,建议从页边界开始读写至页结束。读操作流程图如下所示2、写操作过程写操作的过程:发送编程指令“0x80”发送第1个周期地址(A0~A7)发送第2个周期地址(A9~A16)④发送第3个周期地址(A17~A24)⑤发送第4个周期地址(A25)⑥向器件的数据总线发送一个扇区的数据⑦发送编程指令“0x10”⑧发送查询状态命令字“0x70”⑨读取器件的数据总线,判断I/O6上的值或判断R/B#线上的值,直到I/O6=1或R/B#=1⑩判断I/O0是否为0,从而确定操作是否成功。0表示成功,1表示失败注意:写入的操作对象是一个页面。写操作流程图如下所示3、擦除操作过程擦除操作的过程:发送擦除指令“0x60”发送第1个周期地址(A9~A16)发送第2个周期地址(A17~A24)④发送第3个周期地址(A25)⑤发送擦除指令“0xD0”⑥发送查询状态命令字“0x70”⑦读取K9F1208数据总线,判断I/O6上的值或判断R/B#线上的值,直到I/O6=1或R/B#=1⑧判断I/O0是否为0,从而确定操作是否成功。0表示成功,1表示失败注意:擦除的对象是一个数据块。擦除操作流程图如下所示4、命令设置二、S3C2410NANDflash控制寄存器介绍S3C2410NANDflash控制器中几个比较重要的寄存器NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT等。1、配置寄存器NFCONF(地址:0x4E000000)NFCONF位描述初始值Enable/disable[15]Nandflash使能位0:关闭控制器1:使能控制器0Reserved[13:14]保留-InitalizeECC[12]初始化ECC0:不使用ECC1:使用ECC0Nandflashmemorychipenable[11]Nandflash片选使能0:激活1:不激活0TACLS[8:10]CLE和ALE持续时间设置(0~7)持续时间=HCLK×(设定值+1)000Reserved[7]保留-TWRPH0[4:6]TWRPH0持续时间设置(0~7)持续时间=HCLK×(设定值+1)000Reserved[3]保留-TWRPH1[0:2]TWRPH1持续时间设置(0~7)持续时间=HCLK×(设定值+1)0002、命令寄存器NFCMD(地址:0x4E000004)NFCMD位描述初始值Reserved[8:15]保留-Command[0:7]命令寄存器0x003、地址寄存器NFADDR(地址:0x4E000008)NFADDR位描述初始值Reserved[8:15]保留-NFADDR[0:7]地址寄存器-4、数据寄存器NFDATA(地址:0x4E00000)NFDATA位描述初始值Reserved[8:15]保留-Data[0:7]数据寄存器-5、状态寄存器NFSTAT(地址:0x4E000010)NFSTAT位描述初始值Reserved[1:16]保留-RnB[0]NANDflash忙位判断0:忙1:准备好-三、程序设计示例1、NANDflash控制器相关寄存器及宏定义控制寄存器定义#definerNFCONF(*(volatileunsigned*)0x4e000000)#definerNFCMD(*(volatileunsigned*)0x4e000004)#definerNFADDR(*(volatileunsigned*)0x4e000008)#definerNFDATA(*(volatileunsigned*)0x4e00000C)#definerNFSTAT(*(volatileunsigned*)0x4e000010)宏定义#defineREADCMD00#defineREADCMD11#defineREADCMD20x50#defineERASECMD00x60#defineERASECMD10xD0#definePROGCMD00x80#definePROGCMD10x10#defineEnNandFlash()(rNFCONF|=0x8000)#defineDsNandFlash()(rNFCONF&=^0x8000)#defineInitEcc()(rNFCONF|=0x1000)#defineNoEcc()(rNFCONF&=^0x1000)#defineNFChipEn()(rNFCONF|=0x800)#defineNFChipDs()(rNFCONF&=^0x800)#defineWrNFCmd(cmd)(rNFCMD=(cmd))#defineWrNFAddr(addr)(rNFADDR=(addr))#defineWrNFDat(dat)(rNFDATA=(dat))#defineRdNFDat()(rNFDATA)#defineRdNFStat()(rNFSTAT)#defineNFIsBusy()(!(rNFSTAT&1))#defineNFIsReady()(rNFSTAT&1)2、初始化函数staticvoidInitNandCfg(void){//使能NANDflash控制器,不片选NANDflashchiprNFCONF=(115)|(112)|(111)|(78)|(74)|(7);}voidInitNandFlash(void){U32i;InitNandCfg();i=ReadChipId();if((i==0x9873)||(i==0xec75))NandAddr=0;elseif(i==0xec76){Support=1;NandAddr=1;}else{uart_printf(“Chipiderror!\n”);return;}}3、页面读函数voidReadPage(U32addr,U8*buf){U16i;NFChipEn();WrNFCmd(READCMD0);WrNFAddr(0);WrNFAddr(addr);WrNFAddr(addr8);if(NandAddr)WrNFAddr(addr16);WaitNFBusy();for(i=0;i512;i++)buf[i]=RdNFDat();NFChipDs();}4、页面写函数U32WritePage(U32addr,U8*buf){U16i;U8stat;NFChipEn();WrNFCmd(READCMD0);WrNFCmd(PROGCMD0);WrNFAddr(0);WrNFAddr(addr);WrNFAddr(addr8);if(NandAddr)WrNFAddr(addr16);for(i=0;i512;i++)WrNFDat(buf[i]);WrNFCmd(PROGCMD1);stat=WaitNFBusy();NFChipDs();if(stat)uart_printf(“WriteNandFlash0x%xfail\n”,addr);else{U8RdDat[512];ReadPage(addr,RdDat);for(i=0;i512;i++)if(RdDat[i]!=buf[i]){uart_printf(“Checkdataatpage0x%x,offset0x%xfail\n”,addr,i);stat=1;break;}}returnstat;}5、块擦除函数U32EraseBlock(U32addr){U8stat;addr&=^0x1f;NFChipEn();WrNFCmd(ERASECMD0);WrNFAddr(addr);WrNFAddr(addr8);if(NandAddr)WrNFAddr(addr16);WrNFCmd(ERASECMD1);stat=WaitNFBusy();NFChipDs();returnstat;}6、主函数voidnand_test(void){INT32TnTmp;unsignedintpage,block,i;unsignedcharbuf_write[512]={0,1,2,3,4,5,6,7,8,9};unsignedcharbuf_read[512]={0};block=0x20;page=block5;uart_printf(“\nnandtest