一、結構分析
S3C2410處理器集成了8位NandFlash控制器。目前市場上常見的8位NandFlash有三星公司的k9f1208、k9f1g08、k9f2g08等。k9f1208、k9f1g08、k9f2g08的數(shù)據(jù)頁大小分別為512Byte、2kByte、2kByte。它們在尋址方式上有一定差異,所以程序代碼并不通用。本文以S3C2410處理器和k9f1208系統(tǒng)為例,講述NandFlash的讀寫方法。
NandFlash的數(shù)據(jù)是以bit 的方式保存在memory cell里的,一般來說,一個cell 中只能存儲一個bit,這些cell 以8 個或者16 個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device 的位寬。這些Line 組成Page, page 再組織形成一個Block。k9f1208的相關數(shù)據(jù)如下:
1block=32page;1page=528byte=512byte(Main Area)+16byte(Spare Area)。
總容量為=4096(block數(shù)量)*32(page/block)*512(byte/page)=64Mbyte
NandFlash以頁為單位讀寫數(shù)據(jù),而以塊為單位擦除數(shù)據(jù)。按照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] 表示;
二、讀操作過程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,選中下半頁。
雖然讀寫過程可以不從頁邊界開始,但在正式場合下還是建議從頁邊界開始讀寫至頁結束。下面通過分析讀取頁的代碼,闡述讀過程。
static void ReadPage(U32 addr, U8 *buf) //addr表示flash中的第幾頁,即‘flash地址>>9’
{
U16 i;
NFChipEn(); //使能NandFlash
WrNFCmd(READCMD0); //發(fā)送讀指令‘0x00’,由于是整頁讀取,所以選用指令‘0x00’
WrNFAddr(0); //寫地址的第1個cycle,即Column Address,由于是整頁讀取所以取0
WrNFAddr(addr); //寫地址的第2個cycle,即A[9:16]
WrNFAddr(addr>>8); //寫地址的第3個cycle,即A[17:24]
WrNFAddr(addr>>16); //寫地址的第4個cycle,即A[25]。
WaitNFBusy(); //等待系統(tǒng)不忙
for(i=0; i<512; i++)
buf[i] = RdNFDat(); //循環(huán)讀出1頁數(shù)據(jù)
NFChipDs(); //釋放NandFlash
}
三、寫操作過程
寫操作的過程為: 1、發(fā)送寫開始指令;2、發(fā)送第1個cycle地址;3、發(fā)送第2個cycle地址;4、發(fā)送第3個cycle地址;5、發(fā)送第4個cycle地址;6、寫入數(shù)據(jù)至頁末;7、發(fā)送寫結束指令
下面通過分析寫入頁的代碼,闡述讀寫過程。
static void WritePage(U32 addr, U8 *buf) //addr表示flash中的第幾頁,即‘flash地址>>9’
{
U32 i;
NFChipEn(); //使能NandFlash
WrNFCmd(PROGCMD0); //發(fā)送寫開始指令’0x80’
WrNFAddr(0); //寫地址的第1個cycle
WrNFAddr(addr); //寫地址的第2個cycle
WrNFAddr(addr>>8); //寫地址的第3個cycle
WrNFAddr(addr>>16); 寫地址的第4個cycle
WaitNFBusy(); //等待系統(tǒng)不忙
for(i=0; i<512; i++)
WrNFDat(buf[i]); //循環(huán)寫入1頁數(shù)據(jù)
WrNFCmd(PROGCMD1); //發(fā)送寫結束指令’0x10’
NFChipDs(); //釋放NandFlash
}
四、總結
本文以S3C2410處理器和k9f1208系統(tǒng)為例講述了nand flash的讀寫過程。在讀寫過程中沒有考慮到壞塊問題,有關ecc及壞塊處理問題將在下個專題中講述。我的板子上使用的是SAMSUNG的K9F1208U0B,下面我將對此型號的NandFlash讀取操作做一個講解。
首先我們先從物理結構上來了解這顆芯片,結構圖如下所示
正如硬盤的盤片被分為磁道,每個磁道又被分為若干扇區(qū),一塊Nand Flash被分為若干Block,每個Block又被分為若干Page。
由上圖我們可以知道flash中Byte(字節(jié)),Page(頁),Block(塊)3個單位之間的關系為
1 Page =512 Bytes Data Field+ 16 Bytes Spare Field
1 Blcok="32" Pages
我們討論的K9F1208U0B總共有4096 個Blocks,故我們可以知道這塊flash的容量為4096 *(32 *528)= 69206016 Bytes = 66 MB
但事實上每個Page上的最后16Bytes是用于存貯檢驗碼用的,并不能存放實際的數(shù)據(jù),所以實際上我們可以操作的芯片容量為
4096 *(32 *512) = 67108864 Bytes = 64 MB
由上圖所示,1個Page總共由528 Bytes組成,這528個字節(jié)按順序由上而下以列為單位進行排列(1列代表一個Byte。第0行為第0 Byte ,第1行為第1 Byte,以此類推,每個行又由8個位組成,每個位表示1個Byte里面的1bit)。這528Bytes按功能分為兩大部分,分別是Data Field和Spare Field,其中Spare Field占528Bytes里的16Bytes,這16Bytes是用于在讀寫操作的時候存放校驗碼用的,一般不用做普通數(shù)據(jù)的存儲區(qū),除去這16Bytes,剩下的512Bytes便是我們用于存放數(shù)據(jù)用的Data Field,所以一個Page上雖然有528個Bytes,但我們只按512Bytes進行容量的計算。
Data Field按位置關系又可分為兩個部分,分別稱為1st half與2nd half,每個half各占256個bytes?;蛟S你會感到納悶,為什么要把DataField分為兩個部分?把他們看做一個整體進行操作不就好了嗎?呵呵,凡事都有因果關系,這么分塊自然有它的道理所在,但現(xiàn)在還不是告訴你答案的時候。我們還是先討論一下它的操作吧。
對K9F1208U0B的操作是通過向Nand Flash命令寄存器(對于s3c2410來說此寄存器為NFCMD,內存映射地址為0x4e000004)發(fā)送命令隊列進行的,為什么說是命令隊列?就是因為要完成某個操作的時候發(fā)送的不是一條命令,而是連續(xù)幾條命令或是一條命令加幾個參數(shù)
下面是K9F1208U0B的操作命令集:
讀命令有兩個,分別是 Read1,Read2其中Read1用于讀取Data Field的數(shù)據(jù),而Read2則是用于讀取Spare Field的數(shù)據(jù)。對于Nand Flash來說,讀操作的最小操作單位為Page,也就是說當我們給定了讀取的起始位置后,讀操作將從該位置開始,連續(xù)讀取到本Page的最后一個Byte為止(可以包括Spare Field)
Nand Flash的尋址
Nand Flash的地址寄存器把一個完整的Nand Flash地址分解成Column Address與Page Address.進行尋址
Column Address: 列地址。Column Address其實就是指定Page上的某個Byte,指定這個Byte其實也就是指定此頁的讀寫起始地址。
Page 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并沒有出現(xiàn),也就是A8被忽略,在下面你將了解到這是什么原因)
Read1命令的操作分為4個Cycle,發(fā)送完讀命令00h或01h(00h與01h的區(qū)別請見下文描述)之后將分4個Cycle發(fā)送參數(shù),1st.Cycle是發(fā)送Column Address。2nd.Cycle ,3rd.Cycle和4th.Cycle則是指定Page Address(每次向地址寄存器發(fā)送的數(shù)據(jù)只能是8位,所以17位的Page Address必須分成3次進行發(fā)送)。
4個Cycle
你是否還記得我上文提到過的Data Field被分為1st half 和2end half兩個部分?而從上面的命令集我們看到Read1的命令里面出現(xiàn)了兩個命令選項,分別是00h和01h。這里出現(xiàn)了兩個讀命是否令你意識到什么呢?是的,00h是用于讀寫1st half的命令,而01h是用于讀取2nd half的命令。現(xiàn)在我可以結合上圖給你說明為什么K9F1208U0B的DataField被分為2個half了。
如上文我所提及的,Read1的1st.Cycle是發(fā)送Column Address,假設我現(xiàn)在指定的Column Address是0,那么讀操作將從此頁的第0號Byte開始一直讀取到此頁的最后一個Byte(包括Spare Field),如果我指定的Column Address是127,情況也與前面一樣,但不知道你發(fā)現(xiàn)沒有,用于傳遞Column Address的數(shù)據(jù)線有8條(I/O0~I/O7,對應A0~A7,這也是A8為什么不出現(xiàn)在我們傳遞的地址位中),也就是說我們能夠指定的Column Address范圍為0~255,但不要忘了,1個Page的DataField是由512個Byte組成的,假設現(xiàn)在我要指定讀命令從第256個字節(jié)處開始讀取此頁,那將會發(fā)生什么情景?我必須把Column Address設置為256,但Column Address最大只能是255,這就造成數(shù)據(jù)溢出。。。正是因為這個原因我們才把Data Field分為兩個半?yún)^(qū),當要讀取的起始地址(Column Address)在0~255內時我們用00h命令,當讀取的起始地址是在256~511時,則使用01h命令.假設現(xiàn)在我要指定從第256個byte開始讀取此頁,那么我將這樣發(fā)送命令串
column_addr=256;
NF_CMD=0x01; ? 從2nd half開始讀取