<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > S3C2440對(duì)Nand Flash操作和電路原理(基于K9F2G08U0A)

          S3C2440對(duì)Nand Flash操作和電路原理(基于K9F2G08U0A)

          作者: 時(shí)間:2016-11-26 來(lái)源:網(wǎng)絡(luò) 收藏

          下面就開(kāi)始詳細(xì)介紹K9F2G08U0A的基本操作,包括復(fù)位,讀ID,頁(yè)讀、寫(xiě)數(shù)據(jù),隨意讀、寫(xiě)數(shù)據(jù),塊擦除等。

          為了更好地應(yīng)用ECC和使能Nand Flash片選,我們還需要一些宏定義:

          #define NF_nFCE_L(){rNFCONT &= ~(1<<1); }

          #define NF_CE_L()NF_nFCE_L()//打開(kāi)nandflash片選

          #define NF_nFCE_H(){rNFCONT |= (1<<1); }

          #define NF_CE_H() NF_nFCE_H() //關(guān)閉nandflash片選

          #define NF_RSTECC(){rNFCONT |= (1<<4); }//復(fù)位ECC

          #define NF_MECC_UnLock(){rNFCONT &= ~(1<<5); }//解鎖main區(qū)ECC

          #define NF_MECC_Lock(){rNFCONT |= (1<<5); }//鎖定main區(qū)ECC

          #define NF_SECC_UnLock() {rNFCONT &= ~(1<<6); }//解鎖spare區(qū)ECC

          #define NF_SECC_Lock(){rNFCONT |= (1<<6); }//鎖定spare區(qū)ECC

          NFSTAT是另一個(gè)比較重要的寄存器,它的第0位可以用于判斷nandflash是否在忙,第2位用于檢測(cè)RnB引腳信號(hào):

          #define NF_WAITRB(){while(!(rNFSTAT&(1<<0)));} //等待Nand Flash不忙

          #define NF_CLEAR_RB(){rNFSTAT |= (1<<2); }//清除RnB信號(hào)

          #define NF_DETECT_RB(){while(!(rNFSTAT&(1<<2)));}

          //等待RnB信號(hào)變高,即不忙

          NFCMMD,NFADDR和NFDATA分別用于傳輸命令,地址和數(shù)據(jù),為了方便起見(jiàn),我們可以定義一些宏定義用于完成上述操作:

          #define NF_CMD(data) {rNFCMD = (data); }//傳輸命令

          #define NF_ADDR(addr){rNFADDR = (addr); }//傳輸?shù)刂?p>#define NF_RDDATA() rNFDATA) //讀32位數(shù)據(jù)

          #define NF_RDDATA8()(rNFDATA8)//讀8位數(shù)據(jù)

          #define NF_WRDATA(data){rNFDATA = (data); }//寫(xiě)32位數(shù)據(jù)

          #define NF_WRDATA8(data) {rNFDATA8 = (data); }//寫(xiě)8位數(shù)據(jù)

          首先,是初始化操作

          void rNF_Init(void)

          {

          rNFCONF = (TACLS<<12)|(TWRPH0<<8)|( TWRPH1<<4)|(0<<0);//初始化時(shí)序參數(shù)

          rNFCONT =

          (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); //非鎖定,屏蔽nandflash中斷,初始化ECC及鎖定main區(qū)和spare區(qū)ECC,使能nandflash片選及控制器

          rNF_Reset();//復(fù)位芯片

          }

          復(fù)位操作,寫(xiě)入復(fù)位命令

          static void rNF_Reset()

          {

          NF_CE_L();//打開(kāi)nandflash片選

          NF_CLEAR_RB();//清除RnB信號(hào)

          NF_CMD(CMD_RESET); //寫(xiě)入復(fù)位命令

          NF_DETECT_RB();//等待RnB信號(hào)變高,即不忙

          NF_CE_H();//關(guān)閉nandflash片選

          }

          讀取K9F2G08U0A芯片ID的操作如下:時(shí)序圖在datasheet的figure18。首先需要寫(xiě)入讀ID命令(0x90),然后再寫(xiě)入0x00地址,并等待芯片就緒,就可以讀取到一共五個(gè)周期的芯片ID,第一個(gè)周期為廠商ID,第二個(gè)周期為設(shè)備ID,第三個(gè)周期至第五個(gè)周期包括了一些具體的該芯片信息,函數(shù)如下

          static char rNF_ReadID()

          {

          char pMID;

          char pDID;

          char cyc3, cyc4, cyc5;

          NF_nFCE_L();//打開(kāi)nandflash片選

          NF_CLEAR_RB();//清RnB信號(hào)

          NF_CMD(CMD_READID);//讀ID命令

          NF_ADDR(0x0); //寫(xiě)0x00地址

          for ( i = 0; i < 100; i++ );等一段時(shí)間

          //讀五個(gè)周期的ID

          pMID = NF_RDDATA8();//廠商ID:0xEC

          pDID = NF_RDDATA8();//設(shè)備ID:0xDA

          cyc3 = NF_RDDATA8();//0x10

          cyc4 = NF_RDDATA8();//0x95

          cyc5 = NF_RDDATA8();//0x44

          NF_nFCE_H();//關(guān)閉nandflash片選

          return (pDID);

          }

          下面介紹Nand Flash讀操作,讀操作是以頁(yè)為單位進(jìn)行的。如果在讀取數(shù)據(jù)的過(guò)程中不進(jìn)行ECC校驗(yàn)判斷,則讀操作比較簡(jiǎn)單,在寫(xiě)入讀命令的兩個(gè)周期之間寫(xiě)入要讀取的頁(yè)地址,然后讀取數(shù)據(jù)即可。如果為了更準(zhǔn)確地讀取數(shù)據(jù),則在讀取完數(shù)據(jù)之后還要進(jìn)行ECC校驗(yàn)判斷,以確定所讀取的數(shù)據(jù)是否正確。

          在上文中已經(jīng)介紹過(guò),Nand Flash的每一頁(yè)有兩區(qū):main區(qū)和spare區(qū),main區(qū)用于存儲(chǔ)正常的數(shù)據(jù),spare區(qū)用于存儲(chǔ)其他附加信息,其中就包括ECC校驗(yàn)碼。當(dāng)我們?cè)趯?xiě)入數(shù)據(jù)的時(shí)候,我們就計(jì)算這一頁(yè)數(shù)據(jù)的ECC校驗(yàn)碼,然后把校驗(yàn)碼存儲(chǔ)到spare區(qū)的特定位置中,在下次讀取這一頁(yè)數(shù)據(jù)的時(shí)候,同樣我們也計(jì)算ECC校驗(yàn)碼,然后與spare區(qū)中的ECC校驗(yàn)碼比較,如果一致則說(shuō)明讀取的數(shù)據(jù)正確,如果不一致則不正確。ECC的算法較為復(fù)雜,好在S3C2440能夠硬件產(chǎn)生ECC校驗(yàn)碼,這樣就省去了不少的麻煩事。S3C2440既可以產(chǎn)生main區(qū)的ECC校驗(yàn)碼,也可以產(chǎn)生spare區(qū)的ECC校驗(yàn)碼。因?yàn)镵9F2G08U0A是8位IO口,因此S3C2440共產(chǎn)生4個(gè)字節(jié)的main區(qū)ECC碼和2個(gè)字節(jié)的spare區(qū)ECC碼。在這里我們規(guī)定,在每一頁(yè)的spare區(qū)的第0個(gè)地址到第3個(gè)地址存儲(chǔ)main區(qū)ECC,第4個(gè)地址和第5個(gè)地址存儲(chǔ)spare區(qū)ECC。

          產(chǎn)生ECC校驗(yàn)碼的過(guò)程為:在讀取或?qū)懭肽膫€(gè)區(qū)的數(shù)據(jù)之前,先解鎖該區(qū)的ECC,以便產(chǎn)生該區(qū)的ECC。在讀取或?qū)懭胪陻?shù)據(jù)之后,再鎖定該區(qū)的ECC,這樣系統(tǒng)就會(huì)把產(chǎn)生的ECC碼保存到相應(yīng)的寄存器中。main區(qū)的ECC保存到NFMECC0/1中(因?yàn)镵9F2G08U0A是8位IO口,因此這里只用到了NFMECC0),spare區(qū)的ECC保存到NFSECC中。對(duì)于讀操作來(lái)說(shuō),我們還要繼續(xù)讀取spare區(qū)的相應(yīng)地址內(nèi)容,以得到上次寫(xiě)操作時(shí)所存儲(chǔ)的main區(qū)和spare區(qū)的ECC,并把這些數(shù)據(jù)分別放入NFMECCD0/1和NFSECCD的相應(yīng)位置中。最后我們就可以通過(guò)讀取NFESTAT0/1(因?yàn)镵9F2G08U0A是8位IO口,因此這里只用到了NFESTAT0)中的低4位來(lái)判斷讀取的數(shù)據(jù)是否正確,其中第0位和第1位為main區(qū)指示錯(cuò)誤,第2位和第3位為spare區(qū)指示錯(cuò)誤。

          下面是一段具體的頁(yè)讀操作程序:

          U8 rNF_ReadPage( U32 page_number )

          {

          U32 i, mecc0, secc;

          NF_RSTECC();//復(fù)位ECC

          NF_MECC_UnLock(); //解鎖main區(qū)ECC

          NF_nFCE_L();//使能芯片

          NF_CLEAR_RB();//清除RnB

          NF_CMD(CMD_READ1); //頁(yè)讀命令周期1,0x00

          //寫(xiě)入5個(gè)地址周期

          NF_ADDR(0x00); //列地址A0-A7

          NF_ADDR(0x00); //列地址A8-A11

          NF_ADDR((addr) & 0xff); //行地址A12-A19

          NF_ADDR((addr >> 8) & 0xff); //行地址A20-A27

          NF_ADDR((addr >> 16) & 0xff); //行地址A28

          NF_CMD(CMD_READ2); //頁(yè)讀命令周期2,0x30

          NF_DETECT_RB(); ////等待RnB信號(hào)變高,即不忙

          for (i = 0; i < 2048; i++)

          {

          buf[i] = NF_RDDATA8();//讀取一頁(yè)數(shù)據(jù)內(nèi)容

          }

          NF_MECC_Lock();//鎖定main區(qū)ECC值

          NF_SECC_UnLock();//解鎖spare區(qū)ECC

          mecc0=NF_RDDATA();//讀spare區(qū)的前4個(gè)地址內(nèi)容,即第2048~2051地址,這4個(gè)字節(jié)為main區(qū)的ECC

          //把讀取到的main區(qū)的ECC校驗(yàn)碼放入NFMECCD0/1的相應(yīng)位置內(nèi)

          rNFMECCD0=((mecc0&0xff00)<<8)|(mecc0&0xff);

          rNFMECCD1=((mecc0&0xff000000)>>8)|((mecc0&0xff0000)>>16);

          NF_SECC_Lock();//鎖定spare區(qū)的ECC值

          secc=NF_RDDATA();//繼續(xù)讀spare區(qū)的4個(gè)地址內(nèi)容,即第2052~2055地址,其中前2個(gè)字節(jié)為spare區(qū)的ECC值

          //把讀取到的spare區(qū)的ECC校驗(yàn)碼放入NFSECCD的相應(yīng)位置內(nèi)

          rNFSECCD=((secc&0xff00)<<8)|(secc&0xff);

          NF_nFCE_H();//關(guān)閉nandflash片選

          //判斷所讀取到的數(shù)據(jù)是否正確

          if ((rNFESTAT0&0xf) == 0x0)

          return 0x66; //正確

          else

          return 0x44; //錯(cuò)誤

          }

          這段程序是把某一頁(yè)的內(nèi)容讀取到全局變量數(shù)組buffer中。該程序的輸入?yún)?shù)直接就為K9F2G08U0A的第幾頁(yè),例如我們要讀取第128064頁(yè)中的內(nèi)容,可以調(diào)用該程序?yàn)椋簉NF_ReadPage(128064)。由于第128064頁(yè)是第2001塊中的第0頁(yè)(128064=2001×64+0),所以為了更清楚地表示頁(yè)與塊之間的關(guān)系,也可以寫(xiě)為:rNF_ReadPage(2001*64)。

          頁(yè)寫(xiě)操作的大致流程為:在兩個(gè)寫(xiě)命令周期之間分別寫(xiě)入頁(yè)地址和數(shù)據(jù),當(dāng)然如果為了保證下次讀取該數(shù)據(jù)時(shí)的正確性,還需要把main區(qū)的ECC值和spare區(qū)的ECC值寫(xiě)入到該頁(yè)的spare區(qū)內(nèi)。然后我們還需要讀取狀態(tài)寄存器,以判斷這次寫(xiě)操作是否正確。下面就給出一段具體的頁(yè)寫(xiě)操作程序,其中輸入?yún)?shù)也是要寫(xiě)入數(shù)據(jù)到第幾頁(yè):

          U8 rNF_WritePage(U32 page_number)

          {

          U32 i, mecc0, secc;

          U8 stat, temp;

          temp = rNF_IsBadBlock(page_number>>6); //判斷該塊是否為壞塊

          if(temp == 0x33)

          return 0x42; //是壞塊,返回

          NF_RSTECC(); //復(fù)位ECC

          NF_MECC_UnLock();//解鎖main區(qū)的ECC

          NF_nFCE_L();//打開(kāi)nandflash片選

          NF_CLEAR_RB(); //清RnB信號(hào)

          NF_CMD(CMD_WRITE1); //頁(yè)寫(xiě)命令周期1

          //寫(xiě)入5個(gè)地址周期

          NF_ADDR(0x00);//列地址A0~A7

          NF_ADDR(0x00); //列地址A8~A11

          NF_ADDR((page_number) & 0xff);//行地址A12~A19

          NF_ADDR((page_number >> 8) & 0xff); //行地址A20~A27

          NF_ADDR((page_number >> 16) & 0xff); //行地址A28

          for (i = 0; i < 2048; i++)//寫(xiě)入一頁(yè)數(shù)據(jù)

          {

          NF_WRDATA8((char)(i+6));

          }

          NF_MECC_Lock();//鎖定main區(qū)的ECC值

          mecc0=rNFMECC0; //讀取main區(qū)的ECC校驗(yàn)碼

          //把ECC校驗(yàn)碼由字型轉(zhuǎn)換為字節(jié)型,并保存到全局變量數(shù)組ECCBuf中

          ECCBuf[0]=(U8)(mecc0&0xff);

          ECCBuf[1]=(U8)((mecc0>>8) & 0xff);

          ECCBuf[2]=(U8)((mecc0>>16) & 0xff);

          ECCBuf[3]=(U8)((mecc0>>24) & 0xff);

          NF_SECC_UnLock(); //解鎖spare區(qū)的ECC

          //把main區(qū)的ECC值寫(xiě)入到spare區(qū)的前4個(gè)字節(jié)地址內(nèi),即第2048~2051地址

          for(i=0;i<4;i++)

          {

          NF_WRDATA8(ECCBuf[i]);

          }

          NF_SECC_Lock(); //鎖定spare區(qū)的ECC值

          secc=rNFSECC; //讀取spare區(qū)的ECC校驗(yàn)碼

          //把ECC校驗(yàn)碼保存到全局變量數(shù)組ECCBuf中

          ECCBuf[4]=(U8)(secc&0xff);

          ECCBuf[5]=(U8)((secc>>8) & 0xff);

          //把spare區(qū)的ECC值繼續(xù)寫(xiě)入到spare區(qū)的第2052~2053地址內(nèi)

          for(i=4;i<6;i++)

          {

          NF_WRDATA8(ECCBuf[i]);

          }

          NF_CMD(CMD_WRITE2);//頁(yè)寫(xiě)命令周期2

          delay(1000); //延時(shí)一段時(shí)間,以等待寫(xiě)操作完成

          NF_CMD(CMD_STATUS); //讀狀態(tài)命令

          //判斷狀態(tài)值的第6位是否為1,即是否在忙,該語(yǔ)句的作用與NF_DETECT_RB();相同

          do{

          stat = NF_RDDATA8();

          }while(!(stat&0x40));

          NF_nFCE_H(); //關(guān)閉Nand Flash片選

          //判斷狀態(tài)值的第0位是否為0,為0則寫(xiě)操作正確,否則錯(cuò)誤

          if (stat & 0x1)

          {

          temp = rNF_MarkBadBlock(page_number>>6);//標(biāo)注該頁(yè)所在的塊為壞塊

          if (temp == 0x21)

          return 0x43 //標(biāo)注壞塊失敗

          else

          return 0x44; //寫(xiě)操作失敗

          }

          else

          return 0x66; //寫(xiě)操作成功

          }



          關(guān)鍵詞: S3C2440NandFlashK9F2G08U0

          評(píng)論


          技術(shù)專(zhuān)區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();