天天看點

NAND Flash結構與驅動分析

NAND Flash結構與驅動分析

一、NAND flash的實體組成

NAND Flash 的資料是以bit的方式儲存在memory cell,一般來說,一個cell 中隻能存儲一個bit。這些cell 以8個或者16個為機關,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device的位寬。這些Line會再組成Page,(NAND Flash 有多種結構,我使用的NAND Flash 是K9F1208,下面内容針對三星的K9F1208U0M),每頁528Bytes(512byte(Main Area)+16byte(Spare Area)),每32個page形成一個Block(32*528B)。具體一片flash上有多少個Block視需要所定。我所使用的三星 k9f1208U0M具有4096個block,故總容量為4096*(32*528B)=66MB,但是其中的2MB是用來儲存ECC校驗碼等額外資料的,故實際中可使用的為64MB。

NAND flash以頁為機關讀寫資料,而以塊為機關擦除資料。按照這樣的組織方式可以形成所謂的三類位址:

Column Address:Starting Address of the Register. 翻成中文為列位址,位址的低8位

Page Address :頁位址

Block Address :塊位址

對于NAND Flash來講,位址和指令隻能在I/O[7:0]上傳遞,資料寬度是8位。

二、NAND Flash位址的表示

512byte需要9bit來表示,對于528byte系列的NAND,這512byte被分成1st half Page Register和2nd half Page Register,各自的通路由位址指針指令來選擇,A[7:0]就是所謂的column address(列位址),在進行擦除操作時不需要它,why?因為以塊為機關擦除。32個page需要5bit來表示,占用A[13:9],即該page在塊内的相對位址。A8這一位位址被用來設定512byte的1st half page還是2nd half page,0表示1st,1表示2nd。Block的位址是由A14以上的bit來表示。

例如64MB(512Mb)的NAND flash(實際中由于存在spare area,故都大于這個值),共4096block,是以,需要12個bit來表示,即A[25:14],如果是128MB(1Gbit) 的528byte/page的NAND Flash,則block address用A[26:14]表示。而page address就是blcok address|page address in block NAND Flash 的位址表示為: Block Address|Page Address in block|halfpage pointer|Column Address 位址傳送順序是Column Address,Page Address,Block Address。

由于位址隻能在I/O[7:0]上傳遞,是以,必須采用移位的方式進行。例如,對于512Mbit x8的NAND flash,位址範圍是0~0x3FF_FFFF,隻要是這個範圍内的數值表示的位址都是有效的。以NAND_ADDR 為例:

第1 步是傳遞column address,就是NAND_ADDR[7:0],不需移位即可傳遞到I/O[7:0]上,而halfpage pointer即A8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀

寫,而真正的A8 的值是不需程式員關心的。

第2 步就是将NAND_ADDR 右移9位,将NAND_ADDR[16:9]傳到I/O[7:0]上;

第3 步将NAND_ADDR[24:17]放到I/O上;

第4步需要将NAND_ADDR[25]放到I/O上;

是以,整個位址傳遞過程需要4 步才能完成,即4-step addressing。如果NAND Flash 的容量是32MB(256Mbit)以下,那麼,block adress最高位隻到bit24,是以尋址隻需要3步。

下面,就x16 的NAND flash器件稍微進行一下說明。由于一個page 的main area 的容量為256word,仍相當于512byte。但是,這個時候沒有所謂的1st halfpage 和2nd halfpage 之分了,是以,bit8就變得沒有意義了,也就是這個時候 A8 完全不用管,位址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。

三、NAND flash驅動解讀

以前由于做移植多一些,那些工作很簡單(現在看來),從來都不用去關心驅動裡面到底怎麼實作的,這幾次面試才發現真的是學的太淺了,似乎我還在學習仰泳而那些牛人基本都屬于潛水級的了,潛的不知有多深。我對照着開發闆所帶的NAND flash驅動和k9f1208的晶片資料把這些代碼通讀了一遍,終于明白了NAND flash的讀寫過程是如何實作的了。我所參考的驅動是mizi公司為三星晶片所寫的,我看看了,大概和官方2.4.18核心的nand.c差不多。

在 s3c2410處理器中有專門的NAND flash控制器,他們位于SFR區,具體可以參看s3c2410使用者手冊。以下的這些代碼均可以在vivi或者kernel裡面找到,文中會标明程式出自何處。在vivi中,有關NAND flash的驅動都在driver/mtd/nand/下,該目錄中包含的源檔案:smc_core.c是NAND flash的主要驅動。

NAND flash 晶片定義了一個很長的結構,這個結構中包含了操作NAND flash的函數和一些必要的變量(include/mtd/nand.h)。

struct nand_chip {

#ifdef CONFIG_MTD_NANDY    

    void (*hwcontrol)(int cmd);

    void (*write_cmd)(u_char val);

    void (*write_addr)(u_char val);

    u_char (*read_data)(void);

    void (*write_data)(u_char val);

    void (*wait_for_ready)(void);

    int page_shift;

    u_char *data_buf;

    u_char *data_cache;

    int    cache_page;

    struct nand_smc_dev *dev;

