1. 程式人生 > >深入理解nandflash之基本特性

深入理解nandflash之基本特性

nandflash作為嵌入式中的”磁碟”, 被廣泛的應用, 以(K9F2G08U0B)為例,其他型號都差不多

  • nandflash的結構
    這裡寫圖片描述
    nandflash的結構有頁(page), block(塊)的概念,其中頁是真實概念,而塊兒是虛擬概念(目的是為了更好的管理儲存空間)
    page: 一個page大小為2K + 64bytes, 如上圖所示,其中的64bytes是所在頁的infomation, 記錄著此頁的使用情況,比如剩餘存空間等
    block: 一個block由64個頁組成, 一個nandflash晶片由2k個block組成,算算就知道,一個nandflash晶片一共能儲存256M的資料.
  • nandflash的引腳說明
    這裡寫圖片描述
  • nandflash與2440的連線
    這裡寫圖片描述
    由上連線圖可以看出,ALE,CLE這種訊號其實就是2440的GPIO(體現了管腳複用的功能)
    注意,與nandflash的資料傳輸介面就只有IO0->IO7這8根並行的資料線,所以我們傳送讀命令還是寫命令還是地址,都是通過這8跟先發出的,具體情況如下分析
  • nandflash的讀操作,先給出時序圖(datasheet),之後在分析
    這裡寫圖片描述
    首先我們先看一下讀取nandflash需要一個什麼樣的週期
    1.首先發命令 00H(讀命令)
    2.傳送地址
    3.傳送地址
    4.傳送命令 30H(讀命令)
    5.忙等待
    6.讀取資料
    從資料手冊上來看,對於命令代表的意義如下圖所示
    這裡寫圖片描述

    我們看到,讀命令確實要發兩次,那麼為什麼要這麼操作呢?這其實根據nandflash的硬體來定的,第一次發讀命令是把讀取的命令放到nandflash的IO BUFFers這個硬體中,之後再發一次讀命令才真正的把命令寫入nandflash中,這樣做的好處是為了降低頁的寫入時間
  • 根據時序圖看過程1
    我們通過IO1–>IO7來發送讀命令,此時nandflash如何區分到底是命令,地址,還是資料呢?
    很簡單: 拉高CLE, 拉低ALE ,之後拉低WE,把命令00H放到I/O總線上,當WE由電平至高電平轉變時,發生鎖存,nandflash獲取讀命令
    這個過程要注意的是: 拉高CLE是為了鎖存使能,也就是WE上升沿的時候可以鎖存成功從而使nandflash獲取命令資料,ALE拉低是為了告訴nandflash此時發的是命令資料
  • 根據時序圖看過程2
    我們通過IO1–>IO7來發送地址
    這裡寫圖片描述
    上圖即我們需要傳送地址的順序,我們通過時序圖發現要傳送5次(5個週期)地址,每次的格式如上圖所示,接著分析, 當拉低CLE,拉高ALE即認為開始傳送地址資訊, 之後拉低WE,將地址資訊放到總線上,之後WE上升沿鎖存,nandflash獲取地址資訊
    之後的分析過程相信自己就能分析了,
    注意:
    1.根據ALE與CLE的變化來區分匯流排IO1->IO7上的資料type
    2.關於地址說明:大多nandflash是以頁為單位進行讀取或者寫入的,以K9F2G08U0B為例 子,讀取一次資料最小就是2k(一頁的資料量)的資料量,這是由硬體特性決定的,但不是絕對的,比如K9F2G08U0C這一款的nandflash支援頁內的地址訪問,所以我們在寫nandflash底層讀寫函式都應該以頁為單位進行讀寫
    3.寫nandflash時,需要先擦除儲存單元, 之後在向儲存單元寫入資料,要注意的是,nandflash擦除是以block為單位,也就是說一次最少要擦除1個block即64頁的資料, 這也是硬體的限制,至於為什麼要擦除?是因為硬體的原因,使得nandflash只能寫入0,不能寫1,所以擦除是為了讓儲存單元都變為1
  • 對於傳送的地址要進行一個問題的講解
    這裡寫圖片描述
    上圖中A0—>A11為Column Address,對應的是頁內的偏移,問題來了, 一個頁為2k大小,理論上A0->A10就可以了,那麼為什麼多出個A11呢?別忘了,一個頁上除了2k大小的地方,還有個64Bytes的地方,要訪問它的話,A0->A10地方不夠不是,所以多出了個A11,當A11為0時,nandflash也不會理會這個ECC空間(64Bytes) 剩下的A12–>A28為頁索引,因為一個塊有64個頁,所以我們把A12->A17定為頁索引, A18->A28定為塊索引,其對應關係如下圖:
    這裡寫圖片描述這個圖很容易被人誤導,
    比如我要傳送讀取nandflash 4096這個地址的資料, 換句話講,應該是nandflash 4k資料後開始的資料,應該是第三個頁的資料(即第2頁,因為一個頁大小為2k),所以將地址傳入認為
    第一週期應該傳送:A0-A7 —>00
    第二週期應該傳送:A8-A11 —>00
    第三週期應該傳送:A12-A19 —>01
    第四周期應該傳送:A20-A27—->00
    第五週期應該傳送:A28———>00
    這裡寫圖片描述
    即上圖中錯誤認為的情況,因為在我們的角度看來,是不存在A11的,所以應該是圖中下面表示正確的情況(黃色為4096的2進位制),或許說到這裡大家還是似懂非懂,那我們在簡單一點,比如從2049這個地址上取資料,在我們看來,應該是從第1頁開始取資料,但是站在nandflash傳送地址週期的角度上看,其實是訪問第0頁的地址(因為有A11為1,即訪問64Bytes的範圍),也就是說如果把2049嚴格按照發送週期送地址的話其實訪問的是第0頁64Bytes範圍中了,這不是我們所希望的,所以我們要把2049這個地址變成第1頁開始的地方,怎麼辦呢?將A11位至0,之後向後串一位即可.上圖可以慢慢體會
    總結:
    此 Nand Flash 地址週期共有 5 個,2 個列(Column),3個行(Row)週期,而對於對應地,我們可以看出,實際上,列地址 A0~A10,就是頁內地址,地址範圍是從0 到2047,而對出的 A11,理論上可以表示 2048~4095,但是實際上,我們最多也只用到了2048~2011, 用於表示頁內的oob區域,其大小是 64 位元組。對應地,A12~A28,稱作頁號,頁的號碼,可以定位到具體是哪一個頁。而其中,A18~A28,表示對應的塊號,即屬於哪個塊。
