天天看點

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

S3C2440内部內建了一個Nand flash控制器。S3C2440的Nand flash控制器包含了如下的特性:

l        一個引導啟動單元

l        Nand Flash存儲器接口,支援8位或16位的每頁大小為256字,512位元組,1K字和2K位元組的Nand flash

l        軟體模式:使用者可以直接通路Nand Flash存儲器,此特性可以用于Nand Flash存儲器的讀、擦除和程式設計。

l        S3C2440支援8/16位的Nand Flash存儲器接口總線

l        硬體ECC生成,檢測和訓示(軟體糾錯)。

l        Steppingstone接口,支援大/小端模式的按位元組/半字/字通路。

我用的開發闆是天嵌的TQ2440,闆子用到的Nand Flash是Samsung公司的K9F2G08U0A,它是8位的Nand flash。本文隻介紹Nand Flash的電路原理和Nand Flash的讀、寫、擦除等基本操作,暫不涉及Nand Flash啟動程式的問題。

Nand Flash的電路連接配接如圖 1所示:

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

圖 1 Nand Flash電路原理

    上圖的左邊為K9F2G08U0A與2440的連接配接圖,原理方面就不多介紹,去看看datasheet估計就懂得了,右邊的部分是S3C2440的Nand控制器的配置。配置引腳NCON,GPG13,GPG14和GPG15用來設定Nand Flash的基本資訊,Nand控制器通過讀取配置引腳的狀态擷取外接的Nand Flash的配置資訊,圖 2是這四個配置引腳的定義:

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

圖 2 Nand控制配置引腳資訊

       由于K9F2G08U0A的總線寬度為8位,頁大小為2048位元組,需要5個尋址指令,是以NCON、GPG13和GPG14應該接高電平,GPG15應該接低電平。

K9F2G08U0A沒有位址或資料總線,隻有8個IO口,這8個IO口用于傳輸指令、位址和資料。K9F2G08U0A主要以page(頁)為機關進行讀寫,以block(塊)為機關進行擦除。每一頁中又分為main區和spare區,main區用于正常資料的存儲,spare區用于存儲一些附加資訊,如塊好壞的标記、塊的邏輯位址、頁内資料的ECC校驗和等。K9F2G08U0A的存儲陣列如圖 3所示:

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

圖 3 K9F2G08U0A内部存儲陣列

由上圖,我們可以知道:K9F2G08U0A的一頁為(2K+64)位元組(2K表示的是main區容量, 64表示的是spare區容量),它的一塊為64頁,而整個裝置包括了2048個塊。這樣算下來一共有2112M位容量,如果隻算main區容量則有256M位元組(即256M×8位)。

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

圖 4 K9F2G08U0A位址序列

要實作用8個IO口來要通路這麼大的容量,如圖 4所示:K9F2G08U0A規定了用5個周期來實作。第一個周期通路的位址為A0~A7;第二個周期通路的位址為A8~A11,它作用在IO0~IO3上,而此時IO4~IO7必須為低電平;第三個周期通路的位址為A12~A19;第四個周期通路的位址為A20~A27;第五個周期通路的位址為A28,它作用在IO0上,而此時IO1~IO7必須為低電平。前兩個周期傳輸的是列位址,後三個周期傳輸的是行位址。通過分析可知,列位址是用于尋址頁内空間,行位址用于尋址頁,如果要直接通路塊,則需要從位址A18開始。由于所有的指令、位址和資料全部從8位IO口傳輸,是以Nand flash定義了一個指令集來完成各種操作。有的操作隻需要一個指令(即一個周期)即可,而有的操作則需要兩個指令(即兩個周期)來實作。K9F2G08U0A的指令說明如圖 5所示:

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

圖 5 K9F2G08U0A指令表

為了友善使用,我們宏定義了K9F2G08U0A的常用指令

#define CMD_READ1                0x00              //頁讀指令周期1

#define CMD_READ2                0x30              //頁讀指令周期2

#define CMD_READID               0x90              //讀ID指令

