日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

NAND FLASH編程

 Upandi 2011-09-02

NAND FLASH編程

NANDnbsp;FLASH編程_sinoorc_新浪博客 - 火熱的心 - 火熱的心的博客(2008-09-12 20:48:37)
 

1、結(jié)構(gòu)分析

NAND FLASH以頁(page)為單位進行讀寫,以塊(block)為單位進行擦除。

其中,512B用于存放數(shù)據(jù),16B用于存放其他信息(包括:塊好壞的標記、塊的邏輯地址、頁內(nèi)數(shù)據(jù)的ECC校驗和等)。2410處理器針對NAND設(shè)備還集成了硬件ECC校驗,這將大大提高NAND設(shè)備的讀寫效率。系統(tǒng)在每次讀一頁后會計算其校驗和,并和存儲在頁內(nèi)的冗余的16B內(nèi)的校驗和做比較,以此來判斷讀出的數(shù)據(jù)是否正確。

NAND FLASH有與頁大小相同的頁寄存器,用于數(shù)據(jù)緩存。當讀數(shù)據(jù)時,先從NAND FLASH內(nèi)存單元把數(shù)據(jù)讀到頁寄存器,外部通過訪問NAND FLASH I/O端口獲得頁寄存器中數(shù)據(jù)(地址自動累加);當寫數(shù)據(jù)時,外部通過NAND FLASH I/O端口輸入的數(shù)據(jù)首先緩存在頁寄存器,寫命令發(fā)出后才寫入到內(nèi)存單元中。

按照k9f1208的組織方式可以分四類地址: Column Address、halfpage pointer、Page Address 、Block Address。A[0:25]表示數(shù)據(jù)在64M空間中的地址。

Column Address表示數(shù)據(jù)在半頁中的地址,大小范圍0~255,用A[0:7]表示;

halfpage pointer表示半頁在整頁中的位置,即在0~255空間還是在256~511空間,用A[8]表示;

Page Address表示頁在塊中的地址,大小范圍0~31,用A[13:9]表示;

Block Address表示塊在flash中的位置,大小范圍0~4095,A[25:14] 表示;

 

2、NAND設(shè)備的軟件調(diào)試步驟:

設(shè)置相關(guān)寄存器、NAND 設(shè)備的初始化、NAND設(shè)備的識別、NAND設(shè)備的讀擦寫(帶ECC校驗)

NFCONF――配置寄存器 

NFCONT――控制寄存器

NFCMD―― 命令設(shè)置寄存器

NFADDR――地址設(shè)置寄存器

NFDATA――數(shù)據(jù)寄存器

NFSTAT―― 操作狀態(tài)寄存器

NFECC―― ECC 寄存器

讀操作過程

K9f1208的尋址分為4個cycle。分別是:A[0:7]、A[9:16]、A[17:24]、A[25]。讀操作的過程為: 1、發(fā)送讀取指令;2、發(fā)送第1個cycle地址;3、發(fā)送第2個cycle地址;4、發(fā)送第3個cycle地址;5、發(fā)送第4個cycle地址;6、讀取數(shù)據(jù)至頁末。K9f1208提供了兩個讀指令,‘0x00’、‘0x01’。這兩個指令區(qū)別在于‘0x00’可以將A[8]置為0,選中上半頁;而‘0x01’可以將A[8]置為1,選中下半頁。雖然讀寫過程可以不從頁邊界開始,但在正式場合下還是建議從頁邊界開始讀寫至頁結(jié)束。

寫操作過程

寫操作的過程為: 1、發(fā)送寫開始指令;2、發(fā)送第1個cycle地址;3、發(fā)送第2個cycle地址;4、發(fā)送第3個cycle地址;5、發(fā)送第4個cycle地址;6、寫入數(shù)據(jù)至頁末;7、發(fā)送寫結(jié)束指令

 

3、存儲檢查

需要ECC(Error Corection Code)校驗,壞塊標注、地址映射等一系列的技術(shù)手段來達到可靠存儲目的。

       SSFDC軟件規(guī)范中,詳細定義了如何利用NAND設(shè)備每個頁中的冗余信息來實現(xiàn)上述功能。這個軟件規(guī)范中,很重要的一個概念就是塊的邏輯地址,它將在物理上可能不連續(xù)、不可靠的空間分配編號,為他們在邏輯空間上給系統(tǒng)文件提供一個連續(xù)可靠的存儲空間。表1給出了SSFDC規(guī)范中邏輯地址的標注方法。在系統(tǒng)初始化的時候,驅(qū)動程序先將所有的塊掃描一遍,讀出他們所對應(yīng)的邏輯地址,并把邏輯地址和虛擬地址的映射表建好。系統(tǒng)運行時,驅(qū)動程序通過查詢映射表,找到需要訪問的邏輯地址所對應(yīng)的物理地址然后進行數(shù)據(jù)讀寫。

表1 冗余字節(jié)定義

字節(jié)序號

內(nèi)容

字節(jié)序號

內(nèi)容

512

用戶定義數(shù)據(jù)

520

后256BECC校驗和

513

521

514

522

515

523

塊邏輯地址

516

數(shù)據(jù)狀態(tài)

524

517

塊狀態(tài)

525

前256BECC校驗和

518

塊邏輯地址1

526

519

527

表2給出了塊邏輯地址的存放格式,LA表示邏輯地址,P代表偶校驗位。邏輯地址只有10bit,代表只有1024bit的尋址空間。而SSFDC規(guī)范將NAND設(shè)備分成了多個zone,每個zone 內(nèi)有1024塊,但這物理上的1024塊映射到邏輯空間只有1000塊,其他的24塊就作為備份使用,當有壞塊存在時,就可以以備份塊將其替換。

