這是我準備的一個講解MTD子系統的一個文檔,我是以DM368 EVM板子的kernel 2.6.32.17為樣本代碼來講述的,各位最好準備3樣東西再開始閱讀我的文件。
1、DM368的晶片手冊 sprufg5_TMS320DM36xDMSoC ARM Subsystem Reference Guide.pdf
2、kernel 2.6.32.17的源碼
3、一份nand flash的硬體手冊,最好是2KB page的,如K9K8G08U0A.pdf
如果沒有我選用的晶片類型和kernel版本,也沒有關係,大的架構是一樣的,各位可以舉一反三。
MTD是一個很大的子系統,我的思路是從下向上,理出一條線來,讓大家理解Linux kernel是如果管理flash裝置的,上層的檔案系統和應用程式是如何操作flash的。
首先概述下flash吧。
在10年前的曆史上,嵌入式裝置上常用的flash有2種NOR flash和NAND flash,工作原理請自行參考網路資料,他們各有特點,有些裝置甚至同時使用nor和nand 兩種flash。
http://www2.electronicproducts.com/NAND_vs_NOR_flash_technology-article-FEBMSY1-feb2002-html.aspx
http://www.cnblogs.com/lidp/archive/2010/02/25/1696458.html
NOR-NAND comparison
PARAMETER |
NOR |
NAND |
Capacity |
1 to 16 Mbytes |
8 to 128 Mbytes |
XIP (code execution) |
Yes |
No |
Performance Erase Write Read |
Very Slow (5 s) Slow Fast |
Fast (3 ms) Fast Fast |
Strengths |
Addressable to every byte |
More than 10% higher life expectancy |
Erase cycle range |
10,000 to 100,000 |
100,000 to1,000,000 |
Interface |
SRAM-like, memory mapped |
Accessed in bursts of 512 bytes; I/O mapped |
Access method |
Random |
Sequential |
Price |
High |
Very low |
簡單來說,可以總結為上表。
從曆史的發展情況來看,目前大多數運行Linux的嵌入式系統都選用了nand flash,因為nand flash容量很大,性價比高。當然nor flash在某些產品領域中仍然有應用,這是題外話。
Nand flash這些年製造工藝上有了很大的進步,容量飛速增加,性價比進一步提高。
我們只需要知道隨身碟、SD卡、MP3、固態硬碟SSD都使用了nand flash作為儲存介質,再對比下這些年這些產品的價格和容量的走勢,就很容易理解nandflash的飛速發展了。
話說幾年前我們常用的SD卡才512MB,到現在8GB已經標配了,真是飛躍啊,甚至有種趨勢越來越明顯了,nandflash會取代機械硬碟!
現在再介紹下nand flash的幾個基本特性:
1、 資料區的邏輯組織關係Page、Block、OOB
以K9K8G08U0A為例,看;
Page是最小的讀寫單位,Block由多個相鄰Page組成,Block是最小的擦除單位,OOB也叫空閑區,用於存放每個Page的額外資料。
曆史上早期容量小的nand flash,1 Page = (512+16)Bytes,1 Block = 32 Page = 16KB;
現在容量大的flash,Page都加大了,如,1 Page是2KB,還有4KB的Page,具體參數看flash的硬體手冊。
1、 Nand flash的讀寫擦操作特性
Nand flash在寫之前必須先進行擦除操作;
擦除是以Block為單位的,擦除後,該Block內的所有Page資料區bit均為1;
如擦除失敗,需要在該Block的第一個Page的OOB中標記壞塊;
寫操作只能把Page的bit從1修改為0,反之則不行;
有人可能會想,那我能不能一次唯寫一個Page的某些bit呢?
答案是不行,如果你非要這麼做,後果自負!
為什麼這麼說?因為ECC。
如果不理會ECC,單獨寫某些bit,程式上是允許的,而且會激發很多的奇思妙想,也許已經有人這麼幹了,正在為自己的創意沾沾自喜。
但是,我希望你們能夠仔細認真的閱讀nand flash的硬體手冊,看看手冊上有沒有說明可以關閉ECC。只要硬體廠家沒有說明可以關閉ECC,你們就要為自己的程式提心弔膽一天。
為什麼要用ECC?因為位反轉。
http://againinput4.blog.163.com/blog/static/1727994912011885152491/
Nand Flash的位反轉位翻轉現象
Bit Flip/Bit Flipping/Bit-Flip/Bit twiddling of Nand Flash
Nand Flash由於本身硬體的內在特性,會導致(極其)偶爾的出現位反轉的現象。
所謂的位反轉,bit flip,指的是原先Nand Flash中的某個位,變化了,即要麼從1變成0了,要麼從0變成1了。
ECC的原理,可以在網上搜尋,比如http://blog.cechina.cn/dAsh/93427/message.aspx
Nand flash的原理和製造工藝決定了位反轉是不可避免的出錯現象,也許工藝越來越先進,發生的幾率會越來越小,但只要廠家沒有公開保證已經消除了位反轉,我們就必須使用ECC校正,否則程式崩潰死都不知道是怎麼死的。
上面說了這麼大一堆,就是要讓我們知道,寫操作必須一次寫一個Page,並且將ECC校正碼同步寫入該Page的OOB地區。
為什麼不能在已經儲存了資料的page上再次寫入資料?即使是把其中某些bit從1改寫成0也不可以?因為ECC!你在初次寫page資料的時候,就已經將對應的ECC寫入OOB了,你再次修改page資料內容,它的ECC碼也要重新計算,而你想再次寫入新的ECC碼到OOB時,它可能需要將某些bit從0改寫成1,而這是flash不允許的!
所以,正常的讀寫流程是,如果要寫入的page是乾淨的(剛擦除過,bit都為1),那麼就寫入完整page的資料,然後計算ECC,將ECC寫入OOB;如果要寫入的page已經充滿了資料,那麼要麼重新尋找一個乾淨的page寫新資料,要麼擦除對應的block,再寫入資料。
讀取資料的流程,按規範也應該是讀取完整的一個page,然後計算ECC,再跟OOB中的寫時ECC碼做校正,如果校正成功,讀取資料成功,否則失敗。
儘管flash提供了隨機讀取page內的任意資料的功能,但我們不應該這麼做,這麼做就無法使用ECC校正,一旦出現資料錯誤,就會引發程式崩潰等嚴重問題。
1、 Nand flash的壞塊管理
目前nand flash還不敢承諾出廠無壞塊,只能保證晶片的第一個block是好的,否則良率太低,必然導致成本大幅上升。而且隨著不斷擦除,使用過程中也會不斷出現壞塊。因此,我們必須面對壞塊這個問題。
壞塊的產生有三種情況,出廠時就有的壞塊,擦除操作失敗產生的壞塊,寫操作失敗產生的壞塊。
Nand flash每個單元的擦寫次數是有限制的,一般是10萬次(具體看硬體手冊),但這個10萬次是最大壽命呢,還是至少保證10萬次擦寫?沒有官方的回覆,總之我們要做好每次擦寫動作的錯誤處理就好了。
另外一個話題就是“偽壞塊”,為什麼會產生偽壞塊?我們在開發過程中,經常會對開發板進行一些修改調試,可能會導致擦寫flash的電壓不夠,這時候程式上讀取擦寫操作的返回狀態,就會得到失敗的狀態字,於是程式就將改塊標記為壞塊了。而正常的程式流程,在讀到壞塊標記後就會將改塊跳過,不再使用,也不再去擦除它。這樣就導致了偽壞塊的產生,這樣的偽壞塊如果在正常的工作電壓下進行擦除操作,通常是可以擦除成功,作為乾淨塊使用的。
Kernel裡面的nandflash驅動程式,為了提高效率,是不會再對標記壞塊做擦除動作的,因此在linux下無法清除偽壞塊,但是我們可以在uboot中徹底擦除flash,這樣是可以清除偽壞塊的。
那麼如何管理flash中的壞塊?
Kernel裡面的MTD會管理一個BBT,就是壞塊表。
一個進階話題,如何提高nand flash的使用壽命?
既然flash的每個單元的擦寫次數是有限的,那麼如果我們總是頻繁的擦寫flash上的某些塊,而另外一些塊很少被擦寫,那麼這些擦寫頻繁的塊就會很快達到使用壽命成為壞塊,這樣的壞塊多了,如果設計上沒有考慮好這個問題,就會影響整個裝置的使用壽命。
舉個例子,我們將flash上的某個分區格式化為FAT檔案系統,作為隨身碟來使用。FAT檔案系統最大的特點就是使用2個FAT表來儲存整個檔案系統分區的扇區使用方式,我們在隨身碟上進行檔案的複製刪除動作,檔案系統讀寫最頻繁的就是FAT表;根據前面講述的flash的讀寫特性,FAT表所在的Block就會很頻繁的被擦寫,時間長了該塊就會變成壞塊,如果2個FAT表所在的Block都成壞塊了,FAT檔案系統就無法使用了,隨身碟也就壞了。
當然,上面舉的例子,只是為了說明壞塊導致的問題,我相信任何一個生產隨身碟的廠家都發現了這個問題,也採取了一些措施來解決這個問題。
如何解決這個問題?均勻擦寫!簡單來講,就是建立邏輯塊和物理塊的一個映射關係,根據某種演算法,動態將某些擦寫頻繁的邏輯塊重新對應到不同的物理塊,在這個映射過程中,會將擦寫頻繁的物理塊與其他不常擦寫的物理塊做交換,比如我們對FAT表擦寫了10000次,但這個過程中我們將映射表做了修改,與其他塊做了10次交換,就相當於每個物理塊只擦寫了1000次,這樣就相當於提高了10倍的使用壽命。
具體的策略如何?,八仙過海,各有奇招。