我們寫程式傳送地址的時候是這樣寫的:
..........
unsigned int col_add = addr & 0x7ff; //A0-->A10(column Address)
unsigned int raw_add = (addr >> 11)&0x1ffff; //A11-->A28(頁索引)

NFADDR = col_add & 0xff; //A0-A7 8位 
NFADDR = (col_add >> 8) & 0x7; //a11為0 A8-A11 3位
NFADDR = raw_add & 0xff; 
NFADDR = (raw_add >> 8) & 0xff;
NFADDR = (raw_add >> 16) & 0x1;
.....
..

在這裡有些人感覺很奇怪,表格裡rows明明是從A12開始的可是程式裡raw_add= (addr >> 11)&0x1ffff,只向由移11位,不是應該addr >> 12嗎?
最關鍵的地方到了,你別忘了,我們在存放資料的時候,資料裡面不包括ECC資訊,也就是說在我們自己看來nandflash頁大小就是2K。比如說我往nand的0x0地址存了0x800(2KB)大小資料,接下來,如果我們再存資料就繼續從0x800的地址開始存,在這裡你跳過前一頁的ECC部分了嗎?很明顯沒有,理論上前一頁佔了0x1000(4KB)大小,我們應該從0x1000開始存接下的資料,可是,我們實際上不會這麼幹,我們忽略ECC佔的空間,我們認為一頁大小就是2KB。

所以在我們看來nandflash地址就是這樣的:
nand地址=(rows:A27-A11)(columns:A10-A0)
接受到地址後,在傳送地址時,我們是這麼幹的,把A0-A10取出來,再添上一位A11=0,,然後把A11-A27取出來,對應A12-A28發過去,這樣就實現了在傳送地址時跳過每一頁的ECC部分,但在使用者看來每一頁大小還是2KB,這裡有些繞,但是好好想一想還是能想清楚的。實在理解不了可以這麼想,地址2049,應該是第1頁開始地址,如果要訪問第1頁開始的地址,那麼地址如何發?所以轉換關係為: 2096—>第1頁開始—>轉換為5個週期地址

  • 關於nandflash的寫擦除時序,與讀的過程都大同小異,這裡貼出datasheet中寫時序,擦除時序圖,方便以後查閱
  • 寫時序
    這裡寫圖片描述
    可以看到除了命令之外,其餘與讀時序基本差不多
  • 擦除block時序
    這裡寫圖片描述
    如圖可知,擦除的時序以block為單位,傳送的地址 Row Add1後的三個地址