#define CMD_WRITE1               0x80              //頁寫指令周期1

#define CMD_WRITE2               0x10              //頁寫指令周期2

#define CMD_ERASE1               0x60              //塊擦除指令周期1

#define CMD_ERASE2               0xd0              //塊擦除指令周期2

#define CMD_STATUS               0x70              //讀狀态指令

#define CMD_RESET                0xff               //複位

#define CMD_RANDOMREAD1          0x05       //随意讀指令周期1

#define CMD_RANDOMREAD2          0xE0       //随意讀指令周期2

#define CMD_RANDOMWRITE          0x85       //随意寫指令

接下來介紹幾個Nand Flash控制器的寄存器。Nand Flash控制器的寄存器主要有NFCONF(Nand Flash配置寄存器),NFCONT(Nand Flash控制寄存器),NFCMMD(Nand Flash指令集寄存器),NFADDR(Nand Flash位址集寄存器),NFDATA(Nand Flash資料寄存器),NFMECCD0/1(Nand Flash的main區ECC寄存器),NFSECCD(Nand Flash的spare區ECC寄存器),NFSTAT(Nand Flash操作狀态寄存器),NFESTAT0/1(Nand Flash的ECC狀态寄存器),NFMECC0/1(Nand Flash用于資料的ECC寄存器),以及NFSECC(Nand Flash用于IO的ECC寄存器)。

       (1)NFCONF:2440的NFCONF寄存器是用來設定NAND Flash的時序參數TACLS、TWRPH0、TWRPH1。配置寄存器的[3:0]是隻讀位,用來訓示外部所接的Nand Flash的配置資訊,它們是由配置引腳NCON,GPG13,GPG14和GPG15所決定的(比如說K9F2G08U0A的配置為NCON、GPG13和GPG14接高電平,GPG15接低電平,是以[3:0]位狀态應該是1110)。

(2)NFCONT:用來使能/禁止NAND Flash控制器、使能/禁止控制引腳信号nFCE、初始化ECC。它還有其他功能,在一般的應用中用不到,比如鎖定NAND Flash。

(3)NFCMMD:對于不同型号的Flash,操作指令一般不一樣。參考前面介紹的K9F2G08U0A指令序列。

(4)NFADDR:當寫這個寄存器時,它将對Flash發出位址信号。隻用到低8位來傳輸,是以需要分次來寫入一個完整的32位位址,K9F2G08U0A的位址序列在圖4已經做了詳細說明。

(5)NFDATA:隻用到低8位,讀、寫此寄存器将啟動對NAND Flash的讀資料、寫資料操作。

(6)NFSTAT:隻用到位0,用來檢測NAND是否準備好。0:busy,1:ready。

NFCONF寄存器使用TACLS、TWRPH0、TWRPH1這3個參數來控制NAND Flash信号線CLE/ALE與寫控制信号nWE的時序關系,它們之間的關系如圖6和圖7所示:

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

圖6 CLE/ALE時序圖

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

圖7 nWE和nRE時序圖

 TACLS為CLE/ALE有效到nWE有效之間的持續時間,TWRPH0為nWE的有效持續時間,TWRPH1為nWE無效到CLE/ALE無效之間的持續時間,這些時間都是以HCLK為機關的。通過查閱K9F2G08U0A的資料手冊,我們可以找到并計算與S3C2440相對應的時序:K9F2G08U0A中的Twp與TWRPH0相對應,Tclh與TWRPH1相對應, TACLS應該是與Tcls相對應。K9F2G08U0A給出的都是最小時間, 2440隻要滿足它的最小時間即可。TACLS、TWRPH0、TWRPH1這三個變量取值大一些會更保險,在這裡,這三個值分别取1,2和0。

下面就開始詳細介紹K9F2G08U0A的基本操作,包括複位,讀ID,頁讀、寫資料,随意讀、寫資料,塊擦除等。

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

#define NF_nFCE_L()        {rNFCONT &= ~(1

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

#define NF_nFCE_H()        {rNFCONT |= (1

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

