在網(wǎng)上找了一些資料,又結(jié)合自己的經(jīng)歷談一下我對NAND Flash 的了解。S3C2440 板的Nand Flash 支持由兩部分組成:Nand Flash 控制器(集成在S3C2440 CPU)和Nand Flash 存儲芯片(K9F1208U0B)兩大部分組成。當(dāng)要訪問Nand Flash中的數(shù)據(jù)時,必須通過Nand Flash控制器發(fā)送命令才能完成。所以, Nand Flash相當(dāng)于S3C2440的一個外設(shè),而不位于它的內(nèi)存地址區(qū).
本文引用地址:http://m.butianyuan.cn/article/201611/317616.htmNAND Flash 的數(shù)據(jù)是以bit 的方式保存在memory cell,一般來說,一個cell 中只能存儲一個bit。這些cell 以8 個或者16 個為單位,連成bit line,形成所謂的byte(x8)/word(x16),這就是NAND Device 的位寬。這些Line 會再組成Page.
NandFlash有多種結(jié)構(gòu),我使用的NandFlash是K9F1208,下面內(nèi)容針對三星的K9F1208U0M,數(shù)據(jù)存儲容量為64MB,采用塊頁式存儲管理。一共有4096個block(塊),每個block有32個page(頁),每個page有528Byte。
1block=32page,1page=528byte=512byte(MainArea)+16byte(SpareArea)
Nandflash以頁為單位讀寫數(shù)據(jù),而以塊為單位擦除數(shù)據(jù)。
按照這樣的組織方式可以形成所謂的三類地址:
--BlockAddress--PageAddress--ColumnAddress
對于NANDFlash來講,8個I/O引腳充當(dāng)數(shù)據(jù)、地址、命令的復(fù)用端口。地址和命令只能在I/O[7:0]上傳遞,數(shù)據(jù)寬度是8位。
512byte需要9bit來表示,對于528byte系列的NAND,這512byte被分成1sthalf和2ndhalf,最后16個字節(jié)(又稱OOB)用于NandFlash命令執(zhí)行完后設(shè)置狀態(tài)用,各自的訪問由地址指針命令來選擇,A[7:0]就是所謂的columnaddress。
32個page需要5bit來表示,占用A[13:9],即該page在塊內(nèi)的相對地址。Block的地址是由A14以上的bit來表示,例如512Mb的NAND,共4096block,因此,需要12個bit來表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,則blockaddress用A[26:14]表示。
NANDFlash的地址表示為:
BlockAddress|PageAddressinblock|halfpagepointer|ColumnAddress
地址傳送順序是ColumnAddress,PageAddress,BlockAddress。
由于地址只能在I/O[7:0]上傳遞,因此,必須傳遞多次。例如,對于512Mbitx8的NANDflash,地址范圍是0-0x3FFFFFF,只要是這個范圍內(nèi)的數(shù)值表示的地址都是有效的。以NAND_ADDR為例:第1步是傳遞columnaddress,就是NAND_ADDR[7:0]給相應(yīng)的寄存器,即可傳遞到I/O[7:0]上,而halfpagepointer即bit8是由操作指令決定的,即指令決定在哪個halfpage上進行讀寫。而真正的bit8的值是dontcare的。第2步就是將NAND_ADDR[16:9]傳到I/O[7:0]上。第3步將NAND_ADDR[24:17]放到I/O上。第4步需要將NAND_ADDR[25]放到I/O上因此,整個地址傳遞過程需要4步才能完成,即4-stepaddressing。如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此尋址只需要3步。下面,就x16(16位)的NANDflash器件稍微進行一下說明。由于一個page的mainarea的容量為256word,仍相當(dāng)于512byte。但是,這個時候沒有所謂的1sthalfpage和2ndhalfpage之分了,所以,bit8就變得沒有意義了,也就是這個時候bit8完全不用管,地址傳遞仍然和x8器件相同。除了,這一點之外,x16的NAND使用方法和x8的使用方法完全相同。
正如硬盤的盤片被分為磁道,每個磁道又分為若干扇區(qū),一塊nandflash也分為若干block,每個block分為如干page。一般而言,block、page之間的關(guān)系隨著芯片的不同而不同,典型的分配是這樣的:
1block=32page
1page=512bytes(datafield)+16bytes(oob)
需要注意的是,對于flash的讀寫都是以一個page開始的,但是在讀寫之前必須進行flash的擦寫,而擦寫則是以一個block為單位的。同時必須提醒的是,512bytes理論上被分為1sthalf和2sdhalf,每個half各占256個字節(jié)。
我們討論的K9F1208U0B總共有4096個Blocks,故我們可以知道這塊flash的容量為4096*(32*528)=69206016Bytes=66MB。但事實上每個Page上的最后16Bytes是用于存貯檢驗碼和其他信息用的,并不能存放實際的數(shù)據(jù),所以實際上我們可以操作的芯片容量為4096*(32*512)=67108864Bytes=64MB。
由上圖所示,1個Page總共由528Bytes組成,這528個字節(jié)按順序由上而下以列為單位進行排列(1列代表一個Byte。第0行為第0Byte,第1行為第1Byte,以此類推,每個行又由8個位組成,每個位表示1個Byte里面的1bit)。這528Bytes按功能分為兩大部分,分別是DataField和SpareField,其中SpareField占528Bytes里的16Bytes,這16Bytes是用于在讀寫操作的時候存放校驗碼用的,一般不用做普通數(shù)據(jù)的存儲區(qū),除去這16Bytes,剩下的512Bytes便是我們用于存放數(shù)據(jù)用的DataField,所以一個Page上雖然有528個Bytes,但我們只按512Bytes進行容量的計算。
讀命令有兩個,分別是Read1,Read2其中Read1用于讀取DataField的數(shù)據(jù),而Read2則是用于讀取SpareField的數(shù)據(jù)。對于NandFlash來說,讀操作的最小操作單位為Page,也就是說當(dāng)我們給定了讀取的起始位置后,讀操作將從該位置開始,連續(xù)讀取到本Page的最后一個Byte為止(可以包括SpareField)
NandFlash的尋址
NandFlash的地址寄存器把一個完整的NandFlash地址分解成ColumnAddress與PageAddress.進行尋址。
ColumnAddress:列地址。ColumnAddress其實就是指定Page上的某個Byte,指定這個Byte其實也就是指定此頁的讀寫起始地址。
PaageAddress:頁地址。由于頁地址總是以512Bytes對齊的,所以它的低9位總是0。確定讀寫操作是在Flash上的哪個頁進行的。
Read1命令
當(dāng)我們得到一個NandFlash地址addr時我們可以這樣分解出ColumnAddress和PageAddress
column_addr=src_addrQ2;//columnaddress
page_address=(src_addr>>9);//pageaddress
也可以這么認為,一個NandFlash地址的src_addr[7,0]是它的column_addr,addr[25,9]是它的PageAddress。(注意地址位src_addr[8]并沒有出現(xiàn),也就是addr[8]被忽略,在下面你將了解到這是什么原因)
Read1命令的操作發(fā)送完讀命令00h或01h(00h與01h的區(qū)別請見下文描述)之后將分4個Cycle發(fā)送參數(shù),1st.Cycle是發(fā)送ColumnAddress。2nd.Cycle,3rd.Cycle和4th.Cycle則是指定PageAddress(每次向地址寄存器發(fā)送的數(shù)據(jù)只能是8位,所以17位的PageAddress必須分成3次進行發(fā)送。
Read1的命令里面出現(xiàn)了兩個命令選項,分別是00h和01h。這里出現(xiàn)了兩個讀命是否令你意識到什么呢?是的,00h是用于讀寫1sthalf的命令,而01h是用于讀取2ndhalf的命令。現(xiàn)在我可以結(jié)合上圖給你說明為什么K9F1208U0B的DataField被分為2個half了。
如上文我所提及的,Read1的1st.Cycle是發(fā)送ColumnAddress,假設(shè)我現(xiàn)在指定的ColumnAddress是0,那么讀操作將從此頁的第0號Byte開始一直讀取到此頁的最后一個Byte(包括SpareField),如果我指定的ColumnAddress是127,情況也與前面一樣,但不知道你發(fā)現(xiàn)沒有,用于傳遞ColumnAddress的數(shù)據(jù)線有8條(I/O0-I/O7,對應(yīng)addr[7,0],這也是addr[8]為什么不出現(xiàn)在我們傳遞的地址位中),也就是說我們能夠指定的ColumnAddress范圍為0-255,但不要忘了,1個Page的DataField是由512個Byte組成的,假設(shè)現(xiàn)在我要指定讀命令從第256個字節(jié)處開始讀取此頁,那將會發(fā)生什么情景?我必須把ColumnAddress設(shè)置為256,但ColumnAddress最大只能是255,這就造成數(shù)據(jù)溢出。正是因為這個原因我們才把DataField分為兩個半?yún)^(qū),當(dāng)要讀取的起始地址(ColumnAddress)在0-255內(nèi)時我們用00h命令,當(dāng)讀取的起始地址是在256-511時,則使用01h命令.假設(shè)現(xiàn)在我要指定從第256個byte開始讀取此頁,那么我將這樣發(fā)送命令串。
column_addr=256;
NF_CMD=0x01;從2ndhalf開始讀取
NF_ADDR=column_addr&0xff;1stCycle
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=0x30;
事實上,當(dāng)NF_CMD=0x01時,NANDFlash地址寄存器中的第8位(A8)將被設(shè)置為1(如上文分析,A8位不在我們傳遞的地址中,這個位其實就是硬件電路根據(jù)01h或是00h這兩個命令來置高位或是置低位),這樣我們傳遞column_addr的值256隨然由于數(shù)據(jù)溢出變?yōu)?,但A8位已經(jīng)由于NF_CMD=0x01的關(guān)系被置為1了。這8個位所表示的正好是256,這樣讀操作將從此頁的第256號byte(2ndhalf的第0號byte)開始讀取數(shù)據(jù)。
在對NANDFlash進行任何操作之前,NANDFlash必須被初始化。向NandFlash的命令寄存器和地址寄存器發(fā)送完以上命令和參數(shù)之后,我們就可以從rNFDATA寄存器(NandFlash數(shù)據(jù)寄存器)讀取數(shù)據(jù)了.
我用下面的代碼進行數(shù)據(jù)的讀取.
for(i=column_addr;i<512;i++)
{
*buf++=NF_RDDATA();
}
每當(dāng)讀取完一個Page之后,數(shù)據(jù)指針會落在下一個Page的0號Column(0號Byte).
存儲操作特點:
1.擦除操作的最小單位是塊。
2.NandFlash芯片每一位(bit)只能從1變?yōu)?,而不能從0變?yōu)?wbr />1,所以在對其進行寫入操作之前要一定將相應(yīng)塊擦除(擦除即是將相應(yīng)塊得位全部變?yōu)?wbr />1).
3.OOB部分的第六字節(jié)(即517字節(jié))標(biāo)志是否是壞塊,如果不是壞塊該值為FF,否則為壞塊。
4.除OOB第六字節(jié)外,通常至少把OOB的前3個字節(jié)存放NandFlash硬件ECC碼(關(guān)于硬件ECC碼請參看Nandflash控制器一節(jié)).
重要芯片引腳功能
I/O0-I/O7:復(fù)用引腳??梢酝ㄟ^它向nandflash芯片輸入數(shù)據(jù)、地址、nandflash命令以及輸出數(shù)據(jù)和操作狀態(tài)信息。
CLE(CommandLatchEnable):命令鎖存允許
ALE(AddressLactchEnable):地址鎖存允許
-CE:芯片選擇
-RE:讀允許
-WE:寫允許
-WP:在寫或擦除期間,提供寫保護
R/-B:讀/忙輸出
NandFlash控制器中的硬件ECC介紹
ECC產(chǎn)生方法
ECC是用于對存儲器之間傳送數(shù)據(jù)正確進行校驗的一種算法,分硬件ECC和軟件ECC算法兩種,在S3C2440的NandFlash控制器中實現(xiàn)了由硬件電路(ECC生成器)實現(xiàn)的硬件ECC。
ECC生成器工作過程
當(dāng)寫入數(shù)據(jù)到Nandflash存儲空間時,ECC生成器會在寫入數(shù)據(jù)完畢后自動生成ECC碼,將其放入到ECC0-ECC2。當(dāng)讀出數(shù)據(jù)時NandFlash同樣會在讀數(shù)據(jù)完畢后,自動生成ECC碼將其放到ECC0-ECC2當(dāng)中。
ECC的運用
當(dāng)寫入數(shù)據(jù)時,可以在每頁寫完數(shù)據(jù)后將產(chǎn)生的ECC碼放入到OOB指定的位置(Byte6)去,這樣就完成了ECC碼的存儲。這樣當(dāng)讀出該頁數(shù)據(jù)時,將所需數(shù)據(jù)以及整個OOB讀出,然后將指定位置的ECC碼與讀出數(shù)據(jù)后在ECC0-ECC1的實際產(chǎn)生的ECC碼進行對比,如果相等則讀出正確,若不相等則讀取錯誤需要進行重讀。
操作命令字介紹
操作NAND FLASH時,先傳輸命令,接著輸出地址,最后讀/寫數(shù)據(jù),期間還要檢查FLASH的狀態(tài)。具體的命令字見下表。
1、Read命令字為00h,30h。
如上圖,當(dāng)發(fā)出00h命令后,接著4個字節(jié)的地址序列,然后再發(fā)出30h命令,接著,就可以讀出數(shù)據(jù)了,當(dāng)發(fā)送完30h后,可以檢測R/B引腳看是否準(zhǔn)備好了,如果準(zhǔn)備好,就可以讀出數(shù)據(jù)。
2、Reset
命令字:FFh
當(dāng)向芯片發(fā)送FFh命令時,可以復(fù)位芯片,如果芯片正在處于讀、寫、擦除狀態(tài),復(fù)位命令會終止這些命令。
3、Page Program
命令字:80h,10h.
NAND FLASH的寫操作一般是以頁為單位進行的,因此才會叫Page Program,但是也支持一個字以上的(包括一個字)連續(xù)寫操作。開始發(fā)出80h命令,接著發(fā)送5個字節(jié)的地址序列,然后向FLASH發(fā)送數(shù)據(jù),最大為一頁大小,最后發(fā)送10h命令啟動燒寫,此時FLASH內(nèi)部會自動完成寫、校驗操作。發(fā)送10h后,可以通過讀狀態(tài)命令70h(見下文)獲知寫操作是否完成,是否成功。
4、Copy-Back Program
命令字:00h、8Ah、10h.
此命令用于將一頁復(fù)制到同一層的另外一頁,它省去了讀出數(shù)據(jù)、將數(shù)據(jù)重新載入FLASH的過程,使得效率大大提高。
關(guān)于層:NAND FLASH有層的概念,K9F2G08分為兩層,每層包括了1024個塊,如下圖,因此上面的命令表中才會有two-plane的命令,這些命令可以使得在兩個層間完成操作,這樣程序員就很方便的使用一個命令完成更多的操作,其命令格式和單層操作的類似,詳見手冊。但K9F2G08R0A不支持兩層命令。
上圖清晰的告訴我們,開始發(fā)送00h和源地址,當(dāng)發(fā)送35h之后,芯片將一頁大小的數(shù)據(jù)讀入到內(nèi)部寄存器,接著,我們發(fā)送85h和目的地址序列,最后發(fā)送10h啟動。最后,我們可以使用70h/7Bh檢測是否完成,是否成功。
5、Block Erase
命令字:60h、D0h
擦除操作是以塊為單位的,也就是128K。開始發(fā)出60h,然后發(fā)出3個地址序列僅行地址,最好發(fā)出D0h。具體操作,如下圖。
6、Read Status
命令字:70h
讀狀態(tài)命令可以讀出芯片的狀態(tài)寄存器,查看是否讀、寫操作是否完成、是否成功。具體的狀態(tài)見下圖。
S3C2440的NAND FLASH控制器介紹
看了上面的命令時序圖,大家肯定認為對NAND FLASH的操作比較復(fù)雜,因此S3C2440為了簡化操作,為我們提供了幾個寄存器,比如NFCMD寄存器,就是NAND FLASH命令寄存器,如果我們需要讀命令,直接向此寄存器寫00h、30h即可。
基本操作步驟:
1.設(shè)置NFCONF和NFCONT寄存器,配置NAND FLASH;
2.向NFCMD寄存器寫入命令;
3.向NFADDR寄存器寫入地址;
4.讀/寫數(shù)據(jù),通過NFSTAT檢測NAND FLASH的狀態(tài),讀R/nB信號以確定是否完成操作,是否成功。
主要寄存器:
(NFCONF)
配置寄存器,設(shè)置NAND FLASH的時序參考TACLS、TWRPH0、TWRPH1,這三個參數(shù)見下面時序圖;設(shè)置位寬度;還包括一些只讀位,用來批示是否支持其它大小的頁。
TACLS:表示CLT/ALE的建立時間(setup time)。
TWRPH0:表示CLE/ALE的持續(xù)時間。
TWRPH1:表示CLE/ALE的維持時間(hold time)。
NFCONT
用來使能/禁止NAND FLASH控制器、使能/禁止控制引腳信號nFCE、初始化ECC。
NFCMD
命令寄存器,用來向其寫入命令。
NFADDR
地址寄存器,用來向其寫入地址。
NFDATA
數(shù)據(jù)寄存器,用來讀、寫數(shù)據(jù)使用,只用到8位。
NFSTAT
狀態(tài)寄存器,只用到一位,0:busy;1:ready。
NFECC
校驗寄存器,ECC 校驗寄存器
NAND FLASH的操作(以讀為例)
1、設(shè)置NFCONF和NFCONT
NFCONF主要是設(shè)置TACLS、TWRPH0、TWRPH1三個時間參數(shù)。根據(jù)手冊的參數(shù)表,見下圖:
三個參數(shù)只有最小值 MIN,沒有最大值,因此,只要參數(shù)大于表格中的數(shù)即可,這里涉及時鐘的一些概念,這里直接將參數(shù)告訴大家:
TACLS=1;TWRPH0=4;TWRPH1=0。
NFCONT設(shè)置為:NFCONT=(1<<4)|(1<<1)|(1<<0) 表示使能NAND FLASH控制器、禁止控制引腳信號nFCE、初始化ECC。
評論