copy from http://blog.csdn.net/renpine/article/details/4570538
目錄
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的資料。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_01633889755101250000.jpg)
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
目錄
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的資料。
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。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_02.jpg)
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),而是將資料存在內部頁緩衝器中,所以會比一般的讀取加上寫入少了將資料讀寫到外部記憶體的時間,執行上也更快且更有效率。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_03.jpg)
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的操作。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_04.jpg)
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資訊。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_05.jpg)
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)所示。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_06.jpg)
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了。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_07.jpg)
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永遠不會被回收的。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_08.jpg)
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裡。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_09.jpg)
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。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_10.jpg)
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的轉換。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_11.jpg)
Figure 11. Wear Leveling in the FTL [4]
另一種的實現方法為Wear Leveling直接在FileSystem裡實現,OS直接透過HAL和NAND Flash溝通。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_12.jpg)
Figure 12.Wear Leveling in the File System [4]
Flow Chart
Read
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_13.jpg)
Figure 13 Read Operation Flow Chart
Erase
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_14.jpg)
Figure 14 Erase Operation Flow Chart
Write
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_15.jpg)
Figure 15 Write Operation Flow Chart
Timing/Power
Timing
Read Operation
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_16.jpg)
BandWidth:39.82MB/s
Write Operation
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_17.jpg)
BandWidth:4.66MB/s~1.36MB/s
Erase Operation
![](https://p-blog.csdn.net/images/p_blog_csdn_net/renpine/EntryImages/20090919/A_Tutorial_on_NAND_Flash_Memory_and_Its_Management_Issues_18.jpg)
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
第一章绪论 7-15
1.1课题来源 7-8
1.2研究背景与意义 8-14
1.2.1Flash介绍 8
1.2.2NAND Flash介绍 8-10
1.2.3NAND Flash与NORFlash比较 10-13
1.2.4研究目的 13-14
1.3论文章节安排 14-15
第二章NANDFlash结构与原理 15-31
2.1NAND Flash种类 15-17
2.1.1SLC 15
2.1.2MLC 15-17
2.2NAND Flash结构 17-29
2.2.1NAND Flash结构 17-22
2.2.2NAND Flash的主要流程 22-29
2.2.2.1读操作 22-23
2.2.2.2页编程操作 23-25
2.2.2.3块擦除操作 25-26
2.2.2.4COPY-BACK编程 26-27
2.2.2.5Two Plane相关操作 27-29
2.3小结 29-31
第三章NANDFlash动态坏块管理算法 31-61
3.1NAND Flash坏块管理 31-33
3.1.1坏块管理概念的提出 31-32
3.1.2坏块管理的一般方法 32-33
3.2NAND Flash动态坏块管理算法研究与实现 33-56
3.2.1NAND Flash动态坏块管理设计思想 33-35
3.2.2动态坏块管理算法步骤流程及具体函数实现 35-55
3.2.3动态坏块管理算法与一般坏块管理算法比较总结 55-56
3.3损耗平衡 56-58
3.3.1损耗平衡原理和使用意义 56-57
3.3.2损耗平衡算法 57-58
3.4垃圾回收机制 58-61
NANDFLASH内存详解与读写寻址方式
一、内存详解
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的器件。这就使得一种封装和接口能够在将来支持较高的密度。
图2NOR闪存的随机存取时间为0.12ms,而NAND闪存的第一字节随机存取速度要慢得多
NOR闪存的随机存取时间为0.12ms,而NAND闪存的第一字节随机存取速度要慢得多
NAND基本操作
以2GbNAND器件为例,它由2048个区块组成,每个区块有64个页(见下图):
每一个页均包含一个2048字节的数据区和64字节的空闲区,总共包含2,112字节。空闲区通常被用于ECC、耗损均衡(wearleveling)和其它软件开销功能,尽管它在物理上与其它页并没有区别。NAND器件具有8或16位接口。通过8或16位宽的双向数据总线,主数据被连接到NAND存储器。在16位模式,指令和地址仅仅利用低8位,而高8位仅仅在数据传输周期使用。
擦除区块所需时间约为2ms。一旦数据被载入寄存器,对一个页的编程大约要300μs。读一个页面需要大约25μs,其中涉及到存储阵列访问页,并将页载入16,896位寄存器中。
除了I/O总线,NAND接口由6个主要控制信号构成:
1.芯片启动(ChipEnable, CE#):如果没有检测到CE信号,那么,NAND器件就保持待机模式,不对任何控制信号作出响应。
2.写使能(WriteEnable, WE#): WE#负责将数据、地址或指令写入NAND之中。
3.读使能(ReadEnable, RE#): RE#允许输出数据缓冲器。
4.指令锁存使能(CommandLatch Enable, CLE): 当CLE为高时,在WE#信号的上升沿,指令被锁存到NAND指令寄存器中。
5.地址锁存使能(AddressLatch 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等其它类型存储器共享数据总线。该功能有时被称为"无需介意芯片启动(chipenable don't care)"。这种方案的初衷是适应较老的NAND器件,它们要求CE#在整个周期为低(译注:根据上下文改写)。
图4输入寄存器接收到页编程(80h)指令时,内部就会全部重置为1s,使得用户可以只输入他想以0位编程的数据字节
图5带有随机数据输入的编程指令。图中加亮的扇区显示,该指令只需要后面跟随着数据的2个字节的地址
当输出一串WE#时钟时,通过在I/O位7:0上设置指令、驱动CE#变低且CLE变高,就可以实现一个指令周期。注意:在WE#信号的上升沿上,指令、地址或数据被锁存到NAND器件之中。如表1所示,大多数指令在第二个指令周期之后要占用若干地址周期。注意:复位或读状态指令例外,如果器件忙,就不应该发送新的指令。
以2GbNAND器件的寻址方案为例,第一和第二地址周期指定列地址,该列地址指定页内的起始字节表:
注意:因为最后一列的位置是2112,该最后位置的地址就是08h(在第二字节中)和3Fh(在第一字节中)。PA5:0指定区块内的页地址,BA16:6指定区块的地址。虽然大多编程和读操作需要完整的5字节地址,在页内随机存取数据的操作仅仅用到第一和第二字节。块擦除操作仅仅需要三个最高字节(第三、第四和第五字节)来选择区块。
总体而言,NAND的基本操作包括:复位(Reset,FFh)操作、读ID(ReadID, 00h)操作、读状态(ReadStatus, 70h)操作、编程(Program)操作、随机数据输入(Randomdata 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,就提供了强大的系统级解决方案。最简单的硬件实现方案是采用简单的汉明(SimpleHamming)码,但是,只能校正单一位错误。瑞德索罗门(Reed-Solomon)码提供更为强大的纠错,并被目前的控制器广为采用。此外,BCH码由于比瑞德索罗门方法的效率高,应用也日益普及。
要用软件执行NAND闪存的区块管理。该软件负责磨损评级或逻辑到物理映射。该软件还提供ECC码,如果处理器不包含ECC硬件的话。
编程或擦除操作之后,重要的是读状态寄存器,因为它确认是否成功地完成了编程或擦除操作。如果操作失败,要把该区块标记为损坏且不能再使用。以前已编写进去的数据要从损坏的区块中搬出,转移到新的(好的)存储块之中。2GbNAND的规范规定,它可以最多有40个坏的区块,这个数字在器件的生命周期(额定寿命为10万次编程/擦除周期)内都适用。一些有坏块的NAND器件能够出厂,主要就归根于其裸片面积大。管理器件的软件负责映射坏块并由好的存储块取而代之。
利用工厂对这些区块的标记,软件通过扫描块可以确定区块的好坏。坏块标记被固定在空闲区的第一个位置(列地址2048)。如果在0或1页的列地址2048上的数据是"non-FF",那么,该块要标记为坏,并映射出系统。初始化软件仅仅需要扫描所有区块确定以确定哪个为坏,然后建一个坏块表供将来参考。
小心不要擦除坏块标记,这一点很重要。工厂在宽温和宽电压范围内测试了NAND;一些由工厂标记为坏的区块可能在一定的温度或电压条件下仍然能工作,但是,将来可能会失效。如果坏块信息被擦除,就无法再恢复。
二、NAND FLASH读写寻址方式
NAND Flash的寻址方式和NANDFlash的memory组织方式紧密相关。NANDFlash的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。
这些Line会再组成Page,通常是528Byte/page或者264Word/page。然后,每32个page形成一个Block,Sizeof(block)=16kByte.
Block是NANDFlash中最大的操作单元,擦除就是按照block为单位完成的,而
编程/读取是按照page为单位完成的。
所以,按照这样的组织方式可以形成所谓的三类地址:
-Block Address
-Page Address
-Column Address
首先,必须清楚一点,对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度可以是8位或者16位,但是,对于x16的NANDDevice,I/O[15:8]只用于传递数据。
清楚了这一点,我们就可以开始分析NANDFlash的寻址方式了。
以528Byte/page总容量512Mbit+512kbyte的NAND器件为例:
因为,
1 block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area)
用户数据保存在mainarea中。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由所谓的pointeroperation命令来选择,也就是选择了bit8的高低。因此A8就是halfpagepointer,A[7:0]就是所谓的columnaddress。
32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,共8192个block,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block
NAND Flash的地址表示为:
Block Address|Page Address in block|halfpage pointer|ColumnAddress
地址传送顺序是ColumnAddress,Page Address,BlockAddress。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。
例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。
以NAND_ADDR为例:
第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写,而真正的bit8的值是don'tcare的。
第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-stepaddressing。
如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
NandFlash结构与读写分析及NandFlash寻址方式【ZZ】
看vivi代码的head.S的时候,看到copy_myself的部分,尤其nand_read_ll函数,看不太明白,不了解nandflash原理,结合nandflash的datasheet和网上的文章,对那个函数就大概了解一点了
http://www.mcuol.com/Solution/195/21883.htm
下面的内容也是别人转载的,我继续转载http://hi.baidu.com/luyun21/blog/item/e0fa82af6de3c6c87dd92a6b.html,内容好像有点乱,我只看了一点点,对其寻址明白了一点,暂时就这样了,暂时还没需要继续研究,有需要在研究
NandFlash结构与读写分析
NAND Flash 的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page,(NandFlash有多种结构,我使用的NandFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Byte,每32个page形成一个Block,Sizeof(block)=16kByte。1block=16kbyte,512Mbit=64Mbyte,Numberof(block)=10241block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:--Block Address --Page Address --Column Address(即为页内偏移地址)
对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress。32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block, NAND Flash 的地址表示为:Block Address|PageAddress in block|halfpage pointer|Column Address地址传送顺序是ColumnAddress,Page Address,Block Address。由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。以NAND_ADDR为例: 第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写。而真正的bit8的值是don\'tcare的。 第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-stepaddressing。 如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候bit8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
norflash和nandflash的区别
norflash中可以运行程序,nandflash不可以
Norflash按sector可擦除,按bit可读写。NandFlash按Block可擦除,按Page可读写。
最主要是寻址方式不同
*********************************************************************************************************************************
NandFlash寻址方式
NAND Flash的寻址方式和NANDFlash的memory组织方式紧密相关。NANDFlash的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。
这些Line会再组成Page,通常是528Byte/page或者264Word/page。然后,每32个page形成一个Block,Sizeof(block)=16kByte.
Block是NANDFlash中最大的操作单元,擦除就是按照block为单位完成的,而
编程/读取是按照page为单位完成的。
所以,按照这样的组织方式可以形成所谓的三类地址:
-Block Address
-Page Address
-Column Address
首先,必须清楚一点,对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度可以是8位或者16位,但是,对于x16的NANDDevice,I/O[15:8]只用于传递数据。
清楚了这一点,我们就可以开始分析NANDFlash的寻址方式了。
以528Byte/page总容量512Mbit+512kbyte的NAND器件为例:
因为,
1 block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(Main Area)+16byte(Spare Area)
用户数据保存在mainarea中。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由所谓的pointeroperation命令来选择,也就是选择了bit8的高低。因此A8就是halfpagepointer,A[7:0]就是所谓的columnaddress。
32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,共8192个block,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block
NAND Flash的地址表示为:
Block Address|Page Address in block|halfpage pointer|ColumnAddress
地址传送顺序是ColumnAddress,Page Address,BlockAddress。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。
例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。
以NAND_ADDR为例:
第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写,而真正的bit8的值是don'tcare的。
第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-stepaddressing。
如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
NANDFlash Architecture
Architecture
NANDFlash是由4096個Blocks所組成的,每個Block是由128個Pages所組成的,而每個Page是由4KBytes的UserData加上128Bytes的SpareData所構成的,故每個Block的容量為528Kbytes,每個Page的容量為4224Bytes。其中,SpareData主要是用來存放ECC(ErrorCorrecting Code)、BadBlock Information和FileSystem的資料。
Figure 1.Flash MemoryGeometry
NANDFlash的操作特點為:抹除(Erase)的最小單位是Block,而讀取(Read)和寫入(Write)則是以Page為單位。因NANDFlash的每個bit只能由1變為0,而不能從0變為1,所以對Flash做寫入時一定要將其對應的Block先抹除掉,才能做寫入的動作,也因此同樣一個page只能夠寫入一次。
Constraints andFunctionalities
Constraints
Sequential Pageprogram
在一個Block裡,Page必須從LSB(leastsignificant bit) Page依序寫到MSB(mostsignificant bit) Page,隨意不照Pageaddress來寫入是禁止的。另外,LSB是寫入的Pages中最小的位址,不一定是Page0。
Figure2.Sequential Page program [1]
Partial Pageprogram
在NANDFlash中,存取資料的最小單位是Page。在SLCFlash中,若想修改Page中的Data時可以更改部分的Bit而不需要將整個Page抹除後才更改。例如Page中的Data為1001011101,若想將Data改成1001010001,只需將其中的2個Bit更改為0即可,不用抹除後寫入。但之後的MLCFlash,已經不允許此功能了。
Performance-ImprovingCommands
Copy Back Program
CopyBack Program可以快速地將1頁的資料複製(Copy)到另1個指定的頁中,也對於垃圾收集(GarbageCollection)非常的有用。例如當1頁裡的資料壞掉造成整個區塊(Block)為損壞區塊(BadBlock, or Worn-Out Block)時,CopyBack Program可以有效率地將所有有效頁(ValidPage)的資料複製到指定的區塊中。
Copy BackProgram是將1整頁的資料(來源Page)讀取且複製到內部頁緩衝器(InternalPageBuffer)中,再將它寫到另1整頁中(目標Page)。因為它不像一般的讀取、寫入指令將資料存取到外部記憶體(Memory),而是將資料存在內部頁緩衝器中,所以會比一般的讀取加上寫入少了將資料讀寫到外部記憶體的時間,執行上也更快且更有效率。
Figure 3.Copy BackProgram [1]
Random datainput/output
當對Page的資料做讀寫時,必須將1整頁的所有資料都存在於外部記憶體中,當外部的RAM不夠大時,無法一次存放整個頁的資料,故利用NANDFlash的InternalPage Buffer來存放整個頁的資料,並使用RandomData Input/Output就可以對頁中任意位址的資料做存取。
對1頁裡的資料做一般的讀寫時,資料都是Sequential的,但若想要隨意存取1頁裡的資料,如想要存取ECC的資料,便可使用Randomdata input/output跳至UserData的尾端去存取ECC的資料。
-Plane program
NANDFlash Vendor將MemoryArray分成2個Plane,可以同時對2個不同Blockaddresses做Read/Write/Erase的操作。
Figure 4.2-PlaneProgram [6]
NAND-flash ManagementIssues
Address Translation
NANDFlashMemory的同1個page不能做重覆寫入的行為。再者,在寫入1個sector資料之前,必須要有抹除1個Block的資料才能做寫入的動作,但抹除1個Block的動作需要耗費相當多的時間,此舉造成了NANDFlash效能下降的最大原因。為了改善效能,最有效的方法就是減少Erase的次數,因此有了MappingTable。
Mapping Table的管理分為Blocklevel、Sectorlevel以及改良的Hybridlevel。
Block level的addressmapping是指1個LogicalBlock對應到1個PhysicalBlock,它的mappingtable相對於sector-level的mappingtable來的小,能夠節省mappingtable所占RAM的使用量。但當LogicalBlock的個數少於PhysicalBlock個數時,會發生LogicalBlock時常被overwrite的狀況,選定要overwrite的Logicalblock和它mapping的PhysicalBlock都要將資料更新到新的PhysicalBlock上,且做erase-before-write的動作,而造成效能的下降,此外轉換單位大,每次寫入的單位也大,因此會帶來額外的資料寫入成本。
而Sector-Level的addressmapping是1個LogicalSector可以對應到任1個PhysicalBlock裡的Sector,雖然這種mapping的方式彈性佳,可以減少因轉換單位大而帶來額外的資料寫入成本,但是mappingtable的Size過大,例如1GB的Flash,1個sector的大小為512byte的話,RAM就要維護二百萬筆的sector資訊。
Figure 5.資料區塊,紀錄區塊,以及備用區塊的使用。
(a)完整的資料區塊(b)資料依序寫入紀錄區塊的可寫頁中(c)區塊鏈的Merge
改良的Hybridlevel,擷取Blocklevel和Sectorlevel的優點,採用Blocklevel的方式,再加上有限數量的Block做為Sectorlevel的mapping,除了讓mappingtable的size限制住不至於龐大,也減少了erase-before-write的動作。Hybridlevel中,將PhysicalBlock取名為資料區塊(DataBlock),因為資料不能直接更新於資料區塊裡,我們找了一段可寫的Block來紀錄更新的資料,並將它取名為紀錄區塊(LogBlock)。經過一段時間的寫入,一個LBA(LogicalBlock Address)對應會對應一個資料區塊,而此資料區塊會跟著數個紀錄區塊,整個形成一個區塊鏈(BlockChain),如圖5(b)所示。
Figure 6.HybridLevel mapping table [7]
HybridLevel在做write的時候,在寫第1、2筆資料時(sector4,5),會由blocklevel的mappingtable找出DataBlock 10,因為對應sector裡內容是空的,因此就直接寫入DataBlock 10裡。而寫第3筆資料時(sector4),由Blocklevel的mappingtable找到DataBlock 10,但裡面已有寫入的資料,故改由sectorlevel的mappingtable找尋空的LogBlock,寫入第3筆資料。在寫第4筆資料時(sector4),因為sectorlevel的mappingtable裡已有mapped的LogBlock,故將第4筆資料依序寫入對映的LogBlock裡。
而在讀取時,會先由Sectorlevel的mappingtable裡,找出最新的資料,而LogBlock裡沒有的資料,則由BlockLevel mapping table裡找到的DataBlock裡。
GarbageCollection
主要是用於將不必要存在且浪費空間的Block做回收,來增加可用的Block數。當需要新的LogBlock時,會從已經使用的LogBlock裡選取符合回收條件的Block來做GarbageCollection,如freesector低於threshold值。
被選定要回收的LogBlock,會和它的DataBlock做merge的動作,意即選取新的DataBlock,將LogBlock中sector資料copy到此新的DataBlock中,再將原先DataBlock中剩餘的sector資料複製到此新的DataBlock中。
更新block-leveltable對應到新的DataBlock,並將sector-leveltable裡將剛才回收的LogBlock移除。原先的LogBlock和DataBlock做抹除的動作,即完成GarbageCollection了。
例如Figure4中,要將Logblock(pbn=20)做回收時,會將此logblock中最新的資料(sector4)複製到新的DataBlock中(假設為pbn=12),再將它的Datablock(pbn=10)中,其餘的資料(sector5)複製到新的DataBlock(pbn=12)中。並將blocklevel table中對應到pbn=20的資料改為對應到pbn=12,即新的datablock,再將sectorlevel table中pbn=20(回收的logblock)這筆資料刪除。最後將pbn=20,pbn=10舊的block做抹除的動作即可。
Merge在一種特殊情況下,可以做switch的動作,例如像Figure4中,LogBlock(pbn=30)裡是照sector的順序寫入,因此它的DataBlock(pbn=11)裡的資料都是不需要使用的舊資料,要做GarbageCollection,只需要將LogBlock和DataBlock對調即可,即block-leveltable裡對應到pbn=11這筆資料改為對應到pbn=30,而sector-leveltable裡對應到pbn=30這筆刪除,然後將舊的DataBlock(pbn=11)抹除就達到GarbageCollection了。
Figure 7.GarbageCollection Operation [3]
當在做GarbageCollection時,會希望用最少的cleaningwork來獲得最多的freespace,因此會選擇最多garbage的segment來做回收。另外,將資料的型態分為靜態和動態的資料。其中,Read-onlydata屬於靜態資料,即一旦創造就不會去修改它,而動態資料是會被修改的。動態資料依其資料修改頻率分為colddata(較少修改的資料)和hotdata(修改頻繁的資料)。
依不同的資料型態,做資料搬移時的方式也分為三種:
Read-only Data mix withdynamic data
當要被回收的segment中有read-onlydata時,會先將所有的read-onlydata搬到新的segment裡。若此新的segment又會被回收時,之前搬移過的read-onlydata仍然會再被搬移一次。另外,當一個segment中的資料都為read-onlydata時,則此segment永遠不會被回收的。
Figure8.Repeatedly migrating read-only data when they are mixed withdynamic data [9]
Cold data mix with hotdata
當要被回收的segment中有colddata和hotdata時,因colddata更改的頻率較少,在cleaning的期間colddata有較高的可能性為valid的,因此會將colddata搬移到新的segment裡。
Figure 9.Migratingcold data when they are mixed with hot data [9]
Data have high localityof reference
當要被回收segment中的data是有高度被參考性的,這些hotdata在cleaning的過程中仍可能是valid,但在被搬移到新的segment時,hotdata又被更新一次而成為garbage,這類的搬移即稱為uselessmigration。
Figure 10.Uselessmigration when hot data are updated soon after being migrated [9]
Wear-Leveling
當在使用Flash時,常會對某個檔案做修改的動作,當此時檔案變動而要用到更多的Page且Flash中仍有空的Block時,會將空的Block配置給此檔案來使用,若Flash中已經沒有空的Block時,則會執行GarbageCollection來清出空的Block以供使用。在挑選空的Block或執行GarbageCollection清出空的Block時,可能會造成部分的Block時常被挑選,這些Block可能因為被過度使用而造成損毀。為了避免這種情況發生,會使用Wear-Leveling,讓大部分Block的存取次數平均,而不會常常挑選到某些固定的Block上,造成Block的過度存取而損毀。
再者,NANDFlash抹除和寫入的reliability有使用的次數(100,000次),使用wear-leveling可以紀錄並平均每個block被使用的次數。
Wear-Leveling有兩種方式來實現,一種是在FileSystem和NANDFlash中間的FTL(FlashTranslation Layer)裡實現的。FTL可以讓上層的OS透過FTL以disk的方式去讀寫下層的NANDFlash,另外也提供了virtualaddress和physicaladdress的轉換。
Figure 11. WearLeveling in the FTL [4]
另一種的實現方法為WearLeveling直接在FileSystem裡實現,OS直接透過HAL和NANDFlash溝通。
Figure 12.WearLeveling in the File System [4]
Flow Chart
Read
Figure 13Read Operation Flow Chart
Erase
Figure14 Erase Operation Flow Chart
Write
Figure15 Write Operation Flow Chart
Timing/Power
Timing
ReadOperation
BandWidth:39.82MB/s
WriteOperation
BandWidth:4.66MB/s~1.36MB/s
Erase Operation
Power
P(typ)=3.3V*15mA=49.5mW
P(max)=3.6V*30mA=108mW
ReadOperation
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
WriteOperation
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
EraseOperation
E(typ)=49.5mW*(245+
+200)ns=49.5mW*1500445ns
=
J
E(max)=108mW*(245+
+200)ns=108mW*10000445ns
=
J
Reference
SamsungElectronics, "K9GAG08UXM Specification"
Alex Kuo,"Application Note: Partial Page Program MirrorBit ORNAND withNAND interface", Spansion
STMicroelectronics, "AN1821Garbage Collection in Single Level Cell NAND Flash memories"
STMicroelectronics, "AN1822 Wear Leveling in Single LevelCell NAND Flash memories"
STMicroelectronics, "AN1728How to use the Copy Back feature of ST Small Page NAND Flashmemories"
Amber Huffman, ONFI Technical Chair, "FlashPerformance Enhancements through ONFI", Intel Corporation
S.-W.Lee, D.-J. Park, T.-S. Chung, D.-H. Lee, S.-W. Park, H.-J. Song, "ALog Buffer-Based Flash Translation Layer Using Fully-AssociativeSector Translation", ACM Transactions on Embedded ComputingSystems, Vol.6,No.3,Article 18,Publication date: July 2007
STMicroelectronics, "AN1820 How to use the FTL and HALSoftware Modules to Manage Data in Single Level Cell NAND FlashMemories"
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的NANDFlash能达到200MB/s的读取速度
今天看到新闻Intel,Micron claim world’s fastest NANDflash,就直接到Micron的网站上浏览了一下。Micron的新产品分类为HighSpeed NAND Flash Products,用“HighSpeed”与原有NAND产品系列区分(估计ONFI3.0兼容的产品出来后,还要加上“Ultra”,才能再分出一个类别来)。 riple
Micron的HighSpeed系列目前按照容量分为8Gb、16Gb、32Gb三种,按照接口个数分为单端口(8Gb)和双端口(16、32Gb)两种。在Micron的网站上还看不到详细的datasheet,只能看到一个ProductBrief和Flyer。 riple
通过ProductBrief可以得到8Gb芯片的如下信息:采用了50nm而不是72nm工艺生产;是SLC而不是MLC结构;BGA封装取代了TSOP封装;4096Byte/Page,128Page/Block,512Blockx1/Plane,4Planes;I/O分为异步和同步(DDR)两种模式;速度最高的同步传输模式,读写I/O时间都是6ns/Toggle;读Array30us/Page,写Array160us/Page,擦Array3ms/Block。 riple
从上面的信息可以看出,HighSpeed特性要归功于6ns/Toggle的I/O时间,对于8bit的接口来说,相当于166MB/s的传输速度。 riple
但是,NANDFlash的访问速度不仅仅取决于I/O速度,还和Array传输时间、芯片内部缓冲结构和Plane数量有关。 riple
〇、NANDFlash访问时间分析 riple
访问操作 = 命令输入+I/O操作+Array传输操作,第一项的操作时间所占比例很小,在性能估算中可以忽略。 riple
访问时间 = I/O时间+ Array传输时间,在上一代NANDFlash中,第一项占的比例最大,是第二项的4-5倍。 riple
Micron主要采用了如下的4种技术缩短了平均的访问时间。其中第一种技术是第一次在NANDFlash上应用,也是这次“大提速”的核心技术。正是这项技术的采用,使上述公式中的第一项缩小到上一代的1/5,才使得其他3项技术发挥了最佳的效果。 riple
一、接口传输模式对I/O速度的影响 riple
采用ONFi2.0提出的DDR接口,提高了I/O数据传输速率:源同步(缩小了建立保持时间要求)、双边沿触发(加倍了数据传输速率)。 riple
二、Block结构和生产工艺对Array传输速度的影响 riple
与上一代NANDFlash相比,Page容量加倍,在Array传输时间基本不变的情况下,等效地加倍了Array传输速度。 riple
72nm到50nm的工艺改进,缩小了芯片面积,提高了芯片速度(读Array速度提升不明显,写Array速度提升了1倍),降低了功耗。 riple
三、缓冲与缓存对速度的影响 riple
Micron的NANDFlash的一大特点是:每一个Plane对应一个Page大小的缓冲(dataregister)和一个Page大小的缓存(cacheregister)。数据写入的顺序是:I/O-> cache register -> data register ->Plane,数据读出的顺序刚好相反。缓冲(dataregister)与缓存(cacheregister)之间的数据传输速度很快,dataregister可以把I/O操作和Array操作分隔开,形成I/O操作和Array操作的“两级流水线”。这种结构与上一代NANDFlash一样。(其实,4个Plane对应4个dataregister和1个cacheregister即可) riple
四、多Plane操作对速度的影响 riple
4个Plane对应4组缓冲与缓存,每一组可以分别操作。2个Plane交替操作,可以实现“乒乓操作”,达到2倍的Array访问带宽。4个Plane交替操作,可以实现“乒乒乓乓操作”,达到4倍的Array访问带宽。在上一代的NANDFlash芯片中,采用2Plane结构是比较常见的。 riple
五、200MB/s的读速度和100MB/s的写速度是怎样得到的 riple
读I/O时间:1Toggle/Bytex 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/Bytex 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速度限制了读取速度的最大值,在ONFi3.0预计的400MB/s的I/O速度实现后,NANDFlash的平均读取速度也能够达到400MB/s(这回就要采用4Plane模式了);Array传输速度限制了写入速度的最大值,如果不对芯片的内部结构和生产工艺进行改进的话,NANDFlash的平均写入速度很难进一步提高。 riple
nandflash总结
flash2009-12-09 13:21:37 阅读118评论0 字号:大中小 订阅
NANDFlash产品可以分为三大架构,分别是SingleLevel Cell;SLC,包括三星电子、Hynix、Micron以及东芝都是此技术使用者,第二种则是MultiLevelCell;MLC,目前有东芝、Renesas使用,不过三星电子将在2005第四季推出相关产品,最后则是Infineon与SaifunSemiconductors合资利用NROM技术所共同开发的MultiBit Cell;MBC。
MLC是Intel在1997年9月最先开发成功的,其作用是将两个位的信息存入一个Floating Gate(NADAFlash存储单元中存放电荷的部分),然后利用不同Level的电荷,透过内存储存格的电压控制精准读写,假设以4种电压控制、1个晶体管可存取2bits的数据,若是控制8种电压就可以存取3bits的数据,使Flash的容量大幅提升,类似Rambus的QRSL技术,通过精确控制浮动栅上的电荷数量,使其呈现出4种不同的存储状态,每种状态代表两个二进制数值(从00到11)。
当然不光是NOR型NANDFlash在使用,东芝在2003年2月推出第一款MLC型的NANDFlash,并接续2004年4月推出采用MLC技术的4Gbit与8GbitNAND Flash,显然这对于本来就以容量见长的NANDFlash更是如虎添翼。根据SemiconductorInsights研究,东芝利用90nmMLC技术所开发出来的4Gb,其die面积为144mm2。
至于SLC技术与EEPROM相同,但在Floatinggate与Sourcegate之中的氧化薄膜更薄,其数据的写入是透过对浮置闸极的电荷加电压,然后可以透过源极,即可将所储存的电荷消除,藉由这样的方式,便可储存1个个信息位,这种技术的单一位细胞方式能提供快速的程序编程与读取,不过此技术受限于Siliconefficiency的问题,必须要藉由较先进的流程强化技术Processenhancements,才能向上提升SLC制程技术。
将上述所言,做一个比较,SLC架构是0和1两个充电值,而MLC架构可以一次储存4个以上的充电值,因此MLC架构可以有比较好的储存密度,再加上可利用比较老旧的生产设备来提高产品的容量,而无须额外投资生产设备,可以享有成本与良率的优势。
不过MLC架构有着让使用者很难容忍的缺点,就是使用寿命较短,其次MLC架构只能承受约1万次的存取,远低于SLC架构的10万次。至于存取速度,SLC架构比MLC架构要快速三倍以上,加上MLC架构对于电力的消耗较多,因此使用者若是考虑长久使用、安全储存数据以及高速的存取速度等要求,恐怕会改采用SLC架构。
其实在NANDFlash市场中,若以理论数据比较,Renesas的AG-AND技术或是Infineon的MBC技术,其实并不逊于三星电子、东芝或是其它业者,甚至于有过之而无不及,不过这两家业者因为产能、技术开发等问题造成延迟扩大市场占有率时机,这也印证商场中的一句话,任何东西都必须要能够适时适地推出,否则只是将市场拱手让给对方。
Nand Flash结构与读写分析
NAND Flash 的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page,(NandFlash有多种结构,我使用的NandFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Byte,每32个page形成一个Block,Sizeof(block)=16kByte。1block=16kbyte,512Mbit=64Mbyte,Numberof(block)=10241block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:--Block Address --Page Address --Column Address(即为页内偏移地址)
对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half和2ndhalf,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress。32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block, NAND Flash 的地址表示为:Block Address|PageAddress in block|halfpage pointer|Column Address地址传送顺序是ColumnAddress,Page Address,Block Address。由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。以NAND_ADDR为例: 第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写。而真正的bit8的值是don\'tcare的。 第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-stepaddressing。 如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候bit8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
norflash和nandflash的区别
norflash中可以运行程序,nandflash不可以
Norflash按sector可擦除,按bit可读写。NandFlash按Block可擦除,按Page可读写。
最主要是寻址方式不同
*********************************************************************************************************************************
Nand Flash 寻址方式
NAND Flash的寻址方式和NANDFlash的memory组织方式紧密相关。NANDFlash的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。
这些Line会再组成Page,通常是528Byte/page或者264Word/page。然后,每32个page形成一个Block,Sizeof(block)=16kByte.
Block是NANDFlash中最大的操作单元,擦除就是按照block为单位完成的,而
编程/读取是按照page为单位完成的。
所以,按照这样的组织方式可以形成所谓的三类地址:
-Block Address
-Page Address
-ColumnAddress
首先,必须清楚一点,对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度可以是8位或者16位,但是,对于x16的NANDDevice,I/O[15:8]只用于传递数据。
清楚了这一点,我们就可以开始分析NANDFlash的寻址方式了。
以528Byte/page总容量512Mbit+512kbyte的NAND器件为例:
因为,
1block=16kbyte,
512Mbit=64Mbyte,
Numberof(block)=1024
1block=32page,
1page=528byte=512byte(MainArea)+16byte(Spare Area)
用户数据保存在mainarea中。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由所谓的pointeroperation命令来选择,也就是选择了bit8的高低。因此A8就是halfpagepointer,A[7:0]就是所谓的columnaddress。
32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,共8192个block,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block
NAND Flash的地址表示为:
BlockAddress|Page Address in block|halfpage pointer|Column Address
地址传送顺序是ColumnAddress,Page Address,Block Address。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。
例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。
以NAND_ADDR为例:
第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写,而真正的bit8的值是don'tcare的。
第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-stepaddressing。
如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
NAND Flash 的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page.
(Nand Flash有多种结构,下面内容针对三星的K9F1208U0M),每页528Byte,每32个page形成一个Block,Sizeof(block)=16kByte。
1 block="16kbyte",
512Mbit=64Mbyte,
Numberof(block)=40961block=32page,
1page=528byte=512byte(MainArea)+16byte(Spare Area);
Nand flash以页为单位读写数据,而以块为单位擦除数据。
按照这样的组织方式可以形成所谓的三类地址:
--Block Address
-- Page Address
--Column Address
对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress。
32 个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,则blockaddress用A[26:24]表示。而pageaddress就是blcokaddress|page address in block
NAND Flash 的地址表示为:
Block Address|Page Addressin block|halfpage pointer|Column Address
地址传送顺序是ColumnAddress,PageAddress,BlockAddress。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。
以NAND_ADDR为例:
第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写。而真正的bit8的值是don'tcare的。
第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-stepaddressing。 如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候bit8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nandflash也分为若干block,每个block分为如干page。一般而言,block、page之间的关系随着芯片的不同而不同,典型的分配是这样的:
1block = 32page
1page = 512bytes(datafield)+ 16bytes(oob)
需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash的擦写,而擦写则是以一个block为单位的。同时必须提醒的是,512bytes理论上被分为1sthalf和2sdhalf,每个half各占256个字节。
我们讨论的K9F1208U0B总共有4096个Blocks,故我们可以知道这块flash的容量为4096*(32 *528)= 69206016 Bytes = 66 MB但事实上每个Page上的最后16Bytes是用于存贮检验码和其他信息用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为4096*(32 *512) = 67108864 Bytes = 64 MB由上图所示,1个Page总共由528Bytes组成,这528个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0行为第0Byte,第1行为第1Byte,以此类推,每个行又由8个位组成,每个位表示1个Byte里面的1bit)。这528Bytes按功能分为两大部分,分别是DataField和SpareField,其中SpareField占528Bytes里的16Bytes,这16Bytes是用于在读写操作的时候存放校验码用的,一般不用做普通数据的存储区,除去这16Bytes,剩下的512Bytes便是我们用于存放数据用的DataField,所以一个Page上虽然有528个Bytes,但我们只按512Bytes进行容量的计算。
读 命令有两个,分别是Read1,Read2其中Read1用于读取DataField的数据,而Read2则是用于读取SpareField的数据。对于NandFlash来说,读操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后,读操作将从该位置开始,连续读取到本Page的最后一个Byte为止(可以包括SpareField)
Nand Flash的寻址
NandFlash的地址寄存器把一个完整的NandFlash地址分解成ColumnAddress与PageAddress.进行寻址。
Column Address: 列地址。ColumnAddress其实就是指定Page上的某个Byte,指定这个Byte其实也就是指定此页的读写起始地址。
PaageAddress:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0。确定读写操作是在Flash上的哪个页进行的。
Read1命令
当我们得到一个NandFlash地址src_addr时我们可以这样分解出ColumnAddress和PageAddress
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以这么认为,一个NandFlash地址的A0~A7是它的column_addr,A9~A25是它的PageAddress。(注意地址位A8并没有出现,也就是A8被忽略,在下面你将了解到这是什么原因)
Read1命令的操作分为4个Cycle,发送完读命令00h或01h(00h与01h的区别请见下文描述)之后将分4个Cycle发送参数,1st.Cycle是发送ColumnAddress。2nd.Cycle,3rd.Cycle和4th.Cycle则是指定PageAddress(每次向地址寄存器发送的数据只能是8位,所以17位的PageAddress必须分成3次进行发送
Read1的命令里面出现了两个命令选项,分别是00h和01h。这里出现了两个读命是否令你意识到什么呢?是的,00h是用于读写1sthalf的命令,而01h是用于读取2ndhalf的命令。现在我可以结合上图给你说明为什么K9F1208U0B的DataField被分为2个half了。
如上文我所提及的,Read1的1st.Cycle是发送ColumnAddress,假设我现在指定的ColumnAddress是0,那么读操作将从此页的第0号Byte开始一直读取到此页的最后一个Byte(包括SpareField),如果我指定的ColumnAddress是127,情况也与前面一样,但不知道你发现没有,用于传递ColumnAddress的数据线有8条(I/O0~I/O7,对应A0~A7,这也是A8为什么不出现在我们传递的地址位中),也就是说我们能够指定的ColumnAddress范围为0~255,但不要忘了,1个Page的DataField是由512个Byte组成的,假设现在我要指定读命令从第256个字节处开始读取此页,那将会发生什么情景?我必须把ColumnAddress设置为256,但ColumnAddress最大只能是255,这就造成数据溢出。。。正是因为这个原因我们才把DataField分为两个半区,当要读取的起始地址(ColumnAddress)在0~255内时我们用00h命令,当读取的起始地址是在256~511时,则使用01h命令.假设现在我要指定从第256个byte开始读取此页,那么我将这样发送命令串
column_addr=256;
NF_CMD=0x01; ? 从2ndhalf开始读取
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(2ndhalf的第0号byte)开始读取数据。nand_flash.c中包含3个函数
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned intsrc_addr,unsigned char *desc_addr,int size);
nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nandflash进行任何操作之前,nf_init()必须被调用。
nf_read(unsigned intsrc_addr,unsigned char *desc_addr,intsize);为读函数,src_addr是nandflash上的地址,desc_addr是内存地址,size是读取文件的长度。
在nf_reset和nf_read函数中存在两个宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到当每次对NandFlash进行操作之前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是NandFlash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。
现在举一个例子,假设我要从NandFlash中的第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; 从2ndhalf开始读取
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 charseBuf[16]={0xff};
//--------------------------------------------------------------------------------------
unsigned shortnf_checkId(void)
{
int i;
unsignedshort 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
returnid;
}
//--------------------------------------------------------------------------------------
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 rxxx, r xxx
// En r r ECCR nFCE="H"tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned intsrc_addr,unsigned char *desc_addr,int size)
{
int i;
unsignedint column_addr = src_addr % 512; // column address
unsignedint page_address = (src_addr >> 9); // page addrress
unsignedchar *buf = desc_addr;
while((unsignedint)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); // Read2command. cmd 0x01: Read command(start from 2end halfpage)
else
NF_CMD(0x00); // 1sthalft?
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的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page.
(Nand Flash 有多种结构,我使用的NandFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Byte,每32个page形成一个Block,Sizeof(block)=16kByte。
1block="16kbyte",512Mbit=64Mbyte,Numberof(block)=40961block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash以页为单位读写数据,而以块为单位擦除数据。
按照这样的组织方式可以形成所谓的三类地址:
--Block Address -- PageAddress --Column Address
对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress。
32 个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A[25:14],如果是1Gbit的528byte/page的NANDFlash,则blockaddress用A[26:24]表示。而pageaddress就是blcokaddress|page address in block
NAND Flash 的地址表示为:
Block Address|Page Addressin block|halfpage pointer|Column Address
地址传送顺序是ColumnAddress,Page Address,Block Address。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。以NAND_ADDR为例: 第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写。而真正的bit8的值是don'tcare的。 第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-stepaddressing。 如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候bit8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nandflash也分为若干block,每个block分为如干page。一般而言,block、page之间的关系随着芯片的不同而不同,典型的分配是这样的:
1block = 32page
1page = 512bytes(datafield)+ 16bytes(oob)
需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash的擦写,而擦写则是以一个block为单位的。同时必须提醒的是,512bytes理论上被分为1sthalf和2sdhalf,每个half各占256个字节。
我们讨论的K9F1208U0B总共有4096个Blocks,故我们可以知道这块flash的容量为4096*(32 *528)= 69206016 Bytes = 66 MB但事实上每个Page上的最后16Bytes是用于存贮检验码和其他信息用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为4096*(32 *512) = 67108864 Bytes = 64 MB由上图所示,1个Page总共由528Bytes组成,这528个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0行为第0Byte,第1行为第1Byte,以此类推,每个行又由8个位组成,每个位表示1个Byte里面的1bit)。这528Bytes按功能分为两大部分,分别是DataField和SpareField,其中SpareField占528Bytes里的16Bytes,这16Bytes是用于在读写操作的时候存放校验码用的,一般不用做普通数据的存储区,除去这16Bytes,剩下的512Bytes便是我们用于存放数据用的DataField,所以一个Page上虽然有528个Bytes,但我们只按512Bytes进行容量的计算。
读 命令有两个,分别是Read1,Read2其中Read1用于读取DataField的数据,而Read2则是用于读取SpareField的数据。对于NandFlash来说,读操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后,读操作将从该位置开始,连续读取到本Page的最后一个Byte为止(可以包括SpareField)
Nand Flash的寻址
NandFlash的地址寄存器把一个完整的NandFlash地址分解成ColumnAddress与PageAddress.进行寻址。
Column Address: 列地址。ColumnAddress其实就是指定Page上的某个Byte,指定这个Byte其实也就是指定此页的读写起始地址。
PaageAddress:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0。确定读写操作是在Flash上的哪个页进行的。
Read1命令
当我们得到一个NandFlash地址src_addr时我们可以这样分解出ColumnAddress和PageAddress
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以这么认为,一个NandFlash地址的A0~A7是它的column_addr,A9~A25是它的PageAddress。(注意地址位A8并没有出现,也就是A8被忽略,在下面你将了解到这是什么原因)
Read1命令的操作分为4个Cycle,发送完读命令00h或01h(00h与01h的区别请见下文描述)之后将分4个Cycle发送参数,1st.Cycle是发送ColumnAddress。2nd.Cycle,3rd.Cycle和4th.Cycle则是指定PageAddress(每次向地址寄存器发送的数据只能是8位,所以17位的PageAddress必须分成3次进行发送
Read1的命令里面出现了两个命令选项,分别是00h和01h。这里出现了两个读命是否令你意识到什么呢?是的,00h是用于读写1sthalf的命令,而01h是用于读取2ndhalf的命令。现在我可以结合上图给你说明为什么K9F1208U0B的DataField被分为2个half了。
如上文我所提及的,Read1的1st.Cycle是发送ColumnAddress,假设我现在指定的ColumnAddress是0,那么读操作将从此页的第0号Byte开始一直读取到此页的最后一个Byte(包括SpareField),如果我指定的ColumnAddress是127,情况也与前面一样,但不知道你发现没有,用于传递ColumnAddress的数据线有8条(I/O0~I/O7,对应A0~A7,这也是A8为什么不出现在我们传递的地址位中),也就是说我们能够指定的ColumnAddress范围为0~255,但不要忘了,1个Page的DataField是由512个Byte组成的,假设现在我要指定读命令从第256个字节处开始读取此页,那将会发生什么情景?我必须把ColumnAddress设置为256,但ColumnAddress最大只能是255,这就造成数据溢出。。。正是因为这个原因我们才把DataField分为两个半区,当要读取的起始地址(ColumnAddress)在0~255内时我们用00h命令,当读取的起始地址是在256~511时,则使用01h命令.假设现在我要指定从第256个byte开始读取此页,那么我将这样发送命令串
column_addr=256;
NF_CMD=0x01; ? 从2ndhalf开始读取
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(2ndhalf的第0号byte)开始读取数据。nand_flash.c中包含3个函数
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned intsrc_addr,unsigned char *desc_addr,int size);
nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nandflash进行任何操作之前,nf_init()必须被调用。
nf_read(unsigned intsrc_addr,unsigned char *desc_addr,intsize);为读函数,src_addr是nandflash上的地址,desc_addr是内存地址,size是读取文件的长度。
在nf_reset和nf_read函数中存在两个宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到当每次对NandFlash进行操作之前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是NandFlash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。
现在举一个例子,假设我要从NandFlash中的第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; 从2ndhalf开始读取
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 charseBuf[16]={0xff};
//--------------------------------------------------------------------------------------
unsigned shortnf_checkId(void)
{
int i;
unsignedshort 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
returnid;
}
//--------------------------------------------------------------------------------------
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 rxxx, r xxx
// En r r ECCR nFCE="H"tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned intsrc_addr,unsigned char *desc_addr,int size)
{
int i;
unsignedint column_addr = src_addr % 512; // column address
unsignedint page_address = (src_addr >> 9); // page addrress
unsignedchar *buf = desc_addr;
while((unsignedint)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); // Read2command. cmd 0x01: Read command(start from 2end halfpage)
else
NF_CMD(0x00); // 1sthalft?
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 ;
}
NandFlash结构与读写分析
今天在利用ARM7上的nandflash控制器驱动,ID已读取成功,擦写,读取等尚未完成,晚上就在网上查查相关的知识,觉得有一个不错,转贴如下:
NAND Flash 的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page.
(Nand Flash 有多种结构,我使用的NandFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Byte,每32个page形成一个Block,Sizeof(block)=16kByte。
1block="16kbyte",512Mbit=64Mbyte,Numberof(block)=40961block=32page, 1page=528byte=512byte(Main Area)+16byte(Spare Area)
Nand flash 以页为单位读写数据,而以块为单位擦除数据。
按照这样的组织方式可以形成所谓的三类地址:
--BlockAddress-- PageAddress--ColumnAddress
对于NANDFlash来讲,地址和命令只能在I/O【7:0】上传递,数据宽度是8位。
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf和2ndhalf,各自的访问由地址指针命令来选择,A【7:0】就是所谓的columnaddress。
32个page需要5bit来表示,占用A【13:9】,即该page在块内的相对地址。Block的地址是由A14以上的bit来表示,例如512Mb的NAND,共4096block,因此,需要12个bit来表示,即A【25:14】,如果是1Gbit的528byte/page的NANDFlash,则blockaddress用A【26:24】表示。而pageaddress就是blcokaddress|page address in block
NAND Flash 的地址表示为:
BlockAddress|Page Address in block|halfpage pointer|Column Address
地址传送顺序是ColumnAddress,Page Address,Block Address。
由于地址只能在I/O【7:0】上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。以NAND_ADDR为例: 第1步是传递columnaddress,就是NAND_ADDR【7:0】,不需移位即可传递到I/O【7:0】上,而halfpagepointer即bit8是由操作指令决定的,即指令决定在哪个halfpage上进行读写。而真正的bit8的值是don‘tcare的。 第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-stepaddressing。 如果NANDFlash的容量是256Mbit以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候bit8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nandflash也分为若干block,每个block分为如干page。一般而言,block、page之间的关系随着芯片的不同而不同,典型的分配是这样的:
1block = 32page
1page = 512bytes(datafield) + 16bytes(oob)
需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash的擦写,而擦写则是以一个block为单位的。同时必须提醒的是,512bytes理论上被分为1sthalf和2sdhalf,每个half各占256个字节。
我们讨论的K9F1208U0B总共有4096个Blocks,故我们可以知道这块flash的容量为4096*(32 *528)= 69206016 Bytes = 66 MB但事实上每个Page上的最后16Bytes是用于存贮检验码和其他信息用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为4096*(32 *512) = 67108864 Bytes = 64 MB由上图所示,1个Page总共由528Bytes组成,这528个字节按顺序由上而下以列为单位进行排列(1列代表一个Byte。第0行为第0Byte,第1行为第1Byte,以此类推,每个行又由8个位组成,每个位表示1个Byte里面的1bit)。这528Bytes按功能分为两大部分,分别是DataField和SpareField,其中SpareField占528Bytes里的16Bytes,这16Bytes是用于在读写操作的时候存放校验码用的,一般不用做普通数据的存储区,除去这16Bytes,剩下的512Bytes便是我们用于存放数据用的DataField,所以一个Page上虽然有528个Bytes,但我们只按512Bytes进行容量的计算。
读命令有两个,分别是 Read1,Read2其中Read1用于读取DataField的数据,而Read2则是用于读取SpareField的数据。对于NandFlash来说,读操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后,读操作将从该位置开始,连续读取到本Page的最后一个Byte为止(可以包括SpareField)
NandFlash的寻址
NandFlash的地址寄存器把一个完整的NandFlash地址分解成ColumnAddress与PageAddress.进行寻址。
ColumnAddress: 列地址。ColumnAddress其实就是指定Page上的某个Byte,指定这个Byte其实也就是指定此页的读写起始地址。
PaageAddress:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0。确定读写操作是在Flash上的哪个页进行的。
Read1命令
当我们得到一个NandFlash地址src_addr时我们可以这样分解出ColumnAddress和PageAddress
column_addr=src_addr%512; // column address
page_address=(src_addr>>9); // page address
也可以这么认为,一个NandFlash地址的A0~A7是它的column_addr,A9~A25是它的PageAddress。(注意地址位A8并没有出现,也就是A8被忽略,在下面你将了解到这是什么原因)
Read1命令的操作分为4个Cycle,发送完读命令00h或01h(00h与01h的区别请见下文描述)之后将分4个Cycle发送参数,1st.Cycle是发送ColumnAddress。2nd.Cycle,3rd.Cycle和4th.Cycle则是指定PageAddress(每次向地址寄存器发送的数据只能是8位,所以17位的PageAddress必须分成3次进行发送
Read1的命令里面出现了两个命令选项,分别是00h和01h。这里出现了两个读命是否令你意识到什么呢?是的,00h是用于读写1sthalf的命令,而01h是用于读取2ndhalf的命令。现在我可以结合上图给你说明为什么K9F1208U0B的DataField被分为2个half了。
如上文我所提及的,Read1的1st.Cycle是发送ColumnAddress,假设我现在指定的ColumnAddress是0,那么读操作将从此页的第0号Byte开始一直读取到此页的最后一个Byte(包括SpareField),如果我指定的ColumnAddress是127,情况也与前面一样,但不知道你发现没有,用于传递ColumnAddress的数据线有8条(I/O0~I/O7,对应A0~A7,这也是A8为什么不出现在我们传递的地址位中),也就是说我们能够指定的ColumnAddress范围为0~255,但不要忘了,1个Page的DataField是由512个Byte组成的,假设现在我要指定读命令从第256个字节处开始读取此页,那将会发生什么情景?我必须把ColumnAddress设置为256,但ColumnAddress最大只能是255,这就造成数据溢出。。。正是因为这个原因我们才把DataField分为两个半区,当要读取的起始地址(ColumnAddress)在0~255内时我们用00h命令,当读取的起始地址是在256~511时,则使用01h命令.假设现在我要指定从第256个byte开始读取此页,那么我将这样发送命令串
column_addr=256;
NF_CMD=0x01; ? 从2ndhalf开始读取
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) //NANDFlash address
事实上,当NF_CMD=0x01时,地址寄存器中的第8位(A8)将被设置为1(如上文分析,A8位不在我们传递的地址中,这个位其实就是硬件电路根据01h或是00h这两个命令来置高位或是置低位),这样我们传递column_addr的值256随然由于数据溢出变为1,但A8位已经由于NF_CMD=0x01的关系被置为1了,所以我们传到地址寄存器里的值变成了
A0 A1 A2 A3A4 A5 A6 A7 A8
1 0 0 0 0 0 0 0 1
这8个位所表示的正好是256,这样读操作将从此页的第256号byte(2ndhalf的第0号byte)开始读取数据。nand_flash.c中包含3个函数
voidnf_reset(void);
void nf_init(void);
void nf_read(unsigned intsrc_addr,unsigned ch ar *desc_addr,int size);
nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nandflash进行任何操作之前,nf_init()必须被调用。
nf_read(unsignedint src_addr,unsigned ch ar *desc_addr,int size);为读函数,src_addr是nandflash上的地址,desc_addr是内存地址,size是读取文件的长度。
在nf_reset和nf_read函数中存在两个宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到当每次对NandFlash进行操作之前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是NandFlash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。
现在举一个例子,假设我要从NandFlash中的第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; 从2ndhalf开始读取
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"
staticunsigned ch ar seBuf【16】={0xff};
//--------------------------------------------------------------------------------------
unsigned shortnf_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; // Makercode(K9S1208V:0xec)
id|=NF_RDDATA(); // Devidecode(K9S1208V:0x76)
NF_nFCE_H(); //chip enable
return id;
}
//--------------------------------------------------------------------------------------
static voidnf_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(); //chipdisable
}
//--------------------------------------------------------------------------------------
voidnf_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();
}
//--------------------------------------------------------------------------------------
voidnf_read(unsigned int src_addr,unsigned ch ar *desc_addr,int size)
{
int i;
unsigned int column_addr = src_addr % 512; // columnaddress
unsigned int page_address = (src_addr >> 9); //page addrress
unsigned ch ar *buf = desc_addr;
while((unsignedint)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); // Read2command. 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结构与驱动分析
一、NANDflash的物理组成
NANDFlash 的数据是以bit的方式保存在memorycell,一般来说,一个cell中只能存储一个bit。这些cell以8个或者16个为单位,连成bitline,形成所谓的byte(x8)/word(x16),这就是NANDDevice的位宽。这些Line会再组成Page,(NANDFlash有多种结构,我使用的NANDFlash是K9F1208,下面内容针对三星的K9F1208U0M),每页528Bytes(512byte(MainArea)+16byte(SpareArea)),每32个page形成一个Block(32*528B)。具体一片flash上有多少个Block视需要所定。我所使用的三星k9f1208U0M具有4096个block,故总容量为4096*(32*528B)=66MB,但是其中的2MB是用来保存ECC校验码等额外数据的,故实际中可使用的为64MB。
NANDflash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:
ColumnAddress:StartingAddress of the Register.翻成中文为列地址,地址的低8位
PageAddress :页地址
BlockAddress :块地址
对于NANDFlash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
二、NANDFlash地址的表示
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1sthalf Page Register和2ndhalf Page Register,各自的访问由地址指针命令来选择,A[7:0]就是所谓的columnaddress(列地址),在进行擦除操作时不需要它,why?因为以块为单位擦除。32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。A8这一位地址被用来设置512byte的1sthalf page还是2ndhalf page,0表示1st,1表示2nd。Block的地址是由A14以上的bit来表示。
例如64MB(512Mb)的NANDflash(实际中由于存在sparearea,故都大于这个值),共4096block,因此,需要12个bit来表示,即A[25:14],如果是128MB(1Gbit)的528byte/page的NANDFlash,则blockaddress用A[26:14]表示。而pageaddress就是blcokaddress|page address in block NAND Flash 的地址表示为:BlockAddress|Page Address in block|halfpage pointer|Column Address地址传送顺序是ColumnAddress,Page Address,Block Address。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。例如,对于512Mbitx8的NANDflash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。以NAND_ADDR为例:
第1步是传递columnaddress,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpagepointer即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-stepaddressing。 如果NANDFlash的容量是32MB(256Mbit)以下,那么,blockadress最高位只到bit24,因此寻址只需要3步。
下面,就x16的NANDflash器件稍微进行一下说明。由于一个page的mainarea的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1sthalfpage和2ndhalfpage之分了,所以,bit8就变得没有意义了,也就是这个时候A8完全不用管,地址传递仍然和x8器件相同。除了,这一点之外,x16的NAND使用方法和x8的使用方法完全相同。
三、NANDflash驱动解读
以前由于做移植多一些,那些工作很简单(现在看来),从来都不用去关心驱动里面到底怎么实现的,这几次面试才发现真的是学的太浅了,似乎我还在学习仰泳而那些牛人基本都属于潜水级的了,潜的不知有多深。我对照着开发板所带的NANDflash驱动和k9f1208的芯片资料把这些代码通读了一遍,终于明白了NANDflash的读写过程是如何实现的了。我所参考的驱动是mizi公司为三星芯片所写的,我看看了,大概和官方2.4.18内核的nand.c差不多。
在s3c2410处理器中有专门的NANDflash控制器,他们位于SFR区,具体可以参看s3c2410用户手册。以下的这些代码均可以在vivi或者kernel里面找到,文中会标明程序出自何处。在vivi中,有关NANDflash的驱动都在driver/mtd/nand/下,该目录中包含的源文件:smc_core.c是NANDflash的主要驱动。
NANDflash 芯片定义了一个很长的结构,这个结构中包含了操作NANDflash的函数和一些必要的变量(include/mtd/nand.h)。
structnand_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_charval);
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 */
……
#ifdefCONFIG_MTD_NAND_ECC
u_char ecc_code_buf[6];
u_char reserved[2];
#endif
#endif /*CONFIG_MTD_NANDY */
};
纵观对NANDflash的各种操作(read、write、erase),无外乎如下几种操作:
1.选择flash nand_select()
2.发送命令 nand_command()
3.进行相应操作read,write……
4.反选NANDflash nand_deselect()
下面是以上四步的实现代码:
1、选择NANDflash
#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); \
nand_command(mtd, NAND_CMD_RESET, -1, -1); \
udelay (10);
hwcontrol(NAND_CTL_SETNCE) 的作用是设置2410的NANDFLASH CONFIGURATION (NFCONF) REGISTER的NANDFlash Memory chip enable位为0,这位寄存器在自动重启后就被系统自动清零。如果要访问NANDflash的内存,这位必须置1。
nand_command(mtd,NAND_CMD_RESET, -1, -1);向flash发送命令,此命令为reset,即为重置NANDflash。
然后是10us的延迟,给flash个反应时间。
2、发送命令
Nand_command()同样在smc_core.c中实现。NANDflash的命令有如下几种:
命令 命令值 描述
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 读FlashID号
NAND_CMD_ERASE2 0xd0 擦写操作
NAND_CMD_RESET oxff 复位操作
按照程序的注释,可以将该函数的实现分为如下几步:
1、Begincommand latch cycle
实现代码:
this->hwcontrol(NAND_CTL_SETCLE);
this->hwcontrol(NAND_CTL_DAT_OUT);
找到第二条语句的定义,发现什么都么做,不解!!希望达人解答。我猜想可能是一个数据读出的使能操作,允许数据读出。
CommandLatch Enable(CLE) and Address Latch Enable(ALE) are used to multiplexcommand and address respectively, via the I/O pins. The CLE inputcontrols the path activation for commands sent to the commandregister. When active high, commands are latched into the commandregister through the I/O ports on the rising edge of the nWE signal.看了这段英文相信对第一条语句的作用已经十分清楚了,他就是用来控制向命令寄存(COMMANDSET (NFCMD) REGISTER)发送命令的。
2、Write out thecommand to thedevice
这部分对于不同的命令来说,操作的步骤也不太相同,如果为写操作,那么还有根据flash不同的容量决定操作步骤,具体可以参看代码。如果为其他命令,那么就是简单的一行:
this->write_cmd(command);
将命令直接想到命令寄存器(NFCMD[7:0])中。
3、Set ALE andclear CLE to start address cycle & Serially inputaddress
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()将地址写到NANDFLASH ADDRESS SET (NFADDR) REGISTER中。
4、Latch inaddress
实现代码:
this->hwcontrol(NAND_CTL_CLRALE);
this->hwcontrol(NAND_CTL_DAT_IN);
地址发送完毕,清楚ALE。
5、Pause for15us
我使用的VIVI中,使用udelay(15)延时15us,但这个时间会因NANDFlash的不同而不同。
三、Operation
根据函数的不同,操作部分会不一样,但是主要的是对NANDFLASH DATA (NFDATA)REGISTER的操作,或写(编程)或者读。通过读或写函数的参数来返回或传递读出的值或写入的值。写得操作通常比较麻烦,他要将写到flash的内容重新读出后进行ECC校验,如果数据正确则在重新真正的写(编程),如果错误,则将数据写入flash的另一个块。读和写都是以页为单位进行操作。而擦除则以块为单位,三个周期发送完地址。擦除完毕后同样需要进行检察以确定是否擦除成功。
四、De-selectthe NAND device
实现代码:
#definenand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
反选flash吧,不知这样叫正确与否,跟selectthe 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;一些由工厂标记为坏的区块可能在一定的温度或电压条件下仍然能工作,但是,将来可能会失效。如果坏块信息被擦除,就无法再恢复。
nandflash坏块管理OOB,BBT,ECC
0.NAND的操作管理方式
NANDFLASH的管理方式:以三星FLAHS为例,一片Nandflash为一个设备(device),1(Device) = xxxx (Blocks),1(Block) = xxxx (Pages),1(Page) =528(Bytes) = 数据块大小(512Bytes)+ OOB块大小(16Bytes,除OOB第六字节外,通常至少把OOB的前3个字节存放NandFlash硬件ECC码)。
1.为什么会出现坏块
由于NANDFlash的工艺不能保证NAND的MemoryArray在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块。坏块的特性是:当编程/擦除这个块时,会造成PageProgram和BlockErase操作时的错误,相应地反映到StatusRegister的相应位。
2.坏块的分类
总体上,坏块可以分为两大类:(1)固有坏块:这是生产过程中产生的坏块,一般芯片原厂都会在出厂时都会将每个坏块第一个page的sparearea的第6个byte标记为不等于0xff的值。(2)使用坏块:这是在NANDFlash使用过程中,如果BlockErase或者PageProgram错误,就可以简单地将这个块作为坏块来处理,这个时候需要把坏块标记起来。为了和固有坏块信息保持一致,将新发现的坏块的第一个page的sparearea的第6个Byte标记为非0xff的值。
3.坏块管理
根据上面的这些叙述,可以了解NANDFlash出厂时在sparearea中已经反映出了坏块信息,因此,如果在擦除一个块之前,一定要先check一下第一页的sparearea的第6个byte是否是0xff,如果是就证明这是一个好块,可以擦除;如果是非0xff,那么就不能擦除,以免将坏块标记擦掉。当然,这样处理可能会犯一个错误―――“错杀伪坏块”,因为在芯片操作过程中可能由于电压不稳定等偶然因素会造成NAND操作的错误。但是,为了数据的可靠性及软件设计的简单化,还是需要遵照这个标准。
可以用BBT:badblocktable,即坏块表来进行管理。各家对nand的坏块管理方法都有差异。比如专门用nand做存储的,会把bbt放到block0,因为第0块一定是好的块。但是如果nand本身被用来boot,那么第0块就要存放程序,不能放bbt了。有的把bbt放到最后一块,当然,这一块坚决不能为坏块。bbt的大小跟nand大小有关,nand越大,需要的bbt也就越大。
4.坏块纠正
ECC:NANDFlash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。一般使用一种比较专用的校验——ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。
ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1。(512生成两组ECC?)
当往NANDFlash的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)需要对前面由于PageProgram错误发现的坏块进行一下特别说明。如果在对一个块的某个page进行编程的时候发生了错误就要把这个块标记为坏块,首先就要把块里其他好的面的内容备份到另外一个空的好块里面,然后,把这个块标记为坏块。当然,这可能会犯“错杀”之误,一个补救的办法,就是在进行完块备份之后,再将这个坏块擦除一遍,如果BlockErase发生错误,那就证明这个块是个真正的坏块,那就毫不犹豫地将它打个“戳”吧!
(2)可能有人会问,为什么要使用每个块第一页的sparearea的第六个byte作为坏块标记。这是NANDFlash生产商的默认约定,你可以看到Samsung,Toshiba,STMicroelectronics都是使用这个Byte作为坏块标记的。
(3)为什么好块用0xff来标记?因为NandFlash的擦除即是将相应块的位全部变为1,写操作时只能把芯片每一位(bit)只能从1变为0,而不能从0变为1。0XFF这个值就是标识擦除成功,是好块。