#define NF_RSTECC()        {rNFCONT |= (1

#define NF_MECC_UnLock()   {rNFCONT &= ~(1

#define NF_MECC_Lock()     {rNFCONT |= (1

#define NF_SECC_UnLock()   {rNFCONT &= ~(1

#define NF_SECC_Lock()     {rNFCONT |= (1

NFSTAT是另一個比較重要的寄存器,它的第0位可以用于判斷nandflash是否在忙,第2位用于檢測RnB引腳信号:

#define NF_WAITRB() {while(!(rNFSTAT&(1

#define NF_CLEAR_RB()  {rNFSTAT |= (1

#define NF_DETECT_RB()   {while(!(rNFSTAT&(1

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

NFCMMD,NFADDR和NFDATA分别用于傳輸指令,位址和資料,為了友善起見,我們可以定義一些宏定義用于完成上述操作: 

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

#define NF_ADDR(addr)      {rNFADDR = (addr); }       //傳輸位址

#define NF_RDDATA()         rNFDATA)                  //讀32位資料

#define NF_RDDATA8()       (rNFDATA8)                 //讀8位資料

#define NF_WRDATA(data)    {rNFDATA = (data); }       //寫32位資料

#define NF_WRDATA8(data)    {rNFDATA8 = (data); }     //寫8位資料

首先,是初始化操作

void rNF_Init(void)

