NANDCONT:
MODE:nand使能位,该位设置为1使能nand
Reg_nCE:控制的nFCE信号,相当于nand芯片的片选CE信号,为0选择nand
initECC:只写寄存器。设置为1初始化ECC解码器和编码器
MainECCLock:锁存main区的ECC的生成 main区的ECC状态寄存器为NFMECC0/1
SpareECCLock:锁存spare区的ECC的生成 spare区的ECC状态寄存器为NFSECC
RnB_TransMode:RnB信号(对应的是nand芯片的忙碌or空闲信号R/B)的转变(包括有高电平降为低电平或者由低电平升为高电平)检测信号,当为0时上升沿检测。为1下降沿
EnbRnBINT:RnB信号状态输入信号转换中断控制寄存器;设置为1时,当RnB信号状态发生变换会触发中断。
EnbIllegalAccINT:非法存取中断寄存器,设置为0禁止非法存取中断。当cpu想要写入或者擦除nand锁存区数据的时候会发生非法存取中断。对于区域锁存看下一条。
Soft Lock:软件锁存配置寄存器,该位可用程序在任何时候做出改变,该位设置为1时,寄存器NFSBLK(存放的是nand要读取或者写入或者控制区域的的开始地址)到NFEBLK(存放的是nand要读取或者写入或者控制区域的结束地址)-1的这块区域存于不锁存状态,整块nand除了上面指定的其他区域写入命令或者数据全是无效的,但是可以读取数据。当用户想如写入或者擦除锁存地区时,就会出现非法存取错误。此时NFSTAT[3]将会置1,这里要注意的是,假如NFSBLK和NFEBLK的地址数据相同,那么整块nand将处于锁存状态。
Lock-tight:这个寄存器比较霸道,看到tight(紧密地,彻底地)应该可以感觉到他的压迫感。该位一旦被设置1,后面将无法清除该位(复位或者芯片由睡眠模式切换到工作模式该位可以被自动清除)。该位的功能与Soft Lock功能完全相同,只是SoftLock的值可以随时改变,Lock-tight却不可以。
nand的控制寄存器总算介绍完了,但是在将控制器的时候有提到main区ECC状态寄存器为NFMECC0/1、spare区的ECC状态寄存器为NFSECC、地址起始存放寄存器NFSBLK、地址结束存放寄存器NFEBLK,还有nand的状态寄存器NFSTAT,下面做出一一介绍。
首先对于8位nand flash,main区只有NFMECC0寄存器:
NFMECC0存放的8位nand flash的main区ECC,每读一次数据就对应一个ECC校验码,32位一共需要读4次(每次8位)。当对该寄存器进行读写的时候一定要确保maid去ecc处于非锁存状态也就是MainECCLock(NFCONT[5])为0。
①对于spare区的ECC状态寄存器为NFSECC,见下图:
对于8位nand,读取NFSECC【0到15】就可以,当对该寄存器进行读写的时候一定要确保main区ecc处于非锁存状态也就是SpareECCLock(NFCONT[6])为0。
②NFSECC和NFSBLK是相互搭配的寄存器,决定了nand规定块的开始和结束地址:
该寄存一次可以存放三块地址,其中2个8位的地址,1个16位的地址。其详细解释可以看对于NFCONF的介绍和结合下面的图来理解:
③对于and的状态寄存器NFSTAT,该寄存器主要是一切状态标记位,看一下图:
RnB:只读寄存器,当nand flash处于忙碌状态时,该位为0,处于可操作状态时该位为1
nCE:标记片选信号nCE引脚的状态
RnB_TransDetect:nand忙碌/空闲信号转换寄存器,当RnB由低电平变化为高电平(由忙碌变为空闲)时,该位会自动置1,如果此时使能中断的话(EnbRnBINT(NFCONF【9】)=1),还会触发中断信号,向该位写1清除数据。
IllegalAccess:一旦用户要编程或者擦除被锁存区域的数据,该位会自动置1
有关对nand的配置、控制寄存器及其关键的状态寄存器大概已经介绍完毕,通过上面的寄存器既可以完成nand的配置了。前面已经介绍过,nand只有8个io分时复用用来阐述命令,地址和数据,那么接下来存放这三个的有关寄存器
一个重要的例子(是关于ecc 非法访问产生中断,凑活看吧,以后继续):
http://blog.csdn.net/lianghongge/article/details/5965455
K9F2G08U0A nand flash 的容量为256M byte,其内部有2048块,每块有64页,每页有2K+64字节,其中每页会分为main区(主域)和spare区(备用域),main区一般用来存入主要数据,spare一般用来存放ECC校验码。 下面几点是编程时需要注意的: 1.NAND FLASH芯片手册里说的column是指页内地址,row是指页地址,page也是指页; 2.删除时是以块为单位的,但是删除块时写的是row地址,自动会删除row所在的块; 3.读写方式有页读写,或随机读写,所谓的随机读写就是可以在页内的任一地方读写一个字节; 4.ECC校验码分为main区的ECC和spare区的ECC,它们一般都会存放在64字节的spare区内,下面是翻译2440手册的关于ECC编程的内容: ECC 编程向导 1)在软件模式, ECC 模块会为全部读 / 写数据产生 ECC 检验码。所以你需要在读或者写数据前给 InitECC(NFCONT[4]) 位写 1 和给 MainECCLock(NFCONT[5]) 位写 0(Unlock) 来复位 ECC 值。 MainECCLock(NFCONT[5]) 和 SpareECCLock(NFCONT[6] 控制 ECC 校验码是否产生。 2)任何时候读或者写数据时, ECC 模块在 NFMECC0/1 上产生 ECC 校验码。 3)在你完成读或者写一个页后(不包含备用数据域),给 MainECCLock 位置 1(lock) 。 ECC 校验码被锁上, ECC 状态寄存器的值将不会被改变。 4)清 0(Unlock) SpareECCLock(NFCONT[6]) 位来产生备用域的 ECC 校验码。 5)任何时候读或者写数据时,备用域 ECC 模块在寄存器 NFSECC 上产生 ECC 校验码。 6)在完成读或者写备用域后,给 SpareECCLock 位置 1(lock) 。 ECC 校验码被锁上, ECC 状态寄存器的值将不会被改变。 7)一旦完成你就可以使用这些值来记录到备用域或者检测位错误。 接下来是代码: NAND-FLASH.H内容: /*********** 128K Pages 2048 Blocks 1 device = 2048 blocks =128k pages 1 block = 64 pages 1 page = (2k +64)bytes ***********/ #ifndef __NAND_FLASH_H__ #define __NAND_FLASH_H__ #include "lhg_def.h" //U8,U32相关的宏 #define MAX_NAND_BLOCK 2048 /*定义nand最大块数*/ #define NAND_PAGE_SIZE 2048 /*定义一页的容量*/ typedef struct nand_id_info //芯片的ID信息 { U8 IDm; //marker code U8 IDd; //device code U8 ID3rd; U8 ID4th; U8 ID5th; } nand_id_info; typedef struct bad_block_info //登记坏块用的 { U8 area[MAX_NAND_BLOCK];//0表示非坏块,1表示坏块 U32 sum;//坏块的总数 } bad_block_info; //NAND 操作指令 #define NAND_CMD_READ_1st 0x00 #define NAND_CMD_READ_2st 0x30 #define NAND_CMD_RANDOM_WRITE 0x85 #define NAND_CMD_RANDOM_READ_1st 0x05 #define NAND_CMD_RANDOM_READ_2st 0xe0 #define NAND_CMD_READ_CB_1st 0x00 #define NAND_CMD_READ_CB_2st 0x35 #define NAND_CMD_READ_ID 0x90 #define NAND_CMD_RES 0xff #define NAND_CMD_WRITE_PAGE_1st 0x80 #define NAND_CMD_WRITE_PAGE_2st 0x10 #define NAND_CMD_BLOCK_ERASE_1st 0x60 #define NAND_CMD_BLOCK_ERASE_2st 0xd0 #define NAND_CMD_READ_STATUS 0x70 //NAND 中断向量 #define INT_NFCON (24) //NFCONF HCLK=100MHZ #define S3C2440_NFCONF_TACLS_init (1<<12) #define S3C2440_NFCONF_TWRPH0_init (4<<8) #define S3C2440_NFCONF_TWRPH1_init (0<<4) #define S3C2440_NFCONF_BusWidth_init (0) /*8-bit bus 这里会根据GPG15硬件自行设置,也可以软件手动设置*/ #define S3C2440_NFCONF_init() ( rNFCONF = S3C2440_NFCONF_TACLS_init | / S3C2440_NFCONF_TWRPH0_init | / S3C2440_NFCONF_TWRPH1_init | / S3C2440_NFCONF_BusWidth_init ) //NFCONT #define S3C2440_NFCONT_LockTight_init (0<<13) #define S3C2440_NFCONT_SoftLock_init (0<<12) #define S3C2440_NFCONT_EnbIllegalAccINT_init (1<<10) /*enable Illegal INT*/ #define S3C2440_NFCONT_EnbRnBINT_init (0<<9) /*禁止Rnb中断*/ #define S3C2440_NFCONT_RnB_TransMode_init (0<<8) /*上升沿产生RnB中断*/ #define S3C2440_NFCONT_SpareECCLock_init (1<<6) #define S3C2440_NFCONT_MainECCLock_init (1<<5) #define S3C2440_NFCONT_InitECC_init (1<<4) #define S3C2440_NFCONT_Reg_nCE_init (1<<1) /*不选择nand flash芯片*/ #define S3C2440_NFCONT_MODE_init (0) /*NAND flash controller disable (Don’t work) 使用时在此处置1*/ #define S3C2440_NFCONT_init() (rNFCONT= S3C2440_NFCONT_LockTight_init | / S3C2440_NFCONT_SoftLock_init | / S3C2440_NFCONT_EnbIllegalAccINT_init | / S3C2440_NFCONT_EnbRnBINT_init | / S3C2440_NFCONT_RnB_TransMode_init | / S3C2440_NFCONT_SpareECCLock_init | / S3C2440_NFCONT_MainECCLock_init | / S3C2440_NFCONT_InitECC_init | / S3C2440_NFCONT_Reg_nCE_init | / S3C2440_NFCONT_MODE_init ) //NFSTAT #define S3C2440_NFSTAT_init() ( rNFSTAT &= 0x3 ) //NFESTAT0 #define S3C2440_NFESTAT0_init() ( rNFESTAT0 = 0 ) //NFESTAT1 #define S3C2440_NFESTAT1_init() ( rNFESTAT1 = 0 ) // #define select_nand() ( rNFCONT &= ~(1<<1) ) /*选择芯片*/ #define dis_select_nand() ( rNFCONT |= 1<<1 ) /*不选择芯片*/ #define controller_enable() ( rNFCONT |= 1 ) /*开控制*/ #define controller_disable() ( rNFCONT &= ~1 ) /*禁止控制*/ // extern void nand_flash_init(void); //初始化 extern int nand_block_erase(U32 num); //num要删除的块号 extern int nand_page_write(U32 addr,U8 *buffer,U32 size); //addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G extern int nand_page_read(U32 addr,U8 *buffer,U32 size); //addr开始页地址,从每页00地址开始读 extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //随机读数据 paddr页地址,offset页内偏移地址 extern int nand_random_write(U32 paddr,U32 offset,U8 data); //随机写,paddr页地址,offset页内偏移地址 extern void nand_test_bad_block(void);//测试坏块函数,并标记在nand_bbi变量里和spare区最后一个地址(如果非0xff则为坏块) #endif NAND-FLASH.c内容: /*********** 128K Pages 2048 Blocks 1 device = 2048 blocks =128k pages 1 block = 64 pages 1 page = (2k +64)bytes ***********/ #include "2440addr.h" #include "NAND-FLASH.h" #include "uart.h" #include "lhg_def.h" //#include "iic_lhg.h" #define NAND_DEBUG 1 #define USE_ECC 1 nand_id_info nand_id;//定义登记芯片ID的全局变量 bad_block_info nand_bbi;//定义来登记坏用的全局变量 void init_nand_bbi(void)//初始化变量 { U32 i; nand_bbi.sum=0; for (i=0;i<MAX_NAND_BLOCK;i++) nand_bbi.area[i]=0;// } void nand_mask_bad_block(U32 n)//标志坏块,n是坏块的块号 { #ifdef NAND_DEBUG Uart_Printf("NAND found and mask a bad block=%d .",n); #endif if (nand_bbi.area[n]!=1) { nand_bbi.area[n]=1; nand_bbi.sum++; nand_random_write(n*64,2048+64-1,0);//每块的第一个spare的最后一个字节,标志本块是否为坏块,非0xff为坏块 } } int detect_nand_busy(void)//检测是否忙 { U32 a; a=0; while(!(rNFSTAT&(1<<2))) { a++; if (a==5000000)//等待超时 { Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n"); rNFSTAT |= (1<<2);//清忙标志 return -1;//错误返回-1 } } rNFSTAT |= (1<<2);//清忙标志 return 1; } void nand_reset(void)//复位 { rNFCMD = NAND_CMD_RES; detect_nand_busy();//检测忙 } void control_start(void){ //开启 select_nand(); controller_enable(); rNFSTAT |= (1<<2);//清忙标志 nand_reset(); } void control_end(void) //关闭 { dis_select_nand(); controller_disable(); } void ecc_main_init(void)//初始化ECC值 { rNFCONT |= 1<<4;//initEcc } void ecc_main_start(void)//开始main ECC { rNFCONT &= ~(1<<5);//unlock } void ecc_main_end(void)//结束main ECC { rNFCONT |= 1<<5;//unlock } void ecc_spare_start(void)//开始spare ECC { // rNFCONT |= 1<<4; //initEcc rNFCONT &= ~(1<<6); //unlock } void ecc_spare_end(void)//结束spare ECC { rNFCONT |= 1<<6; //unlock } void __irq nandINT(void) //中断函数 { //此处写处理代码 #ifdef NAND_DEBUG Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有错误才会进入中断 #endif rSRCPND |= 0x1<<INT_NFCON; //清中断标志位 rINTPND |= 0x1<<INT_NFCON; //清中断标志位 } void nand_read_id(void)//读取芯片ID信息 { control_start();//开控制 rNFCMD = NAND_CMD_READ_ID; rNFADDR = 0; //读ID nand_id.IDm=(U8)rNFDATA8; nand_id.IDd=(U8)rNFDATA8; nand_id.ID3rd=(U8)rNFDATA8; nand_id.ID4th=(U8)rNFDATA8; nand_id.ID5th=(U8)rNFDATA8; #ifdef NAND_DEBUG Uart_Printf("/r/n Read NAND Flash ID:"); Uart_Printf("/r/n NAND Mark code: 0x%x ",nand_id.IDm);//打印ID信息 Uart_Printf("/r/n NAND Device code: 0x%x ",nand_id.IDd); Uart_Printf("/r/n NAND 3rdID code: 0x%x ",nand_id.ID3rd); Uart_Printf("/r/n NAND 4thID code: 0x%x ",nand_id.ID4th); Uart_Printf("/r/n NAND 5thID code: 0x%x ",nand_id.ID5th); #endif control_end();//关控制 } int nand_block_erase(U32 num)//num要删除的块号 { num=num*64; control_start();//开控制 nand_reset();//复位 rNFCMD = NAND_CMD_BLOCK_ERASE_1st; rNFADDR = num&0xff; rNFADDR = (num>>8)&0xff; rNFADDR = (num>>16)&0xff; rNFCMD = NAND_CMD_BLOCK_ERASE_2st; detect_nand_busy();// rNFCMD =NAND_CMD_READ_STATUS; //读状态 if (rNFDATA8&1) { #ifdef NAND_DEBUG Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64); #endif control_end();//关控制 nand_mask_bad_block(num/64);//登记为坏块 return -1;//删除错误返回0 } control_end();//关控制 #ifdef NAND_DEBUG Uart_Printf("/r/n NAND block %d erase completed.",num/64); #endif return 1; } int nand_page_write(U32 addr,U8 *buffer,U32 size) //addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G { U32 i,n,p,temp,ecc; U8 *bu; bu=buffer; temp=0; n=size/2048+(((size%2048)==0)?0:1); //计算出要写的页数,小于一页的部分当作一页 for (i=0;i<n;i++) { control_start();//开控制 nand_reset();//复位 #ifdef USE_ECC ecc_main_init(); ecc_main_start();//可以产生main区ECC #endif // detect_nand_busy();//检测忙 rNFCMD = NAND_CMD_WRITE_PAGE_1st; rNFADDR = 0; //从每页的0地址开始 rNFADDR = 0; //从每页的0地址开始 rNFADDR = (addr)&0xff; rNFADDR = (addr>>8)&0xff; rNFADDR = (addr>>16)&0xff; for (p=0;p<2048;p++)//写入一页 { temp=temp+1; if (temp>size) rNFDATA8 = 0xff;//多余的填写0xff else rNFDATA8 = *(bu+p); } delay_lhg(100,100);// #ifdef USE_ECC ecc_main_end();//锁定main区ecc ecc=rNFMECC0;//main ECC值写入备用区的头0~4个地址内 ecc_spare_start();//开始sprare区ECC rNFDATA8 = ecc&0xff; rNFDATA8 = (ecc>>8)&0xff; rNFDATA8 = (ecc>>16)&0xff; rNFDATA8 = (ecc>>24)&0xff; ecc_spare_end(); delay_lhg(100,100);// ecc = rNFSECC;//spare ECC值写入备用区的5~6两个地址内 rNFDATA8 = ecc&0xff; rNFDATA8 = (ecc>>8)&0xff; #endif bu=bu+2048;//页增量 addr++; rNFCMD = NAND_CMD_WRITE_PAGE_2st; detect_nand_busy();//检测忙 rNFCMD =NAND_CMD_READ_STATUS; //读状态 if (rNFDATA8&1) { #ifdef NAND_DEBUG Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1);//写入失败,以后改进 #endif control_end();//关控制 nand_mask_bad_block((addr-1)/64);//登记为坏块 return -1;//写入错误返回-1 } control_end();//关控制 } return 1;//成功返回1 } int nand_page_read(U32 addr,U8 *buffer,U32 size)//addr开始页地址,从每页00地址开始读 { U32 i,n,p,temp,ecc; U8 *bu,no; bu=buffer; temp=0; n=size/2048+(((size%2048)==0)?0:1); //计算出要读的页数,小于一页的部分当作一页 for (i=0;i<n;i++) { control_start();//开控制 nand_reset();//复位 #ifdef USE_ECC rNFESTAT0 = 0;//复位错误标志位 ecc_main_init(); ecc_main_start();//可以产生main区ECC #endif rNFCMD = NAND_CMD_READ_1st; rNFADDR = 0; rNFADDR = 0; rNFADDR = addr&0xff; rNFADDR = (addr>>8)&0xff; rNFADDR = (addr>>16)&0xff; rNFCMD = NAND_CMD_READ_2st; detect_nand_busy(); for (p=0;p<2048;p++) { temp=temp+1; if (temp>size) no=rNFDATA8;//多余的读出来扔掉 else *(bu+p) = rNFDATA8; } #ifdef USE_ECC rNFESTAT0=0; ecc_main_end();//锁定main区ECC delay_lhg(100,100);// ecc_spare_start();//解锁spare区ecc ecc=rNFDATA8;//从flash读出main区ECC no=rNFDATA8; ecc |= ((U32)no)<<8; no=rNFDATA8; ecc |= ((U32)no)<<16; no=rNFDATA8; ecc |= ((U32)no)<<24; rNFMECCD0 = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件检验main ECC rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16); ecc_spare_end();//锁定spare区ecc delay_lhg(100,100);// ecc=rNFDATA8;//从flash读出spare区ECC的值 no=rNFDATA8; ecc |= ((U32)no)<<8; rNFSECCD = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件检验spare ECC delay_lhg(100,100);//延时一会 ecc=rNFESTAT0&0xffffff;//ecc只是临时用一下错误状态,并非ecc内容 if (ecc!=0)//有错误 { //以后再优化 #ifdef NAND_DEBUG Uart_Printf("/r/n Nand ecc check error... page addr=0x%x,NFESTAT0=0x%x ",addr,ecc); #endif nand_mask_bad_block((addr+i)/64);//登记为坏块 return -1;// } #endif bu=bu+2048; addr++; control_end();//关控制 } return 1; } int nand_random_read(U32 paddr,U32 offset,U8 *data) //随机读数据 paddr页地址,offset页内偏移地址 { control_start();//开控制 nand_reset();//复位 rNFCMD = NAND_CMD_READ_1st; rNFADDR = 0; rNFADDR = 0; rNFADDR = paddr&0xff; rNFADDR = (paddr>>8)&0xff; rNFADDR = (paddr>>16)&0xff; rNFCMD = NAND_CMD_READ_2st; detect_nand_busy(); rNFCMD = NAND_CMD_RANDOM_READ_1st; rNFADDR = offset&0xff; //写入页内偏移地址 rNFADDR = (offset>>8)&0xff; rNFCMD = NAND_CMD_RANDOM_READ_2st; *data = rNFDATA8; control_end(); return 1; } int nand_random_write(U32 paddr,U32 offset,U8 data)//随机写,paddr页地址,offset页内偏移地址 { control_start();//开控制 nand_reset();//复位 rNFCMD = NAND_CMD_WRITE_PAGE_1st; rNFADDR = 0; rNFADDR = 0; rNFADDR = paddr&0xff; rNFADDR = (paddr>>8)&0xff; rNFADDR = (paddr>>16)&0xff; rNFCMD = NAND_CMD_RANDOM_WRITE; rNFADDR = offset&0xff; //写入页内偏移地址 rNFADDR = (offset>>8)&0xff; rNFDATA8 = data; rNFCMD = NAND_CMD_WRITE_PAGE_2st; detect_nand_busy();//检测忙 rNFCMD =NAND_CMD_READ_STATUS; //读状态 if (rNFDATA8&1) { #ifdef NAND_DEBUG Uart_Printf("/r/n Error:nand random write error... paddr=0x%x,offset=0x%x ",paddr,offset); #endif return -1;//删除错误返回0 } control_end(); return 1;//成功返回1 } void nand_test_bad_block(void)//测试坏块函数,并标记spare区最后一个地址,如果非0xff则为坏块 { U8 dest[64*2048];//一个块的main区容量 U8 src [64*2048]; U32 i,k; #ifdef NAND_DEBUG Uart_Printf("/r/n test and mask bad block is begain. /r/n"); #endif // //main区检测 for (i=0;i<64*2048;i++) { dest[i]=0xff;//初始化缓冲区 src [i]=0; } //删除所有块 for (i=0;i<MAX_NAND_BLOCK;i++) { nand_block_erase(i); } for (i=0;i<MAX_NAND_BLOCK;i++)//测试所有块的main区是否有坏块 { nand_page_write(i*64,src,64*2048); nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息 } for (i=0;i<64*2048;i++) { dest[i]=0;//初始化缓冲区 src [i]=0xff; } //删除所有块 for (i=0;i<MAX_NAND_BLOCK;i++) { nand_block_erase(i); } for (i=0;i<MAX_NAND_BLOCK;i++)//测试所有块的main区是否有坏块 { nand_page_write(i*64,src,64*2048); nand_page_read(i*64,dest,64*2048);//使用了ecc校验读出来即可登记坏块信息 } // //spare区检测 for (i=0;i<64;i++) { dest[i]=0xff;//初始化缓冲区 src [i]=0; } //删除所有块 for (i=0;i<MAX_NAND_BLOCK;i++) { nand_block_erase(i); } for (i=0;i<MAX_NAND_BLOCK*64;i++)//测试所有块的spare区是否有坏块 { if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过 continue; for (k=0;k<64;k++) { nand_random_write(i,2048+k,src[k]); nand_random_read(i,2048+k,&dest[k]); if (dest[k]!=src[k])//不相等则登记为坏块 { nand_mask_bad_block(i/64); break; } } } for (i=0;i<64;i++) { dest[i]=0x0;//初始化缓冲区 src [i]=0xff; } //删除所有块 for (i=0;i<MAX_NAND_BLOCK;i++) { nand_block_erase(i); } for (i=0;i<MAX_NAND_BLOCK*64;i++)//测试所有块的spare区是否有坏块 { if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过 continue; for (k=0;k<64;k++) { nand_random_write(i,2048+k,src[k]); nand_random_read(i,2048+k,&dest[k]); if (dest[k]!=src[k])//不相等则登记为坏块 { nand_mask_bad_block(i/64); break; } } } #ifdef NAND_DEBUG Uart_Printf("/r/n test and mask bad block is over. /r/n"); #endif } void nand_flash_init(void)//初始化 { #ifdef NAND_DEBUG Uart_Printf("/r/nNAND FLASH init");// #endif //中断入口地址 pISR_NFCON = (U32)nandINT; //配置GPIO rGPGUP |= 0x7<<13; //GPG13~15关闭上位 rGPGCON &= ~((U32)0x3f<<26);//GPG13~15为输入 //初始化各寄存器 S3C2440_NFCONF_init(); S3C2440_NFCONT_init(); S3C2440_NFSTAT_init(); S3C2440_NFESTAT0_init(); S3C2440_NFESTAT1_init(); //关于中断 rINTMSK &= ~(0x1<<INT_NFCON) ; //中断 rINTMOD &= ~(0x1<<INT_NFCON); //IRQ rSRCPND |= 0x1<<INT_NFCON; //清中断标志位 rINTPND |= 0x1<<INT_NFCON; //清中断标志位 init_nand_bbi();//初始化全局变量 nand_read_id();//读ID nand_test_bad_block();//测试并登记坏块 }