表2  邏輯地址格式

D7

D6

D5

D4

D3

D2

D1

D0

 

0

0

0

1

0

LA9

LA8

LA7

第518   523字節(jié)

LA6

LA5

LA4

LA3

LA2

LA1

LA0

P

第519   524字節(jié)

有了以上的軟件規(guī)范,就可以對NAND設(shè)備寫出較標準的ECC校驗,并可以編寫檢測壞塊、標記壞塊、建立物理地址和邏輯地址的映射表的程序了。

static int NF_IsBadBlock(U32 block)           //檢測壞塊

{

    int i;

    unsigned int blockPage;

    U8 data;

    blockPage=(block<<5);       // For 2'nd cycle I/O[7:5]

    NF_nFCE_L();    

    NF_CMD(0x50);    // Spare array read command

   // Read the mark of bad block in spare array(M addr="5")

   NF_ADDR(517&0xf);  

   NF_ADDR(blockPage&0xff); // The mark of bad block is in 0 page

   NF_ADDR((blockPage>>8)&0xff);   // For block number A[24:17]

   NF_ADDR((blockPage>>16)&0xff);  // For block number A[25]

   for(i=0;i<10;i++);              // wait tWB(100ns) //?????

   NF_WAITRB();                 // Wait tR(max 12us)

   data=NF_RDDATA();

   NF_nFCE_H();   

   if(data!=0xff)

    {

       Uart_Printf("[block %d has been marked as a bad block(%x)]\n",block,data);

       return 1;

    }

    else

    {

       return 0;

    }

}

 

static int NF_MarkBadBlock(U32 block)             //標記壞塊

{

    int i;

    U32 blockPage=(block<<5);

    seBuf[0]=0xff;

    seBuf[1]=0xff;   

    seBuf[2]=0xff;   

    seBuf[5]=0x44;                 // Bad blcok mark="0

    NF_nFCE_L();

    NF_CMD(0x50);                        

    NF_CMD(0x80);                         // Write 1st command

    NF_ADDR(0x0);                  // The mark of bad block is   

    NF_ADDR    (blockPage&0xff);     // marked 5th spare array

    NF_ADDR((blockPage>>8)&0xff);             // in the 1st page.

    NF_ADDR((blockPage>>16)&0xff);           

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

    {

    NF_WRDATA(seBuf[i]);                   // Write spare array

    }

    NF_CMD(0x10);                         // Write 2nd command

    for(i=0;i<10;i++);          //tWB = 100ns. //  

    NF_WAITRB();      // Wait tPROG(200~500us)

    NF_CMD(0x70);

    for(i=0;i<3;i++);                         //twhr=60ns///

    if (NF_RDDATA()&0x1)               // Spare arrray write error

    

       NF_nFCE_H();

       Uart_Printf("[Program error is occurred but ignored]\n");

    }

    else

    {

       NF_nFCE_H();

    }

    Uart_Printf("[block #%d is marked as a bad block]\n",block);

    return 1;

}

//建立物理地址到邏輯地址的映射表

int search_logic_block(void)          

{

    unsigned int block,i,blockPage,logic_no,zone,zone_i;

    U8 SE[16];

    for(i=0;i<BLOCK_NR;i++)                       //初始化全局變量

    lg2ph[i]=space_block[i]=0xffff;

    logic_number=0;

    space_nr=0;

    NF_nFCE_L();

    zone=BLOCK_NR/1024;  //確定NAND設(shè)備中zone的個數(shù)

    for(zone_i=0;zone_i<zone;zone_i++)

    {

       //搜索每個zone 內(nèi)邏輯地址和物理地址的映射關(guān)系

       for(block=0;block<1024;block++)

       {

           blockPage=((block+zone_i*1024)<<BLOCK_ADDRERSS_SHIFT);

           NF_WATIRB();                          //等待R/B#信號有效讀取每個block內(nèi)部

                                                   第0個Page 內(nèi)冗余的16個字節(jié)   

           NF_CMD(0x50);       

           NF_ADDR(0);                                // Column 0

           NF_ADDR(blockPage&0xff);    

           NF_ADDR((blockPage>>8)&0xff);      // Block & page num.

           NF_ADDR((blockPage>>16)&0xff);

           NF_WATIRB();                           //等待R/B#信號有效

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

         se[i]=NF_RDDATA();     // Write spare array

       NF_WATIRB();

       if(se[5]!=0xff)          //檢測是否存在壞塊

           printk("\n\rphysic block %d is bad block\n\r",block);

       else if(se[7]!=se[12])

           printk("block address1:%d!=block address2 %d\n\r",se[7],se[12]);

       else if(se[6]0xf8)==0x10)

       {

           //計算該block對應(yīng)的邏輯地址

           logic_no=((0x7&se[6])<<7)+(se[7]>>1)+zone_i*1000;

           if(lg2ph[logic_no]!=0xffff)     //說明有2個block擁有相同的邏輯地址

              printk("physical block %d and block %d have the same logic number %d\n",lg2ph[logic_no],block,logic_no);

           else lg2ph[logic_no]=block;     //將該block的邏輯地址關(guān)系記入lg2ph表

           logic_number++;                       

       }

       else if(se[7]==0xff)            //說明該block尚未編號

       {space_block[space_nr]=block;

       space_nr++;

       }

       }

    }

    printk("there are totally %d logic blocks\n\r",logic_number);

    NF_nFCE_H();

    return logic_number;

}

這段代碼的主要作用就是產(chǎn)生數(shù)組lg2ph[],這個數(shù)組的含義就是“塊物理地址=lg2ph[邏輯地址]”。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多