{

rNFCONF = (TACLS

rNFCONT =

(0

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,第三個周期至第五個周期包括了一些具體的該晶片資訊,函數如下

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

       //讀五個周期的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讀操作,讀操作是以頁為機關進行的。如果在讀取資料的過程中不進行ECC校驗判斷,則讀操作比較簡單,在寫入讀指令的兩個周期之間寫入要讀取的頁位址,然後讀取資料即可。如果為了更準确地讀取資料,則在讀取完資料之後還要進行ECC校驗判斷,以确定所讀取的資料是否正确。

在上文中已經介紹過,Nand Flash的每一頁有兩區:main區和spare區,main區用于存儲正常的資料,spare區用于存儲其他附加資訊,其中就包括ECC校驗碼。當我們在寫入資料的時候,我們就計算這一頁資料的ECC校驗碼,然後把校驗碼存儲到spare區的特定位置中,在下次讀取這一頁資料的時候,同樣我們也計算ECC校驗碼,然後與spare區中的ECC校驗碼比較,如果一緻則說明讀取的資料正确,如果不一緻則不正确。ECC的算法較為複雜,好在S3C2440能夠硬體産生ECC校驗碼,這樣就省去了不少的麻煩事。S3C2440既可以産生main區的ECC校驗碼,也可以産生spare區的ECC校驗碼。因為K9F2G08U0A是8位IO口,是以S3C2440共産生4個位元組的main區ECC碼和2個位元組的spare區ECC碼。在這裡我們規定,在每一頁的spare區的第0個位址到第3個位址存儲main區ECC,第4個位址和第5個位址存儲spare區ECC。

産生ECC校驗碼的過程為:在讀取或寫入哪個區的資料之前,先解鎖該區的ECC,以便産生該區的ECC。在讀取或寫入完資料之後,再鎖定該區的ECC,這樣系統就會把産生的ECC碼儲存到相應的寄存器中。main區的ECC儲存到NFMECC0/1中(因為K9F2G08U0A是8位IO口,是以這裡隻用到了NFMECC0),spare區的ECC儲存到NFSECC中。對于讀操作來說,我們還要繼續讀取spare區的相應位址内容,以得到上次寫操作時所存儲的main區和spare區的ECC,并把這些資料分别放入NFMECCD0/1和NFSECCD的相應位置中。最後我們就可以通過讀取NFESTAT0/1(因為K9F2G08U0A是8位IO口,是以這裡隻用到了NFESTAT0)中的低4位來判斷讀取的資料是否正确,其中第0位和第1位為main區訓示錯誤,第2位和第3位為spare區訓示錯誤。

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

U8 rNF_ReadPage( U32 page_number )

    U32 i, mecc0, secc;

NF_RSTECC();               //複位ECC

NF_MECC_UnLock();          //解鎖main區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

    {

       buf[i] =  NF_RDDATA8();//讀取一頁資料内容

    }

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

NF_SECC_UnLock();        //解鎖spare區ECC

mecc0=NF_RDDATA();   //讀spare區的前4個位址内容,即第2048~2051位址,這4個位元組為main區的ECC

   //把讀取到的main區的ECC校驗碼放入NFMECCD0/1的相應位置内

rNFMECCD0=((mecc0&0xff00)

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

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

secc=NF_RDDATA();   //繼續讀spare區的4個位址内容,即第2052~2055位址,其中前2個位元組為spare區的ECC值

       //把讀取到的spare區的ECC校驗碼放入NFSECCD的相應位置内

rNFSECCD=((secc&0xff00)

    NF_nFCE_H();   //關閉nandflash片選

    //判斷所讀取到的資料是否正确

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

return 0x66;                  //正确

else

return 0x44;                  //錯誤

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

頁寫操作的大緻流程為:在兩個寫指令周期之間分别寫入頁位址和資料,當然如果為了保證下次讀取該資料時的正确性,還需要把main區的ECC值和spare區的ECC值寫入到該頁的spare區内。然後我們還需要讀取狀态寄存器,以判斷這次寫操作是否正确。下面就給出一段具體的頁寫操作程式,其中輸入參數也是要寫入資料到第幾頁:

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區的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

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

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

mecc0=rNFMECC0;    //讀取main區的ECC校驗碼

//把ECC校驗碼由字型轉換為位元組型,并儲存到全局變量數組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區的ECC

//把main區的ECC值寫入到spare區的前4個位元組位址内,即第2048~2051位址

for(i=0;i

NF_WRDATA8(ECCBuf[i]);

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

secc=rNFSECC;                   //讀取spare區的ECC校驗碼

//把ECC校驗碼儲存到全局變量數組ECCBuf中

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

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

//把spare區的ECC值繼續寫入到spare區的第2052~2053位址内

for(i=4;i

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

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

NF_CMD(CMD_STATUS);          //讀狀态指令

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

do{

stat = NF_RDDATA8();

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

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

//判斷狀态值的第0位是否為0,為0則寫操作正确,否則錯誤

if (stat & 0x1)

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

if (temp == 0x21)

return 0x43            //标注壞塊失敗

return 0x44;           //寫操作失敗

return 0x66;                  //寫操作成功

該段程式先判斷該頁所在的壞是否為壞塊,如果是則退出。在最後寫操作失敗後,還要标注該頁所在的塊為壞塊,其中所用到的函數rNF_IsBadBlock和rNF_MarkBadBlock,我們在後面介紹。我們再總結一下該程式所傳回數值的含義,0x42:表示該頁所在的塊為壞塊;0x43:表示寫操作失敗,并且在标注該頁所在的塊為壞塊時也失敗;0x44:表示寫操作失敗,但是标注壞塊成功;0x66:寫操作成功。

擦除是以塊為機關進行的,是以在寫位址周期是,隻需寫三個行周期,并且要從A18開始寫起。與寫操作一樣,在擦除結束前還要判斷是否擦除操作成功,另外同樣也存在需要判斷是否為壞塊以及要标注壞塊的問題。下面就給出一段具體的塊擦除操作程式:

U8 rNF_EraseBlock(U32 block_number)

char stat, temp;

temp = rNF_IsBadBlock(block_number);     //判斷該塊是否為壞塊

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

NF_nFCE_L();             //打開片選

NF_CMD(CMD_ERASE1);    //擦除指令周期1

    //寫入3個位址周期,從A18開始寫起

NF_ADDR((block_number

NF_ADDR((block_number >> 2) & 0xff);         //行位址A20~A27

NF_ADDR((block_number >> 10) & 0xff);        //行位址A28

    NF_CMD(CMD_ERASE2);         //擦除指令周期2

    delay(1000);          //延時一段時間

    NF_CMD(CMD_STATUS);          //讀狀态指令

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

       stat = NF_RDDATA8();

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

//判斷狀态值的第0位是否為0,為0則擦除操作正确,否則錯誤

       temp = rNF_MarkBadBlock(page_number>>6);    //标注該塊為壞塊

       if (temp == 0x21)

              return 0x43            //标注壞塊失敗

       else

              return 0x44;           //擦除操作失敗

return 0x66;                  //擦除操作成功

該程式的輸入參數為K9F2G08U0A的第幾塊,例如我們要擦除第2001塊,則調用該函數為:rNF_EraseBlock(2001)。

K9F2G08U0A除了提供了頁讀和頁寫功能外,還提供了頁内位址随意讀、寫功能。頁讀和頁寫是從頁的首位址開始讀、寫,而随意讀、寫實作了在一頁範圍内任意位址的讀、寫。随意讀操作是在頁讀操作後輸入随意讀指令和頁内列位址,這樣就可以讀取到列位址所指定位址的資料。随意寫操作是在頁寫操作的第二個頁寫指令周期前,輸入随意寫指令和頁内列位址,以及要寫入的資料,這樣就可以把資料寫入到列位址所指定的位址内。下面兩段程式實作了随意讀和随意寫功能,其中随意讀程式的輸入參數分别為頁位址和頁内位址,輸出參數為所讀取到的資料,随意寫程式的輸入參數分别為頁位址,頁内位址,以及要寫入的資料。

U8 rNF_RamdomRead(U32 page_number, U32 add)

NF_nFCE_L();                    //打開Nand Flash片選

NF_CLEAR_RB();               //清RnB信号

NF_CMD(CMD_READ1);           //頁讀指令周期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

NF_CMD(CMD_READ2);          //頁讀指令周期2

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

NF_CMD(CMD_RANDOMREAD1);   //随意讀指令周期1

//頁内位址

NF_ADDR((char)(add&0xff));                  //列位址A0~A7

NF_ADDR((char)((add>>8)&0x0f));           //列位址A8~A11

NF_CMD(CMD_RANDOMREAD2);            //随意讀指令周期2

return NF_RDDATA8();               //讀取資料

U8 rNF_RamdomWrite(U32 page_number, U32 add, U8 dat)

U8 temp,stat;

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

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

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

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

NF_CMD(CMD_RANDOMWRITE);                 //随意寫指令

NF_ADDR((char)(add&0xff));                   //列位址A0~A7

NF_ADDR((char)((add>>8)&0x0f));          //列位址A8~A11

NF_WRDATA8(dat);                          //寫入資料

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

delay(1000);                 //延時一段時間 

NF_CMD(CMD_STATUS);      //讀狀态指令

       stat =  NF_RDDATA8();

 //判斷狀态值的第0位是否為0,為0則寫操作正确,否則錯誤

return 0x44;                  //失敗

return 0x66;                  //成功

下面介紹上文中提到的判斷壞塊以及标注壞塊的那兩個程式:rNF_IsBadBlock和rNF_MarkBadBlock。在這裡,我們定義在spare區的第6個位址(即每頁的第2054位址)用來标注壞塊,0x44表示該塊為壞塊。要判斷壞塊時,利用随意讀指令來讀取2054位址的内容是否為0x44,要标注壞塊時,利用随意寫指令來向2054位址寫0x33。下面就給出這兩個程式,它們的輸入參數都為塊位址,也就是即使僅僅一頁出現問題,我們也标注整個塊為壞塊。

U8 rNF_IsBadBlock(U32 block)

       return rNF_RamdomRead(block*64, 2054);

U8 rNF_MarkBadBlock(U32 block)

U8 result;

result = rNF_RamdomWrite(block*64, 2054, 0x33);

    if(result == 0x44)

return 0x21;                  //寫壞塊标注失敗

return 0x60;                  //寫壞塊标注成功

關于Nand Flash的基本操作就介紹到這吧

繼續閱讀