    u_char spare[SMC_OOB_SIZE];

#else   

    ……

#ifdef CONFIG_MTD_NAND_ECC

    u_char ecc_code_buf[6];

    u_char reserved[2];

#endif

#endif   

};

縱觀對NAND flash的各種操作(read、write、erase),無外乎如下幾種操作:

1.選擇flash    nand_select()

2.發送指令     nand_command()

3.進行相應操作 read,write……

4.反選NAND flash   nand_deselect()

下面是以上四步的實作代碼:

1、選擇NAND flash

#define nand_select()   this->hwcontrol(NAND_CTL_SETNCE); \

                nand_command(mtd, NAND_CMD_RESET, -1, -1); \

                udelay (10);

hwcontrol(NAND_CTL_SETNCE) 的作用是設定2410的NAND FLASH CONFIGURATION (NFCONF) REGISTER的NAND Flash Memory chip enable位為0,這位寄存器在自動重新開機後就被系統自動清零。如果要通路NAND flash的記憶體,這位必須置1。

nand_command(mtd, NAND_CMD_RESET, -1, -1);向flash發送指令,此指令為reset,即為重置NAND flash。

然後是10us的延遲,給flash個反應時間。

2、發送指令

Nand_command()同樣在smc_core.c中實作。NAND flash的指令有如下幾種:

    指令                         指令值                描述

NAND_CMD_READ0                    0                讀操作

NAND_CMD_READ1                    1                讀操作

NAND_CMD_PAGEPROG                0x10            頁程式設計操作

NAND_CMD_READOOB                0x50            讀寫OOB

NAND_CMD_ERASE1                 0x60            讀寫操作

NAND_CMD_STATUS                    0x70            讀取狀态

NAND_CMD_STATUS_MULTI            0x71            讀取狀态

NAND_CMD_SEQIN                    0x80            寫操作

NAND_CMD_READID                    0x90            讀Flash ID号

NAND_CMD_ERASE2                 0xd0            擦寫操作

NAND_CMD_RESET                    oxff                複位操作

按照程式的注釋,可以将該函數的實作分為如下幾步:

1、Begin command latch cycle

實作代碼:

this->hwcontrol(NAND_CTL_SETCLE);

this->hwcontrol(NAND_CTL_DAT_OUT);

找到第二條語句的定義,發現什麼都麼做,不解!!希望達人解答。我猜想可能是一個資料讀出的使能操作,允許資料讀出。

Command Latch Enable(CLE) and Address Latch Enable(ALE) are used to multiplex command and address respectively, via the I/O pins. The CLE input controls the path activation for commands sent to the command register. When active high, commands are latched into the command register through the I/O ports on the rising edge of the nWE signal. 看了這段英文相信對第一條語句的作用已經十厘清楚了,他就是用來控制向指令寄存(COMMAND SET (NFCMD) REGISTER)發送指令的。

2、 Write out the command to the device

這部分對于不同的指令來說,操作的步驟也不太相同,如果為寫操作,那麼還有根據flash不同的容量決定操作步驟,具體可以參看代碼。如果為其他指令,那麼就是簡單的一行:

this->write_cmd (command);

将指令直接想到指令寄存器(NFCMD[7:0])中。

3、 Set ALE and clear CLE to start address cycle & Serially input address

1中已經提到了ALE和CLE的作用,現在開始發送位址。

實作代碼:

this->hwcontrol(NAND_CTL_CLRCLE); // clear the command latch enable

this->hwcontrol(NAND_CTL_SETALE); // set the address latch enable

然後按位操作,是用函數write_addr()将位址寫到NAND FLASH ADDRESS SET (NFADDR) REGISTER中。

4、 Latch in address

實作代碼:

this->hwcontrol(NAND_CTL_CLRALE);

this->hwcontrol(NAND_CTL_DAT_IN);

位址發送完畢,清楚ALE。

5、 Pause for 15us

我使用的VIVI中,使用udelay (15)延時15us,但這個時間會因NAND Flash的不同而不同。

三、Operation

根據函數的不同,操作部分會不一樣,但是主要的是對NAND FLASH DATA (NFDATA) REGISTER的操作,或寫(程式設計)或者讀。通過讀或寫函數的參數來傳回或傳遞讀出的值或寫入的值。寫得操作通常比較麻煩,他要将寫到flash的内容重新讀出後進行ECC校驗,如果資料正确則在重新真正的寫(程式設計),如果錯誤,則将資料寫入flash的另一個塊。讀和寫都是以頁為機關進行操作。而擦除則以塊為機關,三個周期發送完位址。擦除完畢後同樣需要進行檢察以确定是否擦除成功。

四、De-select the NAND device

實作代碼:

#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);

反選flash吧,不知這樣叫正确與否,跟select the NAND device相反,亦即使用完後将使能flash位清0,代碼是NFCONF位于0x4e00_0000的位置(NFCONF |= NFCONF_nFCE_HIGH;),有興趣的可以讀讀代碼,看看這是怎麼實作的,我的感覺就是關于寄存器的清置讀起來都比較暈。

http://blog.chinaunix.net/uid-26739173-id-3158739.html

繼續閱讀