NANDFlashd的讀寫(基于s3c2440)
本文引用地址:http://m.butianyuan.cn/article/201611/318935.htm
- #ifndef__TEST_H__
- #define__TEST_H__
- #include"def.h"
- #defineMAX_NAND_BLOCK2048//一共2048塊
- #defineNAND_PAGE_SIZE2048//每塊main區(qū)2k字節(jié)=2048
- typedefstructnand_id_info//芯片的ID信息
- {
- U8IDm;//廠商ID
- U8IDd;//設(shè)備ID
- U8ID3rd;
- U8ID4th;
- U8ID5th;
- }nand_id_info;
- typedefstructbad_block_info//登記壞塊
- {
- U8area[MAX_NAND_BLOCK];//0表示非壞塊,1表示壞塊
- U32sum;//壞塊的總數(shù)
- }bad_block_info;
- //NAND操作指令
- #defineNAND_CMD_READ_1st0x00
- #defineNAND_CMD_READ_2st0x30
- #defineNAND_CMD_RANDOM_WRITE0x85//隨機(jī)寫
- #defineNAND_CMD_RANDOM_READ_1st0x05
- #defineNAND_CMD_RANDOM_READ_2st0xe0
- #defineNAND_CMD_READ_CB_1st0x00//將NAND里一塊內(nèi)容寫進(jìn)另一塊
- #defineNAND_CMD_READ_CB_2st0x35
- #defineNAND_CMD_READ_ID0x90
- #defineNAND_CMD_RES0xff//復(fù)位命令
- #defineNAND_CMD_WRITE_PAGE_1st0x80
- #defineNAND_CMD_WRITE_PAGE_2st0x10
- #defineNAND_CMD_BLOCK_ERASE_1st0x60//擦除命令
- #defineNAND_CMD_BLOCK_ERASE_2st0xd0
- #defineNAND_CMD_READ_STATUS0x70
- //NAND中斷向量
- #defineINT_NFCON24
- //NFCONFHCLK=100MHZ
- #defineS3C2440_NFCONF_TACLS_init(1<<12)
- #defineS3C2440_NFCONF_TWRPH0_init(4<<8)
- #defineS3C2440_NFCONF_TWRPH1_init(0<<4)
- #defineS3C2440_NFCONF_BusWidth_init(0)
- #defineS3C2440_NFCONF_init()(rNFCONF=S3C2440_NFCONF_TACLS_init|/
- S3C2440_NFCONF_TWRPH0_init|/
- S3C2440_NFCONF_TWRPH1_init|/
- S3C2440_NFCONF_BusWidth_init)
- //NFCONT
- #defineS3C2440_NFCONT_LockTight_init(0<<13)
- #defineS3C2440_NFCONT_SoftLock_init(0<<12)
- #defineS3C2440_NFCONT_EnbIllegalAccINT_init(1<<10)
- #defineS3C2440_NFCONT_EnbRnBINT_init(0<<9)
- #defineS3C2440_NFCONT_RnB_TransMode_init(0<<8)
- #defineS3C2440_NFCONT_SpareECCLock_init(1<<6)
- #defineS3C2440_NFCONT_MainECCLock_init(1<<5)
- #defineS3C2440_NFCONT_InitECC_init(1<<4)
- #defineS3C2440_NFCONT_Reg_nCE_init(1<<1)//初始配置片選無效
- #defineS3C2440_NFCONT_MODE_init(0)
- #defineS3C2440_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
- #defineS3C2440_NFSTAT_init()(rNFSTAT&=0x3)
- //NFESTAT0
- #defineS3C2440_NFESTAT0_init()(rNFESTAT0=0)
- //NFESTAT1
- #defineS3C2440_NFESTAT1_init()(rNFESTAT1=0)
- //
- #defineselect_nand()(rNFCONT&=~(1<<1))
- #definedis_select_nand()(rNFCONT|=1<<1)
- #definecontroller_enable()(rNFCONT|=1)
- #definecontroller_disable()(rNFCONT&=~1)
- //
- voidnand_flash_init(void);//初始化
- voidnand_read_id(void);
- externintnand_block_erase(U32num);//num要?jiǎng)h除的塊號(hào)
- externintnand_page_write(U32addr,U8*buffer,U32size);//addr要寫的起始頁地址,buffer要寫的緩存,size要寫的字節(jié)大小最大為4G
- externintnand_page_read(U32addr,U8*buffer,U32size);//addr開始頁地址,從每頁00地址開始讀
- externintnand_random_read(U32paddr,U32offset,U8*data);//隨機(jī)讀數(shù)據(jù)paddr頁地址,offset頁內(nèi)偏移地址
- externintnand_random_write(U32paddr,U32offset,U8data);//隨機(jī)寫,paddr頁地址,offset頁內(nèi)區(qū)最后一個(gè)地偏移地址
- externvoidnand_test_bad_block(void);//測(cè)試壞塊函數(shù),并標(biāo)記在nand_bbi變量里和spare里(如果非0xff則為壞塊)
- #endif
- #include"2440addr.h"
- #include"test.h"
- #include"def.h"
- #defineNAND_DEBUG1//打印一些串口調(diào)試信息
- #defineUSE_ECC1//使用ECC驗(yàn)證
- nand_id_infonand_id;//定義登記芯片ID的全局變量
- bad_block_infonand_bbi;//定義來登記壞的全局變量
- voidinit_nand_bbi(void)//初始化變量
- {
- U32i;
- nand_bbi.sum=0;
- for(i=0;i
- nand_bbi.area[i]=0;//全部初始化為0
- }
- voidnand_mask_bad_block(U32n)//標(biāo)志壞塊,n是壞塊的塊號(hào)
- {
- #ifdefNAND_DEBUG
- Uart_Printf("NANDfoundandmaskabadblock=%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);//每塊的第一個(gè)spare的最后一個(gè)字節(jié),標(biāo)志本塊是否為壞塊,非0xff為壞塊
- }
- }
- intdetect_nand_busy(void)//檢測(cè)是否忙
- {
- U32a;
- a=0;
- while(!(rNFSTAT&(1<<2)))
- {
- a++;
- if(a==5000000)//等待超時(shí)
- {
- Uart_Printf("/r/nError:DetectNandBusytimeout!!!/r/n");
- rNFSTAT|=(1<<2);//清忙標(biāo)志
- return-1;//錯(cuò)誤返回-1
- }
- }
- rNFSTAT|=(1<<2);//清忙標(biāo)志
- return1;
- }
- voidnand_reset(void)//NAND復(fù)位
- {
- rNFCMD=NAND_CMD_RES;
- detect_nand_busy();//檢測(cè)忙
- }
- voidcontrol_start(void)//芯片開啟
- {
- select_nand();
- controller_enable();
- rNFSTAT|=(1<<2);//清忙標(biāo)志
- nand_reset();
- }
- voidcontrol_end(void)//芯片關(guān)閉
- {
- dis_select_nand();
- controller_disable();
- }
- voidecc_main_init(void)//初始化ECC值
- {
- rNFCONT|=1<<4;//initEcc
- }
- voidecc_main_start(void)//開鎖mainECC
- {
- rNFCONT&=~(1<<5);//unlock
- }
- voidecc_main_end(void)//鎖定mainECC
- {
- rNFCONT|=1<<5;//lock
- }
- voidecc_spare_start(void)//開鎖spareECC
- {
- rNFCONT&=~(1<<6);//unlock
- }
- voidecc_spare_end(void)//鎖定spareECC
- {
- rNFCONT|=1<<6;//lock
- }
- void__irqnandINT(void)//NAND中斷函數(shù)
- {
- //此處寫處理代碼
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nNandError...Ininterruptnow!!!");//只有錯(cuò)誤才會(huì)進(jìn)入中斷
- #endif
- rSRCPND|=0x1<
- rINTPND|=0x1<
- }
- voidnand_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;
- //打印ID信息
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nReadNANDFlashID:");
- Uart_Printf("/r/nNANDMarkcode:0x%x",nand_id.IDm);
- Uart_Printf("/r/nNANDDevicecode:0x%x",nand_id.IDd);
- Uart_Printf("/r/nNAND3rdIDcode:0x%x",nand_id.ID3rd);
- Uart_Printf("/r/nNAND4thIDcode:0x%x",nand_id.ID4th);
- Uart_Printf("/r/nNAND5thIDcode:0x%x",nand_id.ID5th);
- #endif
- control_end();//關(guān)控制
- }
- //擦出時(shí)只要給定塊所在頁的地址,就能擦除整個(gè)塊
- intnand_block_erase(U32num)//num要?jiǎng)h除的塊號(hào)
- {
- num=num*64;//每塊的第一頁
- control_start();//開控制
- nand_reset();//復(fù)位
- 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;//讀狀態(tài)
- if(rNFDATA8&1)//最低位可以判斷擦除和寫是否成功
- {
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nError:nanderaseerror...block=0x%x",num/64);
- #endif
- control_end();//關(guān)控制
- nand_mask_bad_block(num/64);//登記為壞塊
- return-1;//刪除錯(cuò)誤返回0
- }
- control_end();//關(guān)控制
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nNANDblock%derasecompleted.",num/64);
- #endif
- return1;//擦除成功
- }
- intnand_page_write(U32addr,U8*buffer,U32size)//addr要寫的起始頁地址,buffer要寫的緩存,size要寫的字節(jié)大小最大為4G
- {
- U32i,n,p,temp,ecc;
- U8*bu;
- bu=buffer;
- temp=0;
- n=size/2048+(((size%2048)==0)?0:1);//計(jì)算出要寫的頁數(shù),小于一頁的部分當(dāng)作一頁
- for(i=0;i
- {
- control_start();//開控制
- nand_reset();//復(fù)位
- #ifdefUSE_ECC
- ecc_main_init();
- ecc_main_start();//可以產(chǎn)生main區(qū)ECC
- #endif
- 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);//
- #ifdefUSE_ECC
- ecc_main_end();//鎖定main區(qū)ecc
- ecc=rNFMECC0;
- ecc_spare_start();//解鎖spare區(qū)ECC
- //mainECC值寫入備用區(qū)的頭0~4個(gè)地址內(nèi)
- rNFDATA8=ecc&0xff;
- rNFDATA8=(ecc>>8)&0xff;
- rNFDATA8=(ecc>>16)&0xff;
- rNFDATA8=(ecc>>24)&0xff;
- ecc_spare_end();//鎖定spare區(qū)ECC
- //delay_lhg(100,100);//
- ecc=rNFSECC;//spareECC值寫入備用區(qū)的5~6兩個(gè)地址內(nèi)
- rNFDATA8=ecc&0xff;
- rNFDATA8=(ecc>>8)&0xff;
- #endif
- bu=bu+2048;//頁增量
- addr++;
- rNFCMD=NAND_CMD_WRITE_PAGE_2st;
- detect_nand_busy();//檢測(cè)忙
- rNFCMD=NAND_CMD_READ_STATUS;//讀狀態(tài)
- if(rNFDATA8&1)
- {
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nnandwritepageerror:pageaddr=0x%d",addr-1);//寫入失敗,以后改進(jìn)
- #endif
- control_end();//關(guān)控制
- nand_mask_bad_block((addr-1)/64);//登記為壞塊
- return-1;//寫入錯(cuò)誤返回-1
- }
- control_end();//關(guān)控制
- }
- return1;//成功返回1
- }
- intnand_page_read(U32addr,U8*buffer,U32size)//addr開始頁地址,從每頁00地址開始讀,size為需要讀的字節(jié)數(shù)
- {
- U32i,n,p,temp,ecc;
- U8*bu,no;
- bu=buffer;
- temp=0;
- n=size/2048+(((size%2048)==0)?0:1);//計(jì)算出要讀的頁數(shù),小于一頁的部分當(dāng)作一頁
- for(i=0;i
- {
- control_start();//開控制
- nand_reset();//復(fù)位
- #ifdefUSE_ECC
- rNFESTAT0=0;//復(fù)位錯(cuò)誤標(biāo)志位
- ecc_main_init();
- ecc_main_start();//可以產(chǎn)生main區(qū)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;
- }
- }
- #ifdefUSE_ECC
- rNFESTAT0=0;
- ecc_main_end();//鎖定main區(qū)ECC
- //delay_lhg(100,100);//
- ecc_spare_start();//解鎖spare區(qū)ecc
- ecc=rNFDATA8;//從flash讀出main區(qū)ECC,四個(gè)字節(jié)
- no=rNFDATA8;
- ecc|=((U32)no)<<8;
- no=rNFDATA8;
- ecc|=((U32)no)<<16;
- no=rNFDATA8;
- ecc|=((U32)no)<<24;
- rNFMECCD0=((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)mainECC
- rNFMECCD1=((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16);
- ecc_spare_end();//鎖定spare區(qū)ecc
- //delay_lhg(100,100);//
- ecc=rNFDATA8;//從flash讀出spare區(qū)ECC的值
- no=rNFDATA8;
- ecc|=((U32)no)<<8;
- rNFSECCD=((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)spareECC
- //delay_lhg(100,100);//延時(shí)一會(huì)
- ecc=rNFESTAT0&0xffffff;//ecc只是臨時(shí)用一下錯(cuò)誤狀態(tài),并非ecc內(nèi)容
- if(ecc!=0)//有錯(cuò)誤
- {
- //以后再優(yōu)化
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nNandecccheckerror...pageaddr=0x%x,NFESTAT0=0x%x",addr,ecc);
- #endif
- nand_mask_bad_block((addr+i)/64);//登記為壞塊
- return-1;
- }
- #endif
- bu=bu+2048;
- addr++;
- control_end();//關(guān)控制
- }
- return1;
- }
- intnand_random_read(U32paddr,U32offset,U8*data)//隨機(jī)讀數(shù)據(jù)paddr頁地址,offset頁內(nèi)偏移地址
- {
- control_start();//開控制
- nand_reset();//復(fù)位
- 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;//寫入頁內(nèi)偏移地址
- rNFADDR=(offset>>8)&0xff;
- rNFCMD=NAND_CMD_RANDOM_READ_2st;
- *data=rNFDATA8;
- control_end();
- return1;
- }
- intnand_random_write(U32paddr,U32offset,U8data)//隨機(jī)寫,paddr頁地址,offset頁內(nèi)偏移地址
- {
- control_start();//開控制
- nand_reset();//復(fù)位
- 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;//寫入頁內(nèi)偏移地址
- rNFADDR=(offset>>8)&0xff;
- rNFDATA8=data;
- rNFCMD=NAND_CMD_WRITE_PAGE_2st;
- detect_nand_busy();//檢測(cè)忙
- rNFCMD=NAND_CMD_READ_STATUS;//讀狀態(tài)
- if(rNFDATA8&1)
- {
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nError:nandrandomwriteerror...paddr=0x%x,offset=0x%x",paddr,offset);
- #endif
- return-1;//刪除錯(cuò)誤返回0
- }
- control_end();
- return1;//成功返回1
- }
- voidnand_test_bad_block(void)//測(cè)試壞塊函數(shù),并標(biāo)記spare區(qū)最后一個(gè)地址,如果非0xff則為壞塊
- {
- U8dest[64*2048];//一個(gè)塊的main區(qū)容量
- U8src[64*2048];
- U32i,k;
- #ifdefNAND_DEBUG
- Uart_Printf("/r/ntestandmaskbadblockisbegain./r/n");
- #endif
- //main區(qū)檢測(cè)
- for(i=0;i<64*2048;i++)
- {
- dest[i]=0xff;//初始化緩沖區(qū)
- src[i]=0;
- }
- //刪除所有塊
- for(i=0;i
- {
- nand_block_erase(i);
- }
- for(i=0;i
- {
- nand_page_write(i*64,src,64*2048);
- nand_page_read(i*64,dest,64*2048);//使用了ecc校驗(yàn)讀出來即可登記壞塊信息
- }
- for(i=0;i<64*2048;i++)
- {
- dest[i]=0;//初始化緩沖區(qū)
- src[i]=0xff;
- }
- //刪除所有塊
- for(i=0;i
- {
- nand_block_erase(i);
- }
- for(i=0;i
- {
- nand_page_write(i*64,src,64*2048);
- nand_page_read(i*64,dest,64*2048);//使用了ecc校驗(yàn)讀出來即可登記壞塊信息
- }
- //
- //spare區(qū)檢測(cè)
- for(i=0;i<64;i++)
- {
- dest[i]=0xff;//初始化緩沖區(qū)
- src[i]=0;
- }
- //刪除所有塊
- for(i=0;i
- {
- nand_block_erase(i);
- }
- for(i=0;i
- {
- 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;//初始化緩沖區(qū)
- src[i]=0xff;
- }
- //刪除所有塊
- for(i=0;i
- {
- nand_block_erase(i);
- }
- for(i=0;i
- {
- 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;
- }
- }
- }
- #ifdefNAND_DEBUG
- Uart_Printf("/r/ntestandmaskbadblockisover./r/n");
- #endif
- }
- voidnand_flash_init(void)//初始化
- {
- #ifdefNAND_DEBUG
- Uart_Printf("/r/nNANDFLASHinit");//
- #endif
- //中斷入口地址
- pISR_NFCON=(U32)nandINT;
- //配置GPIO
- rGPGUP|=0x7<<13;//GPG13~15關(guān)閉上位
- rGPGCON&=~((U32)0x3f<<26);//GPG13~15為輸入
- //初始化各寄存器
- S3C2440_NFCONF_init();
- S3C2440_NFCONT_init();
- S3C2440_NFSTAT_init();
- S3C2440_NFESTAT0_init();
- S3C2440_NFESTAT1_init();
- //關(guān)于中斷
- rINTMSK&=~(0x1<
- rINTMOD&=~(0x1<
- rSRCPND|=0x1<
- rINTPND|=0x1<
- //init_nand_bbi();//初始化全局變量
- nand_read_id();//讀ID
- //nand_test_bad_block();//測(cè)試并登記壞塊
- }
評(píng)論