一、內存詳解
NAND閃存陣列分為一系列128kB的區塊(block),這些區塊是 NAND器件中最小的可擦除實體。擦除一個區塊就是把所有的位(bit)設置為"1"(而所有字節(byte)設置為FFh)。有必要通過編程,將已擦除 的位從"1"變為"0"。最小的編程實體是字節(byte)。一些NOR閃存能同時執行讀寫操作(見下圖1)。雖然NAND不能同時執行讀寫操作,它可以采用稱為"映射(shadowing)"的方法,在系統級實現這一點。這種方法在個人電腦上已經沿用多年,即將BIOS從速率較低的ROM加載到速率較高 的RAM上。
NAND的效率較高,是因為NAND串中沒有金屬觸點。NAND閃存單元的大小比NOR要小(4F2:10F2)的原因,是NOR的每一個單元都需 要獨立的金屬觸點。NAND與硬盤驅動器類似,基於扇區(頁),適合於存儲連續的數據,如圖片、音頻或個人電腦數據。雖然通過把數據映射到RAM上,能在 系統級實現隨機存取,但是,這樣做需要額外的RAM存儲空間。此外,跟硬盤一樣,NAND器件存在壞的扇區,需要糾錯碼(ECC)來維持數據的完整性。
存儲單元面積越小,裸片的面積也就越小。在這種情況下,NAND就能夠為當今的低成本消費市場提供存儲容量更大的閃存產品。NAND閃存用於幾乎所有可擦除的存儲卡。NAND的復用接口為所有最新的器件和密度都提供了一種相似的引腳輸出。這種引腳輸出使得設計工程師無須改變電路板的硬件設計,就能從更小的密度移植到更大密度的設計上。
NAND與NOR閃存比較
NAND閃存的優點在於寫(編程)和擦除操作的速率快,而NOR的優點是具有隨機存取和對字節執行寫(編程)操作的能力(見下圖圖2)。NOR的隨 機存取能力支持直接代碼執行(XiP),而這是嵌入式應用經常需要的一個功能。NAND的缺點是隨機存取的速率慢,NOR的缺點是受到讀和擦除速度慢的性 能制約。NAND較適合於存儲文件。如今,越來越多的處理器具備直接NAND接口,並能直接從NAND(沒有NOR)導入數據。
NAND的真正好處是編程速度快、擦除時間短。NAND支持速率超過5Mbps的持續寫操作,其區塊擦除時間短至2ms,而NOR是750ms。顯然,NAND在某些方面具有絕對優勢。然而,它不太適合於直接隨機存取。
對於16位的器件,NOR閃存大約需要41個I/O引腳;相對而言,NAND器件僅需24個引腳。NAND器件能夠復用指令、地址和數據總線,從而 節省了引腳數量。復用接口的一項好處,就在於能夠利用同樣的硬件設計和電路板,支持較大的NAND器件。由於普通的TSOP-1封裝已經沿用多年,該功能 讓客戶能夠把較高密度的NAND器件移植到相同的電路板上。NAND器件的另外一個好處顯然是其封裝選項:NAND提供一種厚膜的2Gb裸片或能夠支持最 多四顆堆疊裸片,容許在相同的TSOP-1封裝中堆疊一個8Gb的器件。這就使得一種封裝和接口能夠在將來支持較高的密度。
圖2 NOR閃存的隨機存取時間為0.12ms,而NAND閃存的第一字節隨機存取速度要慢得多
NOR閃存的隨機存取時間為0.12ms,而NAND閃存的第一字節隨機存取速度要慢得多
NAND基本操作
以2Gb NAND器件為例,它由2048個區塊組成,每個區塊有64個頁(見下圖):
每一個頁均包含一個2048字節的數據區和64字節的空閑區,總共包含2,112字節。空閑區通常被用於ECC、耗損均衡(wear leveling)和其它軟件開銷功能,盡管它在物理上與其它頁並沒有區別。NAND器件具有8或16位接口。通過8或16位寬的雙向數據總線,主數據被 連接到NAND存儲器。在16位模式,指令和地址僅僅利用低8位,而高8位僅僅在數據傳輸周期使用。
擦除區塊所需時間約為2ms。一旦數據被載入寄存器,對一個頁的編程大約要300μs。讀一個頁面需要大約25μs,其中涉及到存儲陣列訪問頁,並將頁載入16,896位寄存器中。
除了I/O總線,NAND接口由6個主要控制信號構成:
1.芯片啟動(Chip Enable, CE#):如果沒有檢測到CE信號,那么,NAND器件就保持待機模式,不對任何控制信號作出響應。
2.寫使能(Write Enable, WE#): WE#負責將數據、地址或指令寫入NAND之中。
3.讀使能(Read Enable, RE#): RE#允許輸出數據緩沖器。
4.指令鎖存使能(Command Latch Enable, CLE): 當CLE為高時,在WE#信號的上升沿,指令被鎖存到NAND指令寄存器中。
5.地址鎖存使能(Address Latch Enable, ALE):當ALE為高時,在WE#信號的上升沿,地址被鎖存到NAND地址寄存器中。
6.就緒/忙(Ready/Busy, R/B#):如果NAND器件忙,R/B#信號將變低。該信號是漏極開路,需要采用上拉電阻。
數據每次進/出NAND寄存器都是通過16位或8位接口。當進行編程操作的時候,待編程的數據進入數據寄存器,處於在WE#信號的上升沿。在寄存器內隨機存取或移動數據,要采用專用指令以便於隨機存取。
數據寄存器輸出數據的方式與利用RE#信號的方式類似,負責輸出現有的數據,並增加到下一個地址。WE#和RE#時鍾運行速度極快,達到30ns的水准。當RE#或CE#不為低的時候,輸出緩沖器將為三態。這種CE#和RE#的組合使能輸出緩沖器,容許NAND閃存與NOR、SRAM或DRAM等其它類型存儲器共享數據總線。該功能有時被稱為"無需介意芯片啟動(chip enable don't care)"。這種方案的初衷是適應較老的NAND器件,它們要求CE#在整個周期為低(譯注:根據上下文改寫)。
圖4 輸入寄存器接收到頁編程(80h)指令時,內部就會全部重置為1s,使得用戶可以只輸入他想以0位編程的數據字節
圖5 帶有隨機數據輸入的編程指令。圖中加亮的扇區顯示,該指令只需要后面跟隨着數據的2個字節的地址
當輸出一串WE#時鍾時,通過在I/O位7:0上設置指令、驅動CE#變低且CLE變高,就可以實現一個指令周期。注意:在WE#信號的上升沿上, 指令、地址或數據被鎖存到NAND器件之中。如表1所示,大多數指令在第二個指令周期之后要占用若干地址周期。注意:復位或讀狀態指令例外,如果器件忙, 就不應該發送新的指令。
以2Gb NAND器件的尋址方案為例,第一和第二地址周期指定列地址,該列地址指定頁內的起始字節表:
注意:因為最后一列的位置是2112,該最后位置的地址就是08h(在第二字節中)和3Fh(在第一字節中)。PA5:0指定區塊內的頁地 址,BA16:6指定區塊的地址。雖然大多編程和讀操作需要完整的5字節地址,在頁內隨機存取數據的操作僅僅用到第一和第二字節。塊擦除操作僅僅需要三個 最高字節(第三、第四和第五字節)來選擇區塊。
總體而言,NAND的基本操作包括:復位(Reset, FFh)操作、讀ID(Read ID, 00h)操作、讀狀態(Read Status, 70h)操作、編程(Program)操作、隨機數據輸入(Random data input, 85h)操作和讀(Read)操作等。
選擇內置NAND接口的處理器或控制器的好處很多。如果沒有這個選擇,有可能在NAND和幾乎任何處理器之間設計一個"無粘接邏輯(glueless)" 接口。NAND和NOR閃存的主要區別是復用地址和數據總線。該總線被用於指定指令、地址或數據。CLE信號指定指令周期,而ALE信號指定地址周期。利 用這兩個控制信號,有可能選擇指令、地址或數據周期。把ALE連接到處理器的第五地址位,而把CLE連接到處理器的第四地址位,就能簡單地通過改變處理器 輸出的地址,任意選擇指令、地址或數據。這容許CLE和ALE在合適的時間自動設置為低。
為了提供指令,處理器在數據總線上輸出想要的指令,並輸出地址0010h;為了輸出任意數量的地址周期,處理器僅僅要依次在處理器地址0020h之后輸出想要的NAND地址。注意,許多處理器能在處理器的寫信號周圍指定若干時序參數,這對於建立合適的時序是至關重要的。利用該技術,你不必采用任何粘接邏輯,就可以直接從處理器存取指令、地址和數據。
多級單元
多級單元(MLC)的每一個單元存儲兩位,而傳統的SLC僅僅能存儲一位。MLC技術有顯著的密度優越性,然而,與SLC相比(下表),其速度或可靠性稍遜。因此,SLC被用於大多數媒體卡和無線應用,而MLC器件通常被用於消費電子和其它低成本產品。
如上所述,NAND需要ECC以確保數據完整性。NAND閃存的每一個頁面上都包括額外的存儲空間,它就是64個字節的空閑區(每512字節的扇區有16字節)。該區能存儲ECC代碼及其它像磨損評級或邏輯到物理塊映射之類的信息。ECC能在硬件或軟件中執行,但是,硬件執行有明顯的性能優勢。在編 程操作期間,ECC單元根據扇區中存儲的數據來計算誤碼校正代碼。數據區的ECC代碼然后被分別寫入到各自的空閑區。當數據被讀出時,ECC代碼也被讀 出;運用反操作可以核查讀出的數據是否正確。
有可能采用ECC算法來校正數據錯誤。能校正的錯誤的數量取決於所用算法的校正強度。在硬件或軟件中包含ECC,就提供了強大的系統級解決方案。最簡單的硬件實現方案是采用簡單的漢明(Simple Hamming)碼,但是,只能校正單一位錯誤。瑞德索羅門(Reed-Solomon)碼提供更為強大的糾錯,並被目前的控制器廣為采用。此外,BCH 碼由於比瑞德索羅門方法的效率高,應用也日益普及。
要用軟件執行NAND閃存的區塊管理。該軟件負責磨損評級或邏輯到物理映射。該軟件還提供ECC碼,如果處理器不包含ECC硬件的話。
編程或擦除操作之后,重要的是讀狀態寄存器,因為它確認是否成功地完成了編程或擦除操作。如果操作失敗,要把該區塊標記為損壞且不能再使用。以前已編寫進去的數據要從損壞的區塊中搬出,轉移到新的(好的)存儲塊之中。2Gb NAND的規范規定,它可以最多有40個壞的區塊,這個數字在器件的生命周期(額定壽命為10萬次編程/擦除周期)內都適用。一些有壞塊的NAND器件能 夠出廠,主要就歸根於其裸片面積大。管理器件的軟件負責映射壞塊並由好的存儲塊取而代之。
利用工廠對這些區塊的標記,軟件通過掃描塊可以確定區塊的好壞。壞塊標記被固定在空閑區的第一個位置(列地址2048)。如果在0或1頁的列地址 2048上的數據是"non-FF",那么,該塊要標記為壞,並映射出系統。初始化軟件僅僅需要掃描所有區塊確定以確定哪個為壞,然后建一個壞塊表供將來參考。
小心不要擦除壞塊標記,這一點很重要。工廠在寬溫和寬電壓范圍內測試了NAND;一些由工廠標記為壞的區塊可能在一定的溫度或電壓條件下仍然能工作,但是,將來可能會失效。如果壞塊信息被擦除,就無法再恢復。
二、NAND FLASH讀寫尋址方式
NAND Flash的尋址方式和NAND Flash的memory組織方式緊密相關。NAND Flash的數據是以bit的方式保存在memory cell,一般來說,一個cell中只能存儲一個bit。這些cell以8個或者16個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device的位寬。
這些Line會再組成Page,通常是528Byte/page或者264Word/page。然后,每32個page形成一個Block,Sizeof(block)=16kByte.
Block是NAND Flash中最大的操作單元,擦除就是按照block為單位完成的,而
編程/讀取是按照page為單位完成的。
所以,按照這樣的組織方式可以形成所謂的三類地址:
-Block Address
-Page Address
-Column Address
首先,必須清楚一點,對於NAND Flash來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度可以是8位或者16位,但是,對於x16的NAND Device,I/O[15:8]只用於傳遞數據。
清楚了這一點,我們就可以開始分析NAND Flash的尋址方式了。
以528Byte/page 總容量512Mbit+512kbyte的NAND器件為例:
因為,
1 block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area)
用戶數據保存在main area中。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由所謂的pointer operation命令來選擇,也就是選擇了bit8的高低。因此A8就是halfpage pointer,A[7:0]就是所謂的column address。
32個page需要5bit來表示,占用A[13:9],即該page在塊內的相對地址。Block的地址是由A14以上的bit來表示,例如512Mb 的NAND,共4096block,因此,需要12個bit來表示,即A[25:14],如果是1Gbit的528byte/page的NAND Flash,共8192個block,則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即bit8是由操作指令決定的,即指令決定在哪個halfpage上進行讀寫,而真正的bit8的值是don't care的。
第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的容量是256Mbit以下,那么,block adress最高位只到bit24,因此尋址只需要3步。
Nand Flash結構與讀寫分析及Nand Flash尋址方式【ZZ】
看vivi代碼的head.S的時候,看到copy_myself的部分,尤其nand_read_ll函數,看不太明白,不了解nand flash原理,結合nand flash的datasheet和網上的文章,對那個函數就大概了解一點了
http://www.mcuol.com/Solution/195/21883.htm
下面的內容也是別人轉載的,我繼續轉載http://hi.baidu.com/luyun21/blog/item/e0fa82af6de3c6c87dd92a6b.html,內容好像有點亂,我只看了一點點,對其尋址明白了一點,暫時就這樣了,暫時還沒需要繼續研究,有需要在研究
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),每頁528Byte,每32 個page 形成一個Block, Sizeof(block)=16kByte 。1 block=16kbyte,512Mbit=64Mbyte,Numberof(block)=1024 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash 以頁為單位讀寫數據,而以塊為單位擦除數據。按照這樣的組織方式可以形成所謂的三類地址: --Block Address -- Page Address --Column Address(即為頁內偏移地址)
對於NAND Flash 來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度是8 位。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由地址指針命令來選擇,A[7:0]就是所謂的column address。32 個page 需要5bit 來表示,占用A[13:9],即該page 在塊內的相對地址。Block的地址是由A14 以上的bit 來表示,例如512Mb 的NAND,共4096block,因此,需要12 個bit 來表示,即A[25:14],如果是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 即bit8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀寫。而真正的bit8 的值是don\'t care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此尋址 只需要3 步。
下面,就x16 的NAND flash 器件稍微進行一下說明。由於一個page 的main area 的容量為256word,仍相當於512byte。但是,這個時候沒有所謂 的1st halfpage 和2nd halfpage 之分了,所以,bit8就變得沒有意義了,也就是這個時候 bit8 完全不用管,地址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
norflash和nandflash的區別
norflash中可以運行程序,nandflash不可以
Nor flash按sector可擦除,按bit可讀寫。Nand Flash按Block可擦除,按Page可讀寫。
最主要是尋址方式不同
*********************************************************************************************************************************
Nand Flash 尋址方式
NAND Flash的尋址方式和NAND Flash的memory組織方式緊密相關。NAND Flash的數據是以bit的方式保存在memory cell,一般來說,一個cell中只能存儲一個bit。這些cell以8個或者16個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device的位寬。
這些Line會再組成Page,通常是528Byte/page或者264Word/page。然后,每32個page形成一個Block,Sizeof(block)=16kByte.
Block是NAND Flash中最大的操作單元,擦除就是按照block為單位完成的,而
編程/讀取是按照page為單位完成的。
所以,按照這樣的組織方式可以形成所謂的三類地址:
-Block Address
-Page Address
-Column Address
首先,必須清楚一點,對於NAND Flash來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度可以是8位或者16位,但是,對於x16的NAND Device,I/O[15:8]只用於傳遞數據。
清楚了這一點,我們就可以開始分析NAND Flash的尋址方式了。
以528Byte/page 總容量512Mbit+512kbyte的NAND器件為例:
因為,
1 block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area)
用戶數據保存在main area中。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由所謂的pointer operation命令來選擇,也就是選擇了bit8的高低。因此A8就是halfpage pointer,A[7:0]就是所謂的column address。
32個page需要5bit來表示,占用A[13:9],即該page在塊內的相對地址。Block的地址是由A14以上的bit來表示,例如512Mb 的NAND,共4096block,因此,需要12個bit來表示,即A[25:14],如果是1Gbit的528byte/page的NAND Flash,共8192個block,則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即bit8是由操作指令決定的,即指令決定在哪個halfpage上進行讀寫,而真正的bit8的值是don't care的。
第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的容量是256Mbit以下,那么,block adress最高位只到bit24,因此尋址只需要3步。
NAND Flash Architecture
Architecture
NAND Flash是由4096個Blocks所組成的,每個Block是由128個Pages所組成的,而每個Page是由4KBytes的User Data加上128Bytes的Spare Data所構成的,故每個Block的容量為528Kbytes,每個Page的容量為4224Bytes。其中,Spare Data主要是用來存放ECC(Error Correcting Code)、Bad Block Information和File System的資料。
Figure 1.Flash Memory Geometry
NAND Flash的操作特點為:抹除(Erase)的最小單位是Block,而讀取(Read)和寫入(Write)則是以Page為單位。因NAND Flash的每個bit只能由1變為0,而不能從0變為1,所以對Flash做寫入時一定要將其對應的Block先抹除掉,才能做寫入的動作,也因此同樣 一個page只能夠寫入一次。
Constraints and Functionalities
Constraints
Sequential Page program
在一個Block裡,Page必須從LSB(least significant bit) Page依序寫到MSB(most significant bit) Page,隨意不照Page address來寫入是禁止的。另外,LSB是寫入的Pages中最小的位址,不一定是Page 0。
Figure 2.Sequential Page program [1]
Partial Page program
在NAND Flash中,存取資料的最小單位是Page。在SLC Flash中,若想修改Page中的Data時可以更改部分的Bit而不需要將整個Page抹除後才更改。例如Page中的Data為1001011101,若想將Data改成1001010001,只需將其中的2個Bit更改為0即可,不用抹除後寫入。但之後的MLC Flash,已經不允許此功能了。
Performance-Improving Commands
Copy Back Program
Copy Back Program可以快速地將1頁的資料複製(Copy)到另1個指定的頁中,也對於垃圾收集(Garbage Collection)非常的有用。例如當1頁裡的資料壞掉造成整個區塊(Block)為損壞區塊(Bad Block, or Worn-Out Block)時,Copy Back Program可以有效率地將所有有效頁(Valid Page)的資料複製到指定的區塊中。
Copy Back Program是將1整頁的資料(來源Page)讀取且複製到內部頁緩衝器(Internal Page Buffer)中,再將它寫到另1整頁中(目標Page)。因為它不像一般的讀取、寫入指令將資料存取到外部記憶體(Memory),而是將資料存在內部頁緩衝器中,所以會比一般的讀取加上寫入少了將資料讀寫到外部記憶體的時間,執行上也更快且更有效率。
Figure 3.Copy Back Program [1]
Random data input/output
當對Page的資料做讀寫時,必須將1整頁的所有資料都存在於外部記憶體中,當外部的RAM不夠大時,無法一次存放整個頁的資料,故利用NAND Flash的Internal Page Buffer來存放整個頁的資料,並使用Random Data Input/Output就可以對頁中任意位址的資料做存取。
對1頁裡的資料做一般的讀寫時,資料都是Sequential的,但若想要隨意存取1頁裡的資料,如想要存取ECC的資料,便可使用Random data input/output跳至User Data的尾端去存取ECC的資料。
-Plane program
NAND Flash Vendor將Memory Array分成2個Plane,可以同時對2個不同Block addresses做Read/Write/Erase的操作。
Figure 4.2-Plane Program [6]
NAND-flash Management Issues
Address Translation
NAND Flash Memory的同1個page不能做重覆寫入的行為。再者,在寫入1個sector資料之前,必須要有抹除1個Block的資料才能做寫入的動作,但抹除 1個Block的動作需要耗費相當多的時間,此舉造成了NAND Flash效能下降的最大原因。為了改善效能,最有效的方法就是減少Erase的次數,因此有了Mapping Table。
Mapping Table的管理分為Block level、Sector level以及改良的Hybrid level。
Block level的address mapping是指1個Logical Block對應到1個Physical Block,它的mapping table相對於sector-level的mapping table來的小,能夠節省mapping table所占RAM的使用量。但當Logical Block的個數少於Physical Block個數時,會發生Logical Block時常被overwrite的狀況,選定要overwrite的Logical block和它mapping的Physical Block都要將資料更新到新的Physical Block上,且做erase-before-write的動作,而造成效能的下降,此外轉換單位大,每次寫入的單位也大,因此會帶來額外的資料寫入成本。
而Sector-Level的address mapping是1個Logical Sector可以對應到任1個Physical Block裡的Sector,雖然這種mapping的方式彈性佳,可以減少因轉換單位大而帶來額外的資料寫入成本,但是mapping table的Size過大,例如1GB的Flash,1個sector的大小為512byte的話,RAM就要維護二百萬筆的sector資訊。
Figure 5. 資料區塊,紀錄區塊,以及備用區塊的使用。
(a)完整的資料區塊(b)資料依序寫入紀錄區塊的可寫頁中(c)區塊鏈的Merge
改良的Hybrid level,擷取Block level和Sector level的優點,採用Block level的方式,再加上有限數量的Block做為Sector level的mapping,除了讓mapping table的size限制住不至於龐大,也減少了erase-before-write的動作。Hybrid level中,將Physical Block取名為資料區塊(Data Block),因為資料不能直接更新於資料區塊裡,我們找了一段可寫的Block來紀錄更新的資料,並將它取名為紀錄區塊(Log Block)。經過一段時間的寫入,一個LBA(Logical Block Address)對應會對應一個資料區塊,而此資料區塊會跟著數個紀錄區塊,整個形成一個區塊鏈(Block Chain),如圖5(b)所示。
Figure 6.Hybrid Level mapping table [7]
Hybrid Level在做write的時候,在寫第1、2筆資料時(sector 4,5),會由block level的mapping table找出Data Block 10,因為對應sector裡內容是空的,因此就直接寫入Data Block 10裡。而寫第3筆資料時(sector 4),由Block level的mapping table找到Data Block 10,但裡面已有寫入的資料,故改由sector level的mapping table找尋空的Log Block,寫入第3筆資料。在寫第4筆資料時(sector 4),因為sector level的mapping table裡已有mapped的Log Block,故將第4筆資料依序寫入對映的Log Block裡。
而在讀取時,會先由Sector level的mapping table裡,找出最新的資料,而Log Block裡沒有的資料,則由Block Level mapping table裡找到的Data Block裡。
Garbage Collection
主要是用於將不必要存在且浪費空間的Block做回收,來增加可用的Block數。當需要新 的Log Block時,會從已經使用的Log Block裡選取符合回收條件的Block來做Garbage Collection,如free sector低於threshold值。
被選定要回收的Log Block,會和它的Data Block做merge的動作,意即選取新的Data Block,將Log Block中sector資料copy到此新的Data Block中,再將原先Data Block中剩餘的sector資料複製到此新的Data Block中。
更新block-level table對應到新的Data Block,並將sector-level table裡將剛才回收的Log Block移除。原先的Log Block和Data Block做抹除的動作,即完成Garbage Collection了。
例如Figure 4中,要將Log block(pbn=20)做回收時,會將此log block中最新的資料(sector 4)複製到新的Data Block中(假設為pbn=12),再將它的Data block(pbn=10)中,其餘的資料(sector 5)複製到新的Data Block(pbn=12)中。並將block level table中對應到pbn=20的資料改為對應到pbn=12,即新的data block,再將sector level table中pbn=20(回收的log block)這筆資料刪除。最後將pbn=20,pbn=10舊的block做抹除的動作即可。
Merge在一種特殊情況下,可以做switch的動作,例如像Figure 4中,Log Block(pbn=30)裡是照sector的順序寫入,因此它的Data Block(pbn=11)裡的資料都是不需要使用的舊資料,要做Garbage Collection,只需要將Log Block和Data Block對調即可,即block-level table裡對應到pbn=11這筆資料改為對應到pbn=30,而sector-level table裡對應到pbn=30這筆刪除,然後將舊的Data Block(pbn=11)抹除就達到Garbage Collection了。
Figure 7.Garbage Collection Operation [3]
當在做Garbage Collection時,會希望用最少的cleaning work來獲得最多的free space,因此會選擇最多garbage的segment來做回收。另外,將資料的型態分為靜態和動態的資料。其中,Read-only data屬於靜態資料,即一旦創造就不會去修改它,而動態資料是會被修改的。動態資料依其資料修改頻率分為cold data(較少修改的資料)和hot data(修改頻繁的資料)。
依不同的資料型態,做資料搬移時的方式也分為三種:
Read-only Data mix with dynamic data
當要被回收的segment中有read-only data時,會先將所有的read-only data搬到新的segment裡。若此新的segment又會被回收時,之前搬移過的read-only data仍然會再被搬移一次。另外,當一個segment中的資料都為read-only data時,則此segment永遠不會被回收的。
Figure 8.Repeatedly migrating read-only data when they are mixed with dynamic data [9]
Cold data mix with hot data
當要被回收的segment中有cold data和hot data時,因cold data更改的頻率較少,在cleaning的期間cold data有較高的可能性為valid的,因此會將cold data搬移到新的segment裡。
Figure 9.Migrating cold data when they are mixed with hot data [9]
Data have high locality of reference
當要被回收segment中的data是有高度被參考性的,這些hot data在cleaning的過程中仍可能是valid,但在被搬移到新的segment時,hot data又被更新一次而成為garbage,這類的搬移即稱為useless migration。
Figure 10.Useless migration when hot data are updated soon after being migrated [9]
Wear-Leveling
當在使用Flash時,常會對某個檔案做修改的動作,當此時檔案變動而要用到更多的Page且 Flash中仍有空的Block時,會將空的 Block配置給此檔案來使用,若Flash中已經沒有空的Block時,則會執行Garbage Collection來清出空的Block以供使用。在挑選空的Block或執行Garbage Collection清出空的Block時,可能會造成部分的Block時常被挑選,這些Block可能因為被過度使用而造成損毀。為了避免這種情況發生,會使用Wear-Leveling,讓大部分Block的存取次數平均,而不會常常挑選到某些固定的Block上,造成Block的過度存取而損毀。
再者,NAND Flash抹除和寫入的reliability有使用的次數(100,000次),使用wear-leveling可以紀錄並平均每個block被使用的次數。
Wear-Leveling有兩種方式來實現,一種是在FileSystem和NAND Flash中間的FTL(Flash Translation Layer)裡實現的。FTL可以讓上層的OS透過FTL以disk的方式去讀寫下層的NAND Flash,另外也提供了virtual address和physical address的轉換。
Figure 11. Wear Leveling in the FTL [4]
另一種的實現方法為Wear Leveling直接在FileSystem裡實現,OS直接透過HAL和NAND Flash溝通。
Figure 12.Wear Leveling in the File System [4]
Flow Chart
Read
Figure 13 Read Operation Flow Chart
Erase
Figure 14 Erase Operation Flow Chart
Write
Figure 15 Write Operation Flow Chart
Timing/Power
Timing
Read Operation
BandWidth:39.82MB/s
Write Operation
BandWidth:4.66MB/s~1.36MB/s
Erase Operation
Power
P(typ)=3.3V*15mA=49.5mW
P(max)=3.6V*30mA=108mW
Read Operation
E(typ)=49.5mW*(195+180+4224*25+100)ns=49.5mW*106075ns
=
J
E(max)=108mW*(195+180+4224*25+100)ns=108mW*106075ns
=
J
Write Operation
E(typ)=49.5mW*(295+4224*25+100+
+200)ns
=49.5mW*906195ns
=
J
E(max)=108mW*(295+4224*25+100+
+200)ns
=108mW*3106195ns
=
J
Erase Operation
E(typ)=49.5mW*(245+
+200)ns=49.5mW*1500445ns
=
J
E(max)=108mW*(245+
+200)ns=108mW*10000445ns
=
J
Reference
Samsung Electronics, "K9GAG08UXM Specification"
Alex Kuo, "Application Note: Partial Page Program MirrorBit ORNAND with NAND interface", Spansion
STMicroelectronics, "AN1821 Garbage Collection in Single Level Cell NAND Flash memories"
STMicroelectronics, "AN1822 Wear Leveling in Single Level Cell NAND Flash memories"
STMicroelectronics, "AN1728 How to use the Copy Back feature of ST Small Page NAND Flash memories"
Amber Huffman, ONFI Technical Chair, "Flash Performance Enhancements through ONFI", Intel Corporation
S.-W. Lee, D.-J. Park, T.-S. Chung, D.-H. Lee, S.-W. Park, H.-J. Song, "A Log Buffer-Based Flash Translation Layer Using Fully-Associative Sector Translation", ACM Transactions on Embedded Computing Systems, Vol.6,No.3,Article 18,Publication date: July 2007
STMicroelectronics, "AN1820 How to use the FTL and HAL Software Modules to Manage Data in Single Level Cell NAND Flash Memories"
Mei-Ling Chiang, Paul C. H. Lee, Ruei-Chuan Chang, "Cleaning Policies in Mobile Computers Using Flash Memory", Journal of Systems and Software, v.48 n.3, p.213-231, Nov. 1, 1999
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/renpine/archive/2009/09/19/4570538.aspx
為什么Micron的NAND Flash能達到200MB/s的讀取速度
今天看到新聞Intel, Micron claim world’s fastest NAND flash,就直接到Micron的網站上瀏覽了一下。Micron的新產品分類為High Speed NAND Flash Products,用“High Speed”與原有NAND產品系列區分(估計ONFI 3.0兼容的產品出來后,還要加上“Ultra”,才能再分出一個類別來)。 riple
Micron的High Speed系列目前按照容量分為8Gb、16Gb、32Gb三種,按照接口個數分為單端口(8Gb)和雙端口(16、32Gb)兩種。在Micron的網站上還看不到詳細的datasheet,只能看到一個Product Brief和Flyer。 riple
通過Product Brief可以得到8Gb芯片的如下信息:采用了50nm而不是72nm工藝生產;是SLC而不是MLC結構;BGA封裝取代了TSOP封 裝;4096Byte/Page,128Page/Block,512Block x 1/Plane,4Planes;I/O分為異步和同步(DDR)兩種模式;速度最高的同步傳輸模式,讀寫I/O時間都是6ns/Toggle;讀 Array 30us/Page,寫Array 160us/Page,擦Array 3ms/Block。 riple
從上面的信息可以看出,High Speed特性要歸功於6ns/Toggle的I/O時間,對於8bit的接口來說,相當於166MB/s的傳輸速度。 riple
但是,NAND Flash的訪問速度不僅僅取決於I/O速度,還和Array傳輸時間、芯片內部緩沖結構和Plane數量有關。 riple
〇、NAND Flash訪問時間分析 riple
訪問操作 = 命令輸入 + I/O操作 + Array傳輸操作,第一項的操作時間所占比例很小,在性能估算中可以忽略。 riple
訪問時間 = I/O時間 + Array傳輸時間,在上一代NAND Flash中,第一項占的比例最大,是第二項的4-5倍。 riple
Micron主要采用了如下的4種技術縮短了平均的訪問時間。其中第一種技術是第一次在NAND Flash上應用,也是這次“大提速”的核心技術。正是這項技術的采用,使上述公式中的第一項縮小到上一代的1/5,才使得其他3項技術發揮了最佳的效果。 riple
一、接口傳輸模式對I/O速度的影響 riple
采用ONFi 2.0提出的DDR接口,提高了I/O數據傳輸速率:源同步(縮小了建立保持時間要求)、雙邊沿觸發(加倍了數據傳輸速率)。 riple
二、Block結構和生產工藝對Array傳輸速度的影響 riple
與上一代NAND Flash相比,Page容量加倍,在Array傳輸時間基本不變的情況下,等效地加倍了Array傳輸速度。 riple
72nm到50nm的工藝改進,縮小了芯片面積,提高了芯片速度(讀Array速度提升不明顯,寫Array速度提升了1倍),降低了功耗。 riple
三、緩沖與緩存對速度的影響 riple
Micron的NAND Flash的一大特點是:每一個Plane對應一個Page大小的緩沖(data register)和一個Page大小的緩存(cache register)。數據寫入的順序是:I/O -> cache register -> data register -> Plane,數據讀出的順序剛好相反。緩沖(data register)與緩存(cache register)之間的數據傳輸速度很快,data register可以把I/O操作和Array操作分隔開,形成I/O操作和Array操作的“兩級流水線”。這種結構與上一代NAND Flash一樣。(其實,4個Plane對應4個data register和1個cache register即可) riple
四、多Plane操作對速度的影響 riple
4個Plane對應4組緩沖與緩存,每一組可以分別操作。2個Plane交替操作,可以實現“乒乓操作”,達到2倍的Array訪問帶寬。4個Plane 交替操作,可以實現“乒乒乓乓操作”,達到4倍的Array訪問帶寬。在上一代的NAND Flash芯片中,采用2Plane結構是比較常見的。 riple
五、200MB/s的讀速度和100MB/s的寫速度是怎樣得到的 riple
讀I/O時間:1Toggle/Byte x 6ns/Toggle x 4096Byte/Page = 24.6us/Page,與讀Array時間30us/Page近似。在采用cache模式的讀操作下,兩級流水線的速度取決於“I/O速度”和“讀 Array速度”中較慢的一個,不采用多Plane操作,平均速度只能達到讀Array速度,即4096Byte/30us =136MB/s;在2Plane模式下,讀Array時間縮短至15us/Page,小於讀I/O時間24.6us/Page,兩級流水線的速度取決於 “I/O速度”,平均速度達到I/O速度4096Byte/24.6us = 166MB/s,這與宣傳中200MB/s的速度還有些差距。我們采用的I/O周期值是數據手冊給出的,芯片實際能夠運行的I/O速度往往要略高一些:在上面的分析中,只要I/O周期縮短至5ns/Toggle,“超頻”后的讀I/O時間就縮短至20us/Page,大於讀Array時間15us /Page,兩級流水線的速度仍然取決於“I/O速度”,這樣一來平均讀取速度就能達到4096Byte/20us =200MB/s。(從上面的分析看,如果不對I/O速度進行“超頻”,平均讀取速度是達不到200MB/s的,看來宣傳還是略有誇張的) riple
寫I/O時間:1Toggle/Byte x 6ns/Toggle x 4096Byte/Page = 24.6us/Page,與寫Array時間160us/Page相差很多,單獨采用cache模式不夠,還要采用4Plane的“乒乒乓乓操作”,縮短 寫Array時間,盡量均衡流水線的兩級操作時間。4Plane模式平均Array寫操作時間為一次Array寫操作時間的1/4,40us/Page。所以在cache模式配合4Plane模式的寫操作下,流水線的速度等於流水線兩級中最慢的“平均Array寫速度”,可以近似為:4096Byte/40us = 102MB/s。 riple
從上面的分析可以看出,I/O速度限制了讀取速度的最大值,在ONFi 3.0預計的400MB/s的I/O速度實現后,NAND Flash的平均讀取速度也能夠達到400MB/s(這回就要采用4Plane模式了);Array傳輸速度限制了寫入速度的最大值,如果不對芯片的內部 結構和生產工藝進行改進的話,NAND Flash的平均寫入速度很難進一步提高。 riple
nand flash 總結
flash 2009-12-09 13:21:37 閱讀118 評論0 字號:大中小 訂閱
NAND Flash產品可以分為三大架構,分別是Single Level Cell;SLC,包括三星電子、Hynix、Micron以及東芝都是此技術使用者,第二種則是Multi Level Cell;MLC,目前有東芝、Renesas使用,不過三星電子將在2005第四季推出相關產品,最后則是Infineon與Saifun Semiconductors合資利用NROM技術所共同開發的Multi Bit Cell;MBC。
MLC是Intel在1997年9月最先開發成功的,其作用是將兩個位的信息存入一個 Floating Gate(NADA Flash存儲單元中存放電荷的部分),然后利用不同Level的電荷,透過內存儲存格的電壓控制精准讀寫,假設以4種電壓控制、1個晶體管可存取2 bits 的數據,若是控制8種電壓就可以存取3 bits 的數據,使Flash 的容量大幅提升,類似Rambus的QRSL技術,通過精確控制浮動柵上的電荷數量,使其呈現出4種不同的存儲狀態,每種狀態代表兩個二進制數值(從00 到11)。
當然不光是NOR型NAND Flash在使用,東芝在2003年2月推出第一款MLC型的NAND Flash,並接續2004年4月推出采用MLC技術的4Gbit與8Gbit NAND Flash,顯然這對於本來就以容量見長的NAND Flash更是如虎添翼。根據Semiconductor Insights研究,東芝利用90nm MLC技術所開發出來的4Gb,其die面積為144 mm2。
至於SLC技術與EEPROM相同,但在Floating gate與Source gate之中的氧化薄膜更薄,其數據的寫入是透過對浮置閘極的電荷加電壓,然后可以透過源極,即可將所儲存的電荷消除,藉由這樣的方式,便可儲存1個個信 息位,這種技術的單一位細胞方式能提供快速的程序編程與讀取,不過此技術受限於Silicon efficiency的問題,必須要藉由較先進的流程強化技術Process enhancements,才能向上提升SLC制程技術。
將上述所言,做一個比較,SLC架構是0和1兩個充電值,而MLC架構可以一次儲存4個以上的充電值,因此MLC架構可以有比較好的儲存密度,再加上可利用比較老舊的生產設備來提高產品的容量,而無須額外投資生產設備,可以享有成本與良率的優勢。
不過MLC架構有着讓使用者很難容忍的缺點,就是使用壽命較短,其次MLC架構只能承受約1 萬次的存取,遠低於SLC架構的10萬次。至於存取速度,SLC架構比MLC架構要快速三倍以上,加上MLC架構對於電力的消耗較多,因此使用者若是考慮長久使用、安全儲存數據以及高速的存取速度等要求,恐怕會改采用SLC架構。
其實在NAND Flash市場中,若以理論數據比較,Renesas的AG-AND技術或是Infineon的MBC技術,其實並不遜於三星電子、東芝或是其它業者,甚 至於有過之而無不及,不過這兩家業者因為產能、技術開發等問題造成延遲擴大市場占有率時機,這也印證商場中的一句話,任何東西都必須要能夠適時適地推出,否則只是將市場拱手讓給對方。
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),每頁528Byte,每32 個page 形成一個Block, Sizeof(block)=16kByte 。1 block=16kbyte,512Mbit=64Mbyte,Numberof(block)=1024 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash 以頁為單位讀寫數據,而以塊為單位擦除數據。按照這樣的組織方式可以形成所謂的三類地址: --Block Address -- Page Address --Column Address(即為頁內偏移地址)
對於NAND Flash 來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度是8 位。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被 分成1st half和2nd half,各自的訪問由地址指針命令來選擇,A[7:0]就是所謂的column address。32 個page 需要5bit 來表示,占用A[13:9],即該page 在塊內的相對地址。Block的地址是由A14 以上的bit 來表示,例如512Mb 的NAND,共4096block,因此,需要12 個bit 來表示,即A[25:14],如果是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 即bit8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀寫。而真正的bit8 的值是don\'t care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此尋址 只需要3 步。
下面,就x16 的NAND flash 器件稍微進行一下說明。 由於一個page 的main area 的容量為256word,仍相當於512byte。但是,這個時候沒有所謂 的1st halfpage 和2nd halfpage 之分了,所以,bit8就變得沒有意義了,也就是這個時候 bit8 完全不用管,地址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
norflash和nandflash的區別
norflash中可以運行程序,nandflash不可以
Nor flash按sector可擦除,按bit可讀寫。Nand Flash按Block可擦除,按Page可讀寫。
最主要是尋址方式不同
*********************************************************************************************************************************
Nand Flash 尋址方式
NAND Flash的尋址方式和NAND Flash的memory組織方式緊密相關。NAND Flash的數據是以bit的方式保存在memory cell,一般來說,一個cell中只能存儲一個bit。這些cell以8個或者16個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device的位寬。
這些Line會再組成Page,通常是528Byte/page或者264Word/page。然后,每32個page形成一個Block,Sizeof(block)=16kByte.
Block是NAND Flash中最大的操作單元,擦除就是按照block為單位完成的,而
編程/讀取是按照page為單位完成的。
所以,按照這樣的組織方式可以形成所謂的三類地址:
-Block Address
-Page Address
-Column Address
首先,必須清楚一點,對於NAND Flash來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度可以是8位或者16位,但是,對於x16的NAND Device,I/O[15:8]只用於傳遞數據。
清楚了這一點,我們就可以開始分析NAND Flash的尋址方式了。
以528Byte/page 總容量512Mbit+512kbyte的NAND器件為例:
因為,
1 block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area)
用戶數據保存在main area中。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由所謂的pointer operation命令來選擇,也就是選擇了bit8的高低。因此A8就是halfpage pointer,A[7:0]就是所謂的column address。
32個page需要5bit來表示,占用A[13:9],即該page在塊內的相對地址。Block的地址是由A14以上的bit來表示,例如512Mb 的NAND,共4096block,因此,需要12個bit來表示,即A[25:14],如果是1Gbit的528byte/page的NAND Flash,共8192個block,則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即bit8是由操作指令決定的,即指令決定在哪個halfpage上進行讀寫,而真正的bit8的值是don't care的。
第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的容量是256Mbit以下,那么,block adress最高位只到bit24,因此尋址只需要3步。
NAND Flash 的數據是以bit 的方式保存在memory cell,一般來說,一個cell 中只能存儲一個bit。這些cell 以8 個或者16 個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device 的位寬。這些Line 會再組成Page.
(Nand Flash 有多種結構,下面內容針對三星的K9F1208U0M),每頁528Byte,每32 個page 形成一個Block, Sizeof(block)=16kByte 。
1 block="16kbyte",
512Mbit=64Mbyte,
Numberof(block)=4096 1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area) ;
Nand flash 以頁為單位讀寫數據,而以塊為單位擦除數據。
按照這樣的組織方式可以形成所謂的三類地址:
--Block Address
-- Page Address
--Column Address
對於NAND Flash 來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度是8 位。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由地址指針命令來選擇,A[7:0]就是所謂的column address。
32 個page 需要5bit 來表示,占用A[13:9],即該page 在塊內的相對地址。Block的地址是由A14 以上的bit 來表示,例如512Mb 的NAND,共4096block,因此,需要12 個bit 來表示,即A[25:14],如果是1Gbit 的528byte/page的NAND Flash,則block address用A[26:24]表示。而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 即bit8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀寫。而真正的bit8 的值是don't care 的。
第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此尋址 只需要3 步。 下面,就x16 的NAND flash 器件稍微進行一下說明。 由於一個page 的main area 的容量為256word,仍相當於512byte。但是,這個時候沒有所謂 的1st halfpage 和2nd halfpage 之分了,所以,bit8就變得沒有意義了,也就是這個時候 bit8 完全不用管,地址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
正如硬盤的盤片被分為磁道,每個磁道又分為若干扇區,一塊nand flash也分為若干block,每個block分為如干page。一般而言,block、page之間的關系隨着芯片的不同而不同,典型的分配是這樣的:
1block = 32page
1page = 512bytes(datafield) + 16bytes(oob)
需要注意的是,對於flash的讀寫都是以一個page開始的,但是在讀寫之前必須進行flash的擦寫,而擦寫則是以一個block為單位的。同時必須提醒的是,512bytes理論上被分為1st half 和2sd half,每個half各占256個字節。
我們討論的K9F1208U0B總共有4096 個Blocks,故我們可以知道這塊flash的容量為4096 *(32 *528)= 69206016 Bytes = 66 MB 但事實上每個Page上的最后16Bytes是用於存貯檢驗碼和其他信息用的,並不能存放實際的數據,所以實際上我們可以操作的芯片容量為4096 *(32 *512) = 67108864 Bytes = 64 MB由 上圖所示,1個Page總共由528 Bytes組成,這528個字節按順序由上而下以列為單位進行排列(1列代表一個Byte。第0行為第0 Byte ,第1行為第1 Byte,以此類推,每個行又由8個位組成,每個位表示1個Byte里面的1bit)。這528Bytes按功能分為兩大部分,分別是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,這16Bytes是用於在讀寫操作的時候存放校驗碼用的,一般不用做普通數據的存儲區,除去這 16Bytes,剩下的512Bytes便是我們用於存放數據用的Data Field,所以一個Page上雖然有528個Bytes,但我們只按512Bytes進行容量的計算。
讀 命令有兩個,分別是 Read1,Read2其中Read1用於讀取Data Field的數據,而Read2則是用於讀取Spare Field的數據。對於Nand Flash來說,讀操作的最小操作單位為Page,也就是說當我們給定了讀取的起始位置后,讀操作將從該位置開始,連續讀取到本Page的最后一個 Byte為止(可以包括Spare Field)
Nand Flash的尋址
Nand Flash的地址寄存器把一個完整的Nand Flash地址分解成Column Address與Page Address.進行尋址。
Column Address: 列地址。Column Address其實就是指定Page上的某個Byte,指定這個Byte其實也就是指定此頁的讀寫起始地址。
Paage Address:頁地址。由於頁地址總是以512Bytes對齊的,所以它的低9位總是0。確定讀寫操作是在Flash上的哪個頁進行的。
Read1命令
當我們得到一個Nand Flash地址src_addr時我們可以這樣分解出Column Address和Page Address
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以這么認為,一個Nand Flash地址的A0~A7是它的column_addr,A9~A25是它的Page Address。(注意地址位A8並沒有出現,也就是A8被忽略,在下面你將了解到這是什么原因)
Read1 命令的操作分為4個Cycle,發送完讀命令00h或01h(00h與01h的區別請見下文描述)之后將分4個Cycle發送參數,1st.Cycle是發送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle則是指定Page Address(每次向地址寄存器發送的數據只能是8位,所以17位的Page Address必須分成3次進行發送
Read1的 命令里面出現了兩個命令選項,分別是00h和01h。這里出現了兩個讀命是否令你意識到什么呢?是的,00h是用於讀寫1st half的命令,而01h是用於讀取2nd half的命令。現在我可以結合上圖給你說明為什么K9F1208U0B的DataField被分為2個half了。
如上文我所提及的,Read1的1st.Cycle是發送Column Address,假設我現在指定的Column Address是0,那么讀操作將從此頁的第0號Byte開始一直讀取到此頁的最后一個Byte(包括Spare Field),如果我指定的Column Address是127,情況也與前面一樣,但不知道你發現沒有,用於傳遞Column Address的數據線有8條(I/O0~I/O7,對應A0~A7,這也是A8為什么不出現在我們傳遞的地址位中),也就是說我們能夠指定的 Column Address范圍為0~255,但不要忘了,1個Page的DataField是由512個Byte組成的,假設現在我要指定讀命令從第256個字節處 開始讀取此頁,那將會發生什么情景?我必須把Column Address設置為256,但Column Address最大只能是255,這就造成數據溢出。。。正是因為這個原因我們才把Data Field分為兩個半區,當要讀取的起始地址(Column Address)在0~255內時我們用00h命令,當讀取的起始地址是在256~511時,則使用01h命令.假設現在我要指定從第256個byte開 始讀取此頁,那么我將這樣發送命令串
column_addr=256;
NF_CMD=0x01; ? 從2nd half開始讀取
NF_ADDR=column_addr&0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
其中NF_CMD和NF_ADDR分別是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般這樣定義它們,
#define rNFCMD (*(volatile unsigned char *)0x4e000004) //NADD Flash command
#define rNFADDR (*(volatile unsigned char *)0x4e000008) //NAND Flash address
事實上,當NF_CMD=0x01時,地址寄存器中的第8位(A8)將被設置為1(如上文分析,A8位不在我們傳遞的地址中,這個位其實就是硬件電路根據 01h或是00h這兩個命令來置高位或是置低位),這樣我們傳遞column_addr的值256隨然由於數據溢出變為1,但A8位已經由於NF_CMD =0x01的關系被置為1了,所以我們傳到地址寄存器里的值變成了
A0 A1 A2 A3 A4 A5 A6 A7 A8
1 0 0 0 0 0 0 0 1
這8個位所表示的正好是256,這樣讀操作將從此頁的第256號byte(2nd half的第0號byte)開始讀取數據。 nand_flash.c中包含3個函數
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);
nf_reset()將被nf_init()調用。nf_init()是nand_flash的初始化函數,在對nand flash進行任何操作之前,nf_init()必須被調用。
nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);為讀函數,src_addr是nand flash上的地址,desc_addr是內存地址,size是讀取文件的長度。
在nf_reset和nf_read函數中存在兩個宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到當每次對Nand Flash進行操作之前NF_nFCE_L()必定被調用,操作結束之時NF_nFCE_H()必定被調用。這兩個宏用於啟動和關閉Flash芯片的工作(片選/取消片選)。至於nf_reset()中的
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
這一行代碼是對NandFlash的控制寄存器進行初始化配置,rNFCONF是Nand Flash的配置寄存器,各個位的具體功能請參閱s3c2410數據手冊。
現在舉一個例子,假設我要從Nand Flash中的第5000字節處開始讀取1024個字節到內存的0x30000000處,我們這樣調用read函數
nf_read(5000, 0x30000000,1024);
我們來分析5000這個src_addr.
根據
column_addr=src_addr%512;
page_address=(src_addr>>9);
我們可得出column_addr=5000%512=392
page_address=(5000>>9)=9
於是我們可以知道5000這個地址是在第9頁的第392個字節處,於是我們的nf_read函數將這樣發送命令和參數
column_addr=5000%512;
>page_address=(5000>>9);
NF_CMD=0x01; 從2nd half開始讀取
NF_ADDR= column_addr &0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
向NandFlash的命令寄存器和地址寄存器發送完以上命令和參數之后,我們就可以從rNFDATA寄存器(NandFlash數據寄存器)讀取數據了.
我用下面的代碼進行數據的讀取.
for(i=column_addr;i<512;i++)
{
*buf++=NF_RDDATA();
}
每當讀取完一個Page之后,數據指針會落在下一個Page的0號Column(0號Byte).
下面是源代碼:
/*
author: caiyuqing
本代碼只屬於交流學習,不得用於商業開發
*/
#include "s3c2410.h"
#include "nand_flash.h"
static unsigned char seBuf[16]={0xff};
//--------------------------------------------------------------------------------------
unsigned short nf_checkId(void)
{
int i;
unsigned short id;
NF_nFCE_L(); //chip enable
NF_CMD(0x90); //Read ID
NF_ADDR(0x0);
for(i=0;i<10;i++); //wait tWB(100ns)
id="NF"_RDDATA()<<8; // Maker code(K9S1208V:0xec)
id|=NF_RDDATA(); // Devide code(K9S1208V:0x76)
NF_nFCE_H(); //chip enable
return id;
}
//--------------------------------------------------------------------------------------
static void nf_reset(void)
{
int i;
NF_nFCE_L(); //chip enable
NF_CMD(0xFF); //reset command
for(i=0;i<10;i++); //tWB = 100ns.
NF_WAITRB(); //wait 200~500us;
NF_nFCE_H(); //chip disable
}
//--------------------------------------------------------------------------------------
void nf_init(void)
{
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
// 1 1 1 1 1 xxx r xxx, r xxx
// En r r ECCR nFCE="H" tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size)
{
int i;
unsigned int column_addr = src_addr % 512; // column address
unsigned int page_address = (src_addr >> 9); // page addrress
unsigned char *buf = desc_addr;
while((unsigned int)buf < (unsigned int)(desc_addr) + size)
{
NF_nFCE_L(); // enable chip
/*NF_ADDR和NF_CMD為nand_flash的地址和命令寄存器的解引用*/
if(column_addr > 255) // 2end halft
NF_CMD(0x01); // Read2 command. cmd 0x01: Read command(start from 2end half page)
else
NF_CMD(0x00); // 1st halft?
NF_ADDR(column_addr & 0xff); // Column Address
NF_ADDR(page_address & 0xff); // Page Address
NF_ADDR((page_address >> 8) & 0xff); // ...
NF_ADDR((page_address >> 16) & 0xff); // ..
for(i = 0; i < 10; i++); // wait tWB(100ns)/////??????
NF_WAITRB(); // Wait tR(max 12us)
// Read from main area
for(i = column_addr; i < 512; i++)
{
*buf++= NF_RDDATA();
}
NF_nFCE_H(); // disable chip
column_addr = 0;
page_address++;
}
return ;
}
今天在利用ARM7上的nandflash控制器驅動,ID已讀取成功,擦寫,讀取等尚未完成,晚上就在網上查查相關的知識,覺得有一個不錯,轉貼如下:
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),每頁528Byte,每32 個page 形成一個Block, Sizeof(block)=16kByte 。
1 block="16kbyte",512Mbit=64Mbyte,Numberof(block)=4096 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash 以頁為單位讀寫數據,而以塊為單位擦除數據。
按照這樣的組織方式可以形成所謂的三類地址:
--Block Address -- Page Address --Column Address
對於NAND Flash 來講,地址和命令只能在I/O[7:0]上傳遞,數據寬度是8 位。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由地址指針命令來選擇,A[7:0]就是所謂的column address。
32 個page 需要5bit 來表示,占用A[13:9],即該page 在塊內的相對地址。Block的地址是由A14 以上的bit 來表示,例如512Mb 的NAND,共4096block,因此,需要12 個bit 來表示,即A[25:14],如果是1Gbit 的528byte/page的NAND Flash,則block address用A[26:24]表示。而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 即bit8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀寫。而真正的bit8 的值是don't care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此尋址 只需要3 步。 下面,就x16 的NAND flash 器件稍微進行一下說明。 由於一個page 的main area 的容量為256word,仍相當於512byte。但是,這個時候沒有所謂 的1st halfpage 和2nd halfpage 之分了,所以,bit8就變得沒有意義了,也就是這個時候 bit8 完全不用管,地址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
正如硬盤的盤片被分為磁道,每個磁道又分為若干扇區,一塊nand flash也分為若干block,每個block分為如干page。一般而言,block、page之間的關系隨着芯片的不同而不同,典型的分配是這樣的:
1block = 32page
1page = 512bytes(datafield) + 16bytes(oob)
需要注意的是,對於flash的讀寫都是以一個page開始的,但是在讀寫之前必須進行flash的擦寫,而擦寫則是以一個block為單位的。同時必須提醒的是,512bytes理論上被分為1st half 和2sd half,每個half各占256個字節。
我們討論的K9F1208U0B總共有4096 個Blocks,故我們可以知道這塊flash的容量為4096 *(32 *528)= 69206016 Bytes = 66 MB 但事實上每個Page上的最后16Bytes是用於存貯檢驗碼和其他信息用的,並不能存放實際的數據,所以實際上我們可以操作的芯片容量為4096 *(32 *512) = 67108864 Bytes = 64 MB由 上圖所示,1個Page總共由528 Bytes組成,這528個字節按順序由上而下以列為單位進行排列(1列代表一個Byte。第0行為第0 Byte ,第1行為第1 Byte,以此類推,每個行又由8個位組成,每個位表示1個Byte里面的1bit)。這528Bytes按功能分為兩大部分,分別是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,這16Bytes是用於在讀寫操作的時候存放校驗碼用的,一般不用做普通數據的存儲區,除去這 16Bytes,剩下的512Bytes便是我們用於存放數據用的Data Field,所以一個Page上雖然有528個Bytes,但我們只按512Bytes進行容量的計算。
讀 命令有兩個,分別是 Read1,Read2其中Read1用於讀取Data Field的數據,而Read2則是用於讀取Spare Field的數據。對於Nand Flash來說,讀操作的最小操作單位為Page,也就是說當我們給定了讀取的起始位置后,讀操作將從該位置開始,連續讀取到本Page的最后一個 Byte為止(可以包括Spare Field)
Nand Flash的尋址
Nand Flash的地址寄存器把一個完整的Nand Flash地址分解成Column Address與Page Address.進行尋址。
Column Address: 列地址。Column Address其實就是指定Page上的某個Byte,指定這個Byte其實也就是指定此頁的讀寫起始地址。
Paage Address:頁地址。由於頁地址總是以512Bytes對齊的,所以它的低9位總是0。確定讀寫操作是在Flash上的哪個頁進行的。
Read1命令
當我們得到一個Nand Flash地址src_addr時我們可以這樣分解出Column Address和Page Address
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以這么認為,一個Nand Flash地址的A0~A7是它的column_addr,A9~A25是它的Page Address。(注意地址位A8並沒有出現,也就是A8被忽略,在下面你將了解到這是什么原因)
Read1 命令的操作分為4個Cycle,發送完讀命令00h或01h(00h與01h的區別請見下文描述)之后將分4個Cycle發送參數,1st.Cycle是發送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle則是指定Page Address(每次向地址寄存器發送的數據只能是8位,所以17位的Page Address必須分成3次進行發送
Read1的 命令里面出現了兩個命令選項,分別是00h和01h。這里出現了兩個讀命是否令你意識到什么呢?是的,00h是用於讀寫1st half的命令,而01h是用於讀取2nd half的命令。現在我可以結合上圖給你說明為什么K9F1208U0B的DataField被分為2個half了。
如上文我所提及的,Read1的1st.Cycle是發送Column Address,假設我現在指定的Column Address是0,那么讀操作將從此頁的第0號Byte開始一直讀取到此頁的最后一個Byte(包括Spare Field),如果我指定的Column Address是127,情況也與前面一樣,但不知道你發現沒有,用於傳遞Column Address的數據線有8條(I/O0~I/O7,對應A0~A7,這也是A8為什么不出現在我們傳遞的地址位中),也就是說我們能夠指定的 Column Address范圍為0~255,但不要忘了,1個Page的DataField是由512個Byte組成的,假設現在我要指定讀命令從第256個字節處 開始讀取此頁,那將會發生什么情景?我必須把Column Address設置為256,但Column Address最大只能是255,這就造成數據溢出。。。正是因為這個原因我們才把Data Field分為兩個半區,當要讀取的起始地址(Column Address)在0~255內時我們用00h命令,當讀取的起始地址是在256~511時,則使用01h命令.假設現在我要指定從第256個byte開 始讀取此頁,那么我將這樣發送命令串
column_addr=256;
NF_CMD=0x01; ? 從2nd half開始讀取
NF_ADDR=column_addr&0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
其中NF_CMD和NF_ADDR分別是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般這樣定義它們,
#define rNFCMD (*(volatile unsigned char *)0x4e000004) //NADD Flash command
#define rNFADDR (*(volatile unsigned char *)0x4e000008) //NAND Flash address
事實上,當NF_CMD=0x01時,地址寄存器中的第8位(A8)將被設置為1(如上文分析,A8位不在我們傳遞的地址中,這個位其實就是硬件電路根據 01h或是00h這兩個命令來置高位或是置低位),這樣我們傳遞column_addr的值256隨然由於數據溢出變為1,但A8位已經由於NF_CMD =0x01的關系被置為1了,所以我們傳到地址寄存器里的值變成了
A0 A1 A2 A3 A4 A5 A6 A7 A8
1 0 0 0 0 0 0 0 1
這8個位所表示的正好是256,這樣讀操作將從此頁的第256號byte(2nd half的第0號byte)開始讀取數據。 nand_flash.c中包含3個函數
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);
nf_reset()將被nf_init()調用。nf_init()是nand_flash的初始化函數,在對nand flash進行任何操作之前,nf_init()必須被調用。
nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);為讀函數,src_addr是nand flash上的地址,desc_addr是內存地址,size是讀取文件的長度。
在nf_reset和nf_read函數中存在兩個宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到當每次對Nand Flash進行操作之前NF_nFCE_L()必定被調用,操作結束之時NF_nFCE_H()必定被調用。這兩個宏用於啟動和關閉Flash芯片的工作(片選/取消片選)。至於nf_reset()中的
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
這一行代碼是對NandFlash的控制寄存器進行初始化配置,rNFCONF是Nand Flash的配置寄存器,各個位的具體功能請參閱s3c2410數據手冊。
現在舉一個例子,假設我要從Nand Flash中的第5000字節處開始讀取1024個字節到內存的0x30000000處,我們這樣調用read函數
nf_read(5000, 0x30000000,1024);
我們來分析5000這個src_addr.
根據
column_addr=src_addr%512;
page_address=(src_addr>>9);
我們可得出column_addr=5000%512=392
page_address=(5000>>9)=9
於是我們可以知道5000這個地址是在第9頁的第392個字節處,於是我們的nf_read函數將這樣發送命令和參數
column_addr=5000%512;
>page_address=(5000>>9);
NF_CMD=0x01; 從2nd half開始讀取
NF_ADDR= column_addr &0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
向NandFlash的命令寄存器和地址寄存器發送完以上命令和參數之后,我們就可以從rNFDATA寄存器(NandFlash數據寄存器)讀取數據了.
我用下面的代碼進行數據的讀取.
for(i=column_addr;i<512;i++)
{
*buf++=NF_RDDATA();
}
每當讀取完一個Page之后,數據指針會落在下一個Page的0號Column(0號Byte).
下面是源代碼:
/*
author: caiyuqing
本代碼只屬於交流學習,不得用於商業開發
*/
#include "s3c2410.h"
#include "nand_flash.h"
static unsigned char seBuf[16]={0xff};
//--------------------------------------------------------------------------------------
unsigned short nf_checkId(void)
{
int i;
unsigned short id;
NF_nFCE_L(); //chip enable
NF_CMD(0x90); //Read ID
NF_ADDR(0x0);
for(i=0;i<10;i++); //wait tWB(100ns)
id="NF"_RDDATA()<<8; // Maker code(K9S1208V:0xec)
id|=NF_RDDATA(); // Devide code(K9S1208V:0x76)
NF_nFCE_H(); //chip enable
return id;
}
//--------------------------------------------------------------------------------------
static void nf_reset(void)
{
int i;
NF_nFCE_L(); //chip enable
NF_CMD(0xFF); //reset command
for(i=0;i<10;i++); //tWB = 100ns.
NF_WAITRB(); //wait 200~500us;
NF_nFCE_H(); //chip disable
}
//--------------------------------------------------------------------------------------
void nf_init(void)
{
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
// 1 1 1 1 1 xxx r xxx, r xxx
// En r r ECCR nFCE="H" tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size)
{
int i;
unsigned int column_addr = src_addr % 512; // column address
unsigned int page_address = (src_addr >> 9); // page addrress
unsigned char *buf = desc_addr;
while((unsigned int)buf < (unsigned int)(desc_addr) + size)
{
NF_nFCE_L(); // enable chip
/*NF_ADDR和NF_CMD為nand_flash的地址和命令寄存器的解引用*/
if(column_addr > 255) // 2end halft
NF_CMD(0x01); // Read2 command. cmd 0x01: Read command(start from 2end half page)
else
NF_CMD(0x00); // 1st halft?
NF_ADDR(column_addr & 0xff); // Column Address
NF_ADDR(page_address & 0xff); // Page Address
NF_ADDR((page_address >> 8) & 0xff); // ...
NF_ADDR((page_address >> 16) & 0xff); // ..
for(i = 0; i < 10; i++); // wait tWB(100ns)/////??????
NF_WAITRB(); // Wait tR(max 12us)
// Read from main area
for(i = column_addr; i < 512; i++)
{
*buf++= NF_RDDATA();
}
NF_nFCE_H(); // disable chip
column_addr = 0;
page_address++;
}
return ;
}
Nand Flash結構與讀寫分析
今天在利用ARM7上的nandflash控制器驅動,ID已讀取成功,擦寫,讀取等尚未完成,晚上就在網上查查相關的知識,覺得有一個不錯,轉貼如下:
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),每頁528Byte,每32 個page 形成一個Block, Sizeof(block)=16kByte 。
1 block="16kbyte",512Mbit=64Mbyte,Numberof(block)=4096 1block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash 以頁為單位讀寫數據,而以塊為單位擦除數據。
按照這樣的組織方式可以形成所謂的三類地址:
--Block Address -- Page Address --Column Address
對於NAND Flash 來講,地址和命令只能在I/O【7:0】上傳遞,數據寬度是8 位。
512byte需要9bit來表示,對於528byte系列的NAND,這512byte被分成1st half和2nd half,各自的訪問由地址指針命令來選擇,A【7:0】就是所謂的column address。
32 個page 需要5bit 來表示,占用A【13:9】,即該page 在塊內的相對地址。Block的地址是由A14 以上的bit 來表示,例如512Mb 的NAND,共4096block,因此,需要12 個bit 來表示,即A【25:14】,如果是1Gbit 的528byte/page的NAND Flash,則block address用A【26:24】表示。而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 即bit8 是由操作指令決定的,即指令決定在哪個halfpage 上進行讀寫。而真正的bit8 的值是don‘t care 的。 第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 的容量是256Mbit 以下,那么,block adress 最高位只到bit24,因此尋址只需要3 步。 下面,就x16 的NAND flash 器件稍微進行一下說明。 由於一個page 的main area 的容量為256word,仍相當於512byte。但是,這個時候沒有所謂 的1st halfpage 和2nd halfpage 之分了,所以,bit8就變得沒有意義了,也就是這個時候 bit8 完全不用管,地址傳遞仍然和x8 器件相同。除了,這一點之外,x16 的NAND使用方法和 x8 的使用方法完全相同。
正如硬盤的盤片被分為磁道,每個磁道又分為若干扇區,一塊nand flash也分為若干block,每個block分為如干page。一般而言,block、page之間的關系隨着芯片的不同而不同,典型的分配是這樣的:
1block = 32page
1page = 512bytes(datafield) + 16bytes(oob)
需要注意的是,對於flash的讀寫都是以一個page開始的,但是在讀寫之前必須進行flash的擦寫,而擦寫則是以一個block為單位的。同時必須提醒的是,512bytes理論上被分為1st half 和2sd half,每個half各占256個字節。
我們討論的K9F1208U0B總共有4096 個Blocks,故我們可以知道這塊flash的容量為4096 *(32 *528)= 69206016 Bytes = 66 MB 但事實上每個Page上的最后16Bytes是用於存貯檢驗碼和其他信息用的,並不能存放實際的數據,所以實際上我們可以操作的芯片容量為4096 *(32 *512) = 67108864 Bytes = 64 MB由 上圖所示,1個Page總共由528 Bytes組成,這528個字節按順序由上而下以列為單位進行排列(1列代表一個Byte。第0行為第0 Byte ,第1行為第1 Byte,以此類推,每個行又由8個位組成,每個位表示1個Byte里面的1bit)。這528Bytes按功能分為兩大部分,分別是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,這16Bytes是用於在讀寫操作的時候存放校驗碼用的,一般不用做普通數據的存儲區,除去這 16Bytes,剩下的512Bytes便是我們用於存放數據用的Data Field,所以一個Page上雖然有528個Bytes,但我們只按512Bytes進行容量的計算。
讀 命令有兩個,分別是 Read1,Read2其中Read1用於讀取Data Field的數據,而Read2則是用於讀取Spare Field的數據。對於Nand Flash來說,讀操作的最小操作單位為Page,也就是說當我們給定了讀取的起始位置后,讀操作將從該位置開始,連續讀取到本Page的最后一個 Byte為止(可以包括Spare Field)
Nand Flash的尋址
Nand Flash的地址寄存器把一個完整的Nand Flash地址分解成Column Address與Page Address.進行尋址。
Column Address: 列地址。Column Address其實就是指定Page上的某個Byte,指定這個Byte其實也就是指定此頁的讀寫起始地址。
Paage Address:頁地址。由於頁地址總是以512Bytes對齊的,所以它的低9位總是0。確定讀寫操作是在Flash上的哪個頁進行的。
Read1命令
當我們得到一個Nand Flash地址src_addr時我們可以這樣分解出Column Address和Page Address
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以這么認為,一個Nand Flash地址的A0~A7是它的column_addr,A9~A25是它的Page Address。(注意地址位A8並沒有出現,也就是A8被忽略,在下面你將了解到這是什么原因)
Read1 命令的操作分為4個Cycle,發送完讀命令00h或01h(00h與01h的區別請見下文描述)之后將分4個Cycle發送參數,1st.Cycle是 發送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle則是指定Page Address(每次向地址寄存器發送的數據只能是8位,所以17位的Page Address必須分成3次進行發送
Read1的 命令里面出現了兩個命令選項,分別是00h和01h。這里出現了兩個讀命是否令你意識到什么呢?是的,00h是用於讀寫1st half的命令,而01h是用於讀取2nd half的命令。現在我可以結合上圖給你說明為什么K9F1208U0B的DataField被分為2個half了。
如上文我所提及的,Read1的1st.Cycle是發送Column Address,假設我現在指定的Column Address是0,那么讀操作將從此頁的第0號Byte開始一直讀取到此頁的最后一個Byte(包括Spare Field),如果我指定的Column Address是127,情況也與前面一樣,但不知道你發現沒有,用於傳遞Column Address的數據線有8條(I/O0~I/O7,對應A0~A7,這也是A8為什么不出現在我們傳遞的地址位中),也就是說我們能夠指定的 Column Address范圍為0~255,但不要忘了,1個Page的DataField是由512個Byte組成的,假設現在我要指定讀命令從第256個字節處 開始讀取此頁,那將會發生什么情景?我必須把Column Address設置為256,但Column Address最大只能是255,這就造成數據溢出。。。正是因為這個原因我們才把Data Field分為兩個半區,當要讀取的起始地址(Column Address)在0~255內時我們用00h命令,當讀取的起始地址是在256~511時,則使用01h命令.假設現在我要指定從第256個byte開 始讀取此頁,那么我將這樣發送命令串
column_addr=256;
NF_CMD=0x01; ? 從2nd half開始讀取
NF_ADDR=column_addr&0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
其中NF_CMD和NF_ADDR分別是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般這樣定義它們,
#define rNFCMD (*(volatile unsigned ch ar *)0x4e000004) //NADD Flash command
#define rNFADDR (*(volatile unsigned ch ar *)0x4e000008) //NAND Flash address
事實上,當NF_CMD=0x01時,地址寄存器中的第8位(A8)將被設置為1(如上文分析,A8位不在我們傳遞的地址中,這個位其實就是硬件電路根據 01h或是00h這兩個命令來置高位或是置低位),這樣我們傳遞column_addr的值256隨然由於數據溢出變為1,但A8位已經由於NF_CMD =0x01的關系被置為1了,所以我們傳到地址寄存器里的值變成了
A0 A1 A2 A3 A4 A5 A6 A7 A8
1 0 0 0 0 0 0 0 1
這8個位所表示的正好是256,這樣讀操作將從此頁的第256號byte(2nd half的第0號byte)開始讀取數據。 nand_flash.c中包含3個函數
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned int src_addr,unsigned ch ar *desc_addr,int size);
nf_reset()將被nf_init()調用。nf_init()是nand_flash的初始化函數,在對nand flash進行任何操作之前,nf_init()必須被調用。
nf_read(unsigned int src_addr,unsigned ch ar *desc_addr,int size);為讀函數,src_addr是nand flash上的地址,desc_addr是內存地址,size是讀取文件的長度。
在nf_reset和nf_read函數中存在兩個宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到當每次對Nand Flash進行操作之前NF_nFCE_L()必定被調用,操作結束之時NF_nFCE_H()必定被調用。這兩個宏用於啟動和關閉Flash芯片的工作(片選/取消片選)。至於nf_reset()中的
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
這一行代碼是對NandFlash的控制寄存器進行初始化配置,rNFCONF是Nand Flash的配置寄存器,各個位的具體功能請參閱s3c2410數據手冊。
現在舉一個例子,假設我要從Nand Flash中的第5000字節處開始讀取1024個字節到內存的0x30000000處,我們這樣調用read函數
nf_read(5000, 0x30000000,1024);
我們來分析5000這個src_addr.
根據
column_addr=src_addr%512;
page_address=(src_addr>>9);
我們可得出column_addr=5000%512=392
page_address=(5000>>9)=9
於是我們可以知道5000這個地址是在第9頁的第392個字節處,於是我們的nf_read函數將這樣發送命令和參數
column_addr=5000%512;
>page_address=(5000>>9);
NF_CMD=0x01; 從2nd half開始讀取
NF_ADDR= column_addr &0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
向NandFlash的命令寄存器和地址寄存器發送完以上命令和參數之后,我們就可以從rNFDATA寄存器(NandFlash數據寄存器)讀取數據了.
我用下面的代碼進行數據的讀取.
for(i=column_addr;i<512;i++)
{
*buf++=NF_RDDATA();
}
每當讀取完一個Page之后,數據指針會落在下一個Page的0號Column(0號Byte).
下面是源代碼:
/*
www.another-prj.com
author: caiyuqing
本代碼只屬於交流學習,不得用於商業開發
*/
#include "s3c2410.h"
#include "nand_flash.h"
static unsigned ch ar seBuf【16】={0xff};
//--------------------------------------------------------------------------------------
unsigned short nf_checkId(void)
{
int i;
unsigned short id;
NF_nFCE_L(); //chip enable
NF_CMD(0x90); //Read ID
NF_ADDR(0x0);
for(i=0;i<10;i++); //wait tWB(100ns)
id="NF"_RDDATA()<<8; // Maker code(K9S1208V:0xec)
id|=NF_RDDATA(); // Devide code(K9S1208V:0x76)
NF_nFCE_H(); //chip enable
return id;
}
//--------------------------------------------------------------------------------------
static void nf_reset(void)
{
int i;
NF_nFCE_L(); //chip enable
NF_CMD(0xFF); //reset command
for(i=0;i<10;i++); //tWB = 100ns.
NF_WAITRB(); //wait 200~500us;
NF_nFCE_H(); //chip disable
}
//--------------------------------------------------------------------------------------
void nf_init(void)
{
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
// 1 1 1 1 1 xxx r xxx, r xxx
// En r r ECCR nFCE="H" tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned int src_addr,unsigned ch ar *desc_addr,int size)
{
int i;
unsigned int column_addr = src_addr % 512; // column address
unsigned int page_address = (src_addr >> 9); // page addrress
unsigned ch ar *buf = desc_addr;
while((unsigned int)buf < (unsigned int)(desc_addr) + size)
{
NF_nFCE_L(); // enable chip
/*NF_ADDR和NF_CMD為nand_flash的地址和命令寄存器的解引用*/
if(column_addr > 255) // 2end halft
NF_CMD(0x01); // Read2 command. cmd 0x01: Read command(start from 2end half page)
else
NF_CMD(0x00); // 1st halft?
NF_ADDR(column_addr & 0xff); // Column Address
NF_ADDR(page_address & 0xff); // Page Address
NF_ADDR((page_address >> 8) & 0xff); // ...
NF_ADDR((page_address >> 16) & 0xff); // ..
for(i = 0; i < 10; i++); // wait tWB(100ns)/////??????
NF_WAITRB(); // Wait tR(max 12us)
// Read from main area
for(i = column_addr; i < 512; i++)
{
*buf++= NF_RDDATA();
}
NF_nFCE_H(); // disable chip
column_addr = 0;
page_address++;
}
return ;
}
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 /* =y */
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 /* CONFIG_MTD_NANDY */
……
#ifdef CONFIG_MTD_NAND_ECC
u_char ecc_code_buf[6];
u_char reserved[2];
#endif
#endif /* CONFIG_MTD_NANDY */
};
縱觀對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;),有興趣的可以讀讀代碼,看看這是怎么實現的,我的感覺就是關於寄存器的清置讀起來都比較暈。
NAND閃存技術深入解析 類別:存儲器 閱讀:1057 對於許多消費類音視頻產品而言,NAND閃存是一種比硬盤驅動器更好的存儲方案,這在不超過4GB的低容量應用中表現得猶為明顯。隨着人們持續追求功耗更低、重量更輕和性能更佳的產品,NAND正被證明極具吸引力。
NAND閃存陣列分為一系列128kB的區塊(block),這些區塊是NAND器件中 最小的可擦除實體。擦除一個區塊就是把所有的位(bit)設置為“1”(而所有字節(byte)設置為FFh)。有必要通過編程,將已擦除的位從“1”變 為“0”。最小的編程實體是字節(byte)。一些NOR閃存能同時執行讀寫操作(見下圖1)。雖然NAND不能同時執行讀寫操作,它可以采用稱為“映射 (shadowing)”的方法,在系統級實現這一點。這種方法在個人電腦上已經沿用多年,即將BIOS從速率較低的ROM加載到速率較高的RAM上。
NAND的效率較高,是因為NAND串中沒有金屬觸點。NAND閃存單元的大小 比NOR要小(4F2:10F2)的原因,是NOR的每一個單元都需要獨立的金屬觸點。NAND與硬盤驅動器類似,基於扇區(頁),適合於存儲連續的數據,如圖片、音頻或個人電腦數據。雖然通過把數據映射到RAM上,能在系統級實現隨機存取,但是,這樣做需要額外的RAM存儲空間。此外,跟硬盤一 樣,NAND器件存在壞的扇區,需要糾錯碼(ECC)來維持數據的完整性。
存儲單元面積越小,裸片的面積也就越小。在這種情況下,NAND就能夠為當今的 低成本消費市場提供存儲容量更大的閃存產品。NAND閃存用於幾乎所有可擦除的存儲卡。NAND的復用接口為所有最新的器件和密度都提供了一種相似的引腳輸出。這種引腳輸出使得設計工程師無須改變電路板的硬件設計,就能從更小的密度移植到更大密度的設計上。
NAND與NOR閃存比較
NAND閃存的優點在於寫(編程)和擦除操作的速率快,而NOR的優點是具有隨 機存取和對字節執行寫(編程)操作的能力(見下圖圖2)。NOR的隨機存取能力支持直接代碼執行(XiP),而這是嵌入式應用經常需要的一個功能。NAND的缺點是隨機存取的速率慢,NOR的缺點是受到讀和擦除速度慢的性能制約。NAND較適合於存儲文件。如今,越來越多的處理器具備直接NAND接 口,並能直接從NAND(沒有NOR)導入數據。
NAND的真正好處是編程速度快、擦除時間短。NAND支持速率超過5Mbps的持續寫操作,其區塊擦除時間短至2ms,而NOR是750ms。顯然,NAND在某些方面具有絕對優勢。然而,它不太適合於直接隨機存取。
對於16位的器件,NOR閃存大約需要41個I/O引腳;相對而言,NAND器 件僅需24個引腳。NAND器件能夠復用指令、地址和數據總線,從而節省了引腳數量。復用接口的一項好處,就在於能夠利用同樣的硬件設計和電路板,支持較大的NAND器件。由於普通的TSOP-1封裝已經沿用多年,該功能讓客戶能夠把較高密度的NAND器件移植到相同的電路板上。NAND器件的另外一個好 處顯然是其封裝選項:NAND提供一種厚膜的2Gb裸片或能夠支持最多四顆堆疊裸片,容許在相同的TSOP-1封裝中堆疊一個8Gb的器件。這就使得一種封裝和接口能夠在將來支持較高的密度。 圖1 不同閃存單元的對比 圖2 NOR閃存的隨機存取時間為0.12ms,而NAND閃存的第一字節隨機存取速度要慢得多
NAND基本操作
以2Gb NAND器件為例,它由2048個區塊組成,每個區塊有64個頁(見圖3)。 圖3 2GB NAND閃存包含2,048個區塊
每一個頁均包含一個2048字節的數據區和64字節的空閑區,總共包含 2,112字節。空閑區通常被用於ECC、耗損均衡(wear leveling)和其它軟件開銷功能,盡管它在物理上與其它頁並沒有區別。NAND器件具有8或16位接口。通過8或16位寬的雙向數據總線,主數據被連接到NAND存儲器。在16位模式,指令和地址僅僅利用低8位,而高8位僅僅在數據傳輸 周期使用。
擦除區塊所需時間約為2ms。一旦數據被載入寄存器,對一個頁的編程大約要300μs。讀一個頁面需要大約25μs,其中涉及到存儲陣列訪問頁,並將頁載入16,896位寄存器中。
除了I/O總線,NAND接口由6個主要控制信號構成:
1.芯片啟動(Chip Enable, CE#):如果沒有檢測到CE信號,那么,NAND器件就保持待機模式,不對任何控制信號作出響應。
2.寫使能(Write Enable, WE#): WE#負責將數據、地址或指令寫入NAND之中。
3.讀使能(Read Enable, RE#): RE#允許輸出數據緩沖器。
4.指令鎖存使能(Command Latch Enable, CLE): 當CLE為高時,在WE#信號的上升沿,指令被鎖存到NAND指令寄存器中。
5.地址鎖存使能(Address Latch Enable, ALE):當ALE為高時,在WE#信號的上升沿,地址被鎖存到NAND地址寄存器中。
6.就緒/忙(Ready/Busy, R/B#):如果NAND器件忙,R/B#信號將變低。該信號是漏極開路,需要采用上拉電阻。
數據每次進/出NAND寄存器都是通過16位或8位接口。當進行編程操作的時候,待編程的數據進入數據寄存器,處於在WE#信號的上升沿。在寄存器內隨機存取或移動數據,要采用專用指令以便於隨機存取。
數據寄存器輸出數據的方式與利用RE#信號的方式類似,負責輸出現有的數據,並 增加到下一個地址。WE#和RE#時鍾運行速度極快,達到30ns的水准。當RE#或CE#不為低的時候,輸出緩沖器將為三態。這種CE#和RE#的組合使能輸出緩沖器,容許NAND閃存與NOR、SRAM或DRAM等其它類型存儲器共享數據總線。該功能有時被稱為“無需介意芯片啟動(chip enable don't care)”。這種方案的初衷是適應較老的NAND器件,它們要求CE#在整個周期為低(譯注:根據上下文改寫)。 圖4 輸入寄存器接收到頁編程(80h)指令時,內部就會全部重置為1s,使得用戶可以只輸入他想以0位編程的數據字節 圖5 帶有隨機數據輸入的編程指令。圖中加亮的扇區顯示,該指令只需要后面跟隨着數據的2個字節的地址
所有NAND操作開始時,都提供一個指令周期(表1)。
當輸出一串WE#時鍾時,通過在I/O位7:0上設置指令、驅動CE#變低且 CLE變高,就可以實現一個指令周期。注意:在WE#信號的上升沿上,指令、地址或數據被鎖存到NAND器件之中。如表1所示,大多數指令在第二個指令周期之后要占用若干地址周期。注意:復位或讀狀態指令例外,如果器件忙,就不應該發送新的指令。
以2Gb NAND器件的尋址方案為例,第一和第二地址周期指定列地址,該列地址指定頁內的起始字節(表2)。
注意:因為最后一列的位置是2112,該最后位置的地址就是08h(在第二字節 中)和3Fh(在第一字節中)。PA5:0指定區塊內的頁地址,BA16:6指定區塊的地址。雖然大多編程和讀操作需要完整的5字節地址,在頁內隨機存取數據的操作僅僅用到第一和第二字節。塊擦除操作僅僅需要三個最高字節(第三、第四和第五字節)來選擇區塊。 圖6 典型的存儲方法 圖7 頁讀緩存模式
總體而言,NAND的基本操作包括:復位(Reset, FFh)操作、讀 ID(Read ID, 00h)操作、讀狀態(Read Status, 70h)操作、編程(Program)操作、隨機數據輸入(Random data input, 85h)操作和讀(Read)操作等。
將NAND連接到處理器
選擇內置NAND接口的處理器或控制器的好處很多。如果沒有這個選擇,有可能在 NAND和幾乎任何處理器之間設計一個“無粘接邏輯(glueless)”接口。NAND和NOR閃存的主要區別是復用地址和數據總線。該總線被用於指定指令、地址或數據。CLE信號指定指令周期,而ALE信號指定地址周期。利用這兩個控制信號,有可能選擇指令、地址或數據周期。把ALE連接到處理器的第 五地址位,而把CLE連接到處理器的第四地址位,就能簡單地通過改變處理器輸出的地址,任意選擇指令、地址或數據。這容許CLE和ALE在合適的時間自動設置為低。
為了提供指令,處理器在數據總線上輸出想要的指令,並輸出地址0010h;為了 輸出任意數量的地址周期,處理器僅僅要依次在處理器地址0020h之后輸出想要的NAND地址。注意,許多處理器能在處理器的寫信號周圍指定若干時序參數,這對於建立合適的時序是至關重要的。利用該技術,你不必采用任何粘接邏輯,就可以直接從處理器存取指令、地址和數據。
多層單元
多層單元(MLC)的每一個單元存儲兩位,而傳統的SLC僅僅能存儲一位。MLC技術有顯著的密度優越性,然而,與SLC相比(表3),其速度或可靠性稍遜。因此,SLC被用於大多數媒體卡和無線應用,而MLC器件通常被用於消費電子和其它低成本產品。
如上所述,NAND需要ECC以確保數據完整性。NAND閃存的每一個頁面上都 包括額外的存儲空間,它就是64個字節的空閑區(每512字節的扇區有16字節)。該區能存儲ECC代碼及其它像磨損評級或邏輯到物理塊映射之類的信息。ECC能在硬件或軟件中執行,但是,硬件執行有明顯的性能優勢。在編程操作期間,ECC單元根據扇區中存儲的數據來計算誤碼校正代碼。數據區的ECC代碼 然后被分別寫入到各自的空閑區。當數據被讀出時,ECC代碼也被讀出;運用反操作可以核查讀出的數據是否正確。
有可能采用ECC算法來校正數據錯誤。能校正的錯誤的數量取決於所用算法的校正 強度。在硬件或軟件中包含ECC,就提供了強大的系統級解決方案。最簡單的硬件實現方案是采用簡單的漢明(Simple Hamming)碼,但是,只能校正單一位錯誤。瑞德索羅門(Reed-Solomon)碼提供更為強大的糾錯,並被目前的控制器廣為采用。此外,BCH碼由於比瑞德索羅門方法的效率 高,應用也日益普及。
要用軟件執行NAND閃存的區塊管理。該軟件負責磨損評級或邏輯到物理映射。該軟件還提供ECC碼,如果處理器不包含ECC硬件的話。
編程或擦除操作之后,重要的是讀狀態寄存器,因為它確認是否成功地完成了編程或 擦除操作。如果操作失敗,要把該區塊標記為損壞且不能再使用。以前已編寫進去的數據要從損壞的區塊中搬出,轉移到新的(好的)存儲塊之中。2Gb NAND的規范規定,它可以最多有40個壞的區塊,這個數字在器件的生命周期(額定壽命為10萬次編程/擦除周期)內都適用。一些有壞塊的NAND器件能 夠出廠,主要就歸根於其裸片面積大。管理器件的軟件負責映射壞塊並由好的存儲塊取而代之。
利用工廠對這些區塊的標記,軟件通過掃描塊可以確定區塊的好壞。壞塊標記被固定 在空閑區的第一個位置(列地址2048)。如果在0或1頁的列地址2048上的數據是“non-FF”,那么,該塊要標記為壞,並映射出系統。初始化軟件 僅僅需要掃描所有區塊確定以確定哪個為壞,然后建一個壞塊表供將來參考。
小心不要擦除壞塊標記,這一點很重要。工廠在寬溫和寬電壓范圍內測試了NAND;一些由工廠標記為壞的區塊可能在一定的溫度或電壓條件下仍然能工作,但是,將來可能會失效。如果壞塊信息被擦除,就無法再恢復。
nand flash壞塊管理OOB,BBT,ECC
0.NAND的操作管理方式
NAND FLASH的管理方式:以三星FLAHS為例,一片Nand flash為一個設備(device),1 (Device) = xxxx (Blocks),1 (Block) = xxxx (Pages),1(Page) =528 (Bytes) = 數據塊大小(512Bytes) + OOB 塊大小(16Bytes,除OOB第六字節外,通常至少把OOB的前3個字節存放Nand Flash硬件ECC碼)。
1.為什么會出現壞塊
由於NAND Flash的工藝不能保證NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生產中及使用過程中會產生壞塊。壞塊的特性是:當編程/擦除這個塊時,會造成Page Program和Block Erase操作時的錯誤,相應地反映到Status Register的相應位。
2.壞塊的分類
總體上,壞塊可以分為兩大類:(1)固有壞塊:這是生產過程中產生的壞塊,一般芯片原廠都會在出廠時都會將每個壞塊第一個page的spare area的第6個byte標記為不等於0xff的值。(2)使用壞塊:這是在NAND Flash使用過程中,如果Block Erase或者Page Program錯誤,就可以簡單地將這個塊作為壞塊來處理,這個時候需要把壞塊標記起來。為了和固有壞塊信息保持一致,將新發現的壞塊的第一個page的 spare area的第6個Byte標記為非0xff的值。
3.壞塊管理
根據上面的這些敘述,可以了解NAND Flash出廠時在spare area中已經反映出了壞塊信息,因此,如果在擦除一個塊之前,一定要先check一下第一頁的spare area的第6個byte是否是0xff,如果是就證明這是一個好塊,可以擦除;如果是非0xff,那么就不能擦除,以免將壞塊標記擦掉。當然,這樣處理可能會犯一個錯誤―――“錯殺偽壞塊”,因為在芯片操作過程中可能由於電壓不穩定等偶然因素會造成NAND操作的錯誤。但是,為了數據的可靠性及軟件設計的簡單化,還是需要遵照這個標准。
可以用BBT:bad block table,即壞塊表來進行管理。各家對nand的壞塊管理方法都有差異。比如專門用nand做存儲的,會把bbt放到block0,因為第0塊一定是好 的塊。但是如果nand本身被用來boot,那么第0塊就要存放程序,不能放bbt了。有的把bbt放到最后一塊,當然,這一塊堅決不能為壞塊。bbt的大小跟nand大小有關,nand越大,需要的bbt也就越大。
4.壞塊糾正
ECC:NAND Flash出錯的時候一般不會造成整個Block或是Page不能讀取或是全部出錯,而是整個Page(例如512Bytes)中只有一個或幾個bit出 錯。一般使用一種比較專用的校驗——ECC。ECC能糾正單比特錯誤和檢測雙比特錯誤,而且計算速度很快,但對1比特以上的錯誤無法糾正,對2比特以上的 錯誤不保證能檢測。
ECC一般每256字節原始數據生成3字節ECC校驗數據,這三字節共24比特分成兩部分:6比特的列校驗和16比特的行校驗,多余的兩個比特置1。(512生成兩組ECC?)
當往NAND Flash的page中寫入數據的時候,每256字節我們生成一個ECC校驗和,稱之為原ECC校驗和,保存到PAGE的OOB(out- of-band)數據區中。其位置就是eccpos[]。校驗的時候,根據上述ECC生成原理不難推斷:將從OOB區中讀出的原ECC校驗和新ECC校驗和按位異或,若結果為0,則表示不存在錯(或是出現了ECC無法檢測的錯誤);若3個字節異或結果中存在11個比特位為1,表示存在一個比特錯誤,且可糾正;若3個字節異或結果中只存在1個比特位為1,表示OOB區出錯;其他情況均表示出現了無法糾正的錯誤。
5.補充
(1)需要對前面由於Page Program錯誤發現的壞塊進行一下特別說明。如果在對一個塊的某個page進行編程的時候發生了錯誤就要把這個塊標記為壞塊,首先就要把塊里其他好的 面的內容備份到另外一個空的好塊里面,然后,把這個塊標記為壞塊。當然,這可能會犯“錯殺”之誤,一個補救的辦法,就是在進行完塊備份之后,再將這個壞塊 擦除一遍,如果Block Erase發生錯誤,那就證明這個塊是個真正的壞塊,那就毫不猶豫地將它打個“戳”吧!
(2)可能有人會問,為什么要使用每個塊第一頁的spare area的第六個byte作為壞塊標記。這是NAND Flash生產商的默認約定,你可以看到Samsung,Toshiba,STMicroelectronics都是使用這個Byte作為壞塊標記的。
(3)為什么好塊用0xff來標記?因為Nand Flash的擦除即是將相應塊的位全部變為1,寫操作時只能把芯片每一位(bit)只能從1變為0,而不能從0變為1。0XFF這個值就是標識擦除成功,是好塊。