在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

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

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

            作者: 時間:2016-11-26 來源:網絡 收藏

            下面就開始詳細介紹K9F2G08U0A的基本操作,包括復位,讀ID,頁讀、寫數(shù)據(jù),隨意讀、寫數(shù)據(jù),塊擦除等。

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

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

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

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

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

            #define NF_RSTECC(){rNFCONT |= (1<<4); }//復位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是另一個比較重要的寄存器,它的第0位可以用于判斷nandflash是否在忙,第2位用于檢測RnB引腳信號:

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

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

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

            //等待RnB信號變高,即不忙

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

            #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); }//寫32位數(shù)據(jù)

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

            首先,是初始化操作

            void rNF_Init(void)

            {

            rNFCONF = (TACLS<<12)|(TWRPH0<<8)|( TWRPH1<<4)|(0<<0);//初始化時序參數(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();//復位芯片

            }

            復位操作,寫入復位命令

            static void rNF_Reset()

            {

            NF_CE_L();//打開nandflash片選

            NF_CLEAR_RB();//清除RnB信號

            NF_CMD(CMD_RESET); //寫入復位命令

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

            NF_CE_H();//關閉nandflash片選

            }

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

            static char rNF_ReadID()

            {

            char pMID;

            char pDID;

            char cyc3, cyc4, cyc5;

            NF_nFCE_L();//打開nandflash片選

            NF_CLEAR_RB();//清RnB信號

            NF_CMD(CMD_READID);//讀ID命令

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

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

            //讀五個周期的ID

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

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

            cyc3 = NF_RDDATA8();//0x10

            cyc4 = NF_RDDATA8();//0x95

            cyc5 = NF_RDDATA8();//0x44

            NF_nFCE_H();//關閉nandflash片選

            return (pDID);

            }

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

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

            產生ECC校驗碼的過程為:在讀取或寫入哪個區(qū)的數(shù)據(jù)之前,先解鎖該區(qū)的ECC,以便產生該區(qū)的ECC。在讀取或寫入完數(shù)據(jù)之后,再鎖定該區(qū)的ECC,這樣系統(tǒng)就會把產生的ECC碼保存到相應的寄存器中。main區(qū)的ECC保存到NFMECC0/1中(因為K9F2G08U0A是8位IO口,因此這里只用到了NFMECC0),spare區(qū)的ECC保存到NFSECC中。對于讀操作來說,我們還要繼續(xù)讀取spare區(qū)的相應地址內容,以得到上次寫操作時所存儲的main區(qū)和spare區(qū)的ECC,并把這些數(shù)據(jù)分別放入NFMECCD0/1和NFSECCD的相應位置中。最后我們就可以通過讀取NFESTAT0/1(因為K9F2G08U0A是8位IO口,因此這里只用到了NFESTAT0)中的低4位來判斷讀取的數(shù)據(jù)是否正確,其中第0位和第1位為main區(qū)指示錯誤,第2位和第3位為spare區(qū)指示錯誤。

            下面是一段具體的頁讀操作程序:

            U8 rNF_ReadPage( U32 page_number )

            {

            U32 i, mecc0, secc;

            NF_RSTECC();//復位ECC

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

            NF_nFCE_L();//使能芯片

            NF_CLEAR_RB();//清除RnB

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

            //寫入5個地址周期

            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); //頁讀命令周期2,0x30

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

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

            {

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

            }

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

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

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

            //把讀取到的main區(qū)的ECC校驗碼放入NFMECCD0/1的相應位置內

            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個地址內容,即第2052~2055地址,其中前2個字節(jié)為spare區(qū)的ECC值

            //把讀取到的spare區(qū)的ECC校驗碼放入NFSECCD的相應位置內

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

            NF_nFCE_H();//關閉nandflash片選

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

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

            return 0x66; //正確

            else

            return 0x44; //錯誤

            }

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

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

            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(); //復位ECC

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

            NF_nFCE_L();//打開nandflash片選

            NF_CLEAR_RB(); //清RnB信號

            NF_CMD(CMD_WRITE1); //頁寫命令周期1

            //寫入5個地址周期

            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++)//寫入一頁數(shù)據(jù)

            {

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

            }

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

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

            //把ECC校驗碼由字型轉換為字節(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值寫入到spare區(qū)的前4個字節(jié)地址內,即第2048~2051地址

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

            {

            NF_WRDATA8(ECCBuf[i]);

            }

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

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

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

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

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

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

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

            {

            NF_WRDATA8(ECCBuf[i]);

            }

            NF_CMD(CMD_WRITE2);//頁寫命令周期2

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

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

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

            do{

            stat = NF_RDDATA8();

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

            NF_nFCE_H(); //關閉Nand Flash片選

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

            if (stat & 0x1)

            {

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

            if (temp == 0x21)

            return 0x43 //標注壞塊失敗

            else

            return 0x44; //寫操作失敗

            }

            else

            return 0x66; //寫操作成功

            }



            評論


            技術專區(qū)

            關閉