:從物理結(jié)構(gòu)到SPI驅(qū)動與全志T113適配)
1. 項目概述為什么我們需要重新梳理NAND Flash在嵌入式開發(fā)、存儲系統(tǒng)設(shè)計甚至日常消費電子維修的圈子里NAND Flash這個詞出現(xiàn)的頻率高得驚人。但說實話我發(fā)現(xiàn)很多剛?cè)胄械呐笥焉踔烈恍┯袔啄杲?jīng)驗的工程師對它的理解都停留在“一種存數(shù)據(jù)的芯片”、“比硬盤快”這樣模糊的層面。當真正需要選型、寫驅(qū)動或者做故障分析時面對數(shù)據(jù)手冊里滿篇的“Page”、“Block”、“ECC”、“SLC/MLC/TLC”就有點發(fā)懵。最近在幫團隊新人做技術(shù)培訓以及處理幾個關(guān)于T113平臺NAND Flash適配的棘手問題時我深感有必要把這塊“老骨頭”重新啃一遍整理出一份既講透原理、又能直接指導實操的筆記。這份整理的目的很明確它不是一份簡單的名詞解釋列表而是一份從物理結(jié)構(gòu)到邏輯操作再到實際開發(fā)中避坑指南的完整地圖。無論你是正在編寫SPI NAND Flash裸機驅(qū)動的嵌入式軟件工程師還是在設(shè)計NAND Flash控制器的硬件架構(gòu)師亦或是需要為特定主控比如全志T113適配Flash的驅(qū)動開發(fā)者我希望這份內(nèi)容能幫你建立起清晰的概念框架知道每一個操作背后的物理限制是什么為什么控制器要這么設(shè)計以及當讀寫出錯時應(yīng)該從哪個環(huán)節(jié)開始排查。畢竟理解了“為什么”才能更好地應(yīng)對“怎么做”。2. NAND Flash核心物理結(jié)構(gòu)解析數(shù)據(jù)是如何被“關(guān)”起來的要理解NAND Flash的所有特性必須從它的物理結(jié)構(gòu)這個根兒上說起。你可以把它想象成一個巨大的、立體化的“網(wǎng)格本”但這個本子有它自己非常獨特的書寫和擦除規(guī)則。2.1 從晶體管到存儲單元電荷的囚籠NAND Flash的存儲核心是浮柵晶體管Floating Gate Transistor。這和我們常見的MOS管不同它在控制柵Control Gate和溝道之間多了一個被絕緣層通常是二氧化硅完全包圍的“浮柵”Floating Gate。這個浮柵與外界沒有任何電氣連接是個孤島。數(shù)據(jù)的寫入編程本質(zhì)上是向這個浮柵上注入電荷。通過給控制柵和漏極施加較高的電壓使得溝道中的電子獲得足夠能量穿越第一層絕緣層隧穿氧化層進入浮柵這個過程叫熱電子注入Channel Hot Electron Injection, CHE或** Fowler-Nordheim隧穿F-N Tunneling**。一旦電荷被困在浮柵上即使斷電由于絕緣層的阻擋電荷也能保存很多年典型數(shù)據(jù)保持時間在10年左右。浮柵上有電荷會改變晶體管的閾值電壓Vth。我們在讀取時施加一個介于“有電荷”和“無電荷”狀態(tài)閾值電壓之間的參考電壓通過檢測晶體管是否導通就能判斷存儲的是“1”還是“0”。這里有個關(guān)鍵點在NAND Flash的世界里擦除Erase才是讓存儲單元回到“1”狀態(tài)的操作即移除浮柵上的電荷。而編程Program是將“1”變成“0”即注入電荷。這和我們習慣的內(nèi)存“寫0/寫1”概念是反的。擦除操作是通過給襯底P-well加高壓讓浮柵上的電子通過F-N隧穿效應(yīng)被拉出來是整個Block一起進行的。2.2 層級架構(gòu)Page, Block, Plane 與 Die單個存儲單元太微小必須組織起來。NAND Flash采用了嚴格的層級管理結(jié)構(gòu)這直接決定了所有軟件操作接口的設(shè)計。頁Page最小的讀寫單元。你可以把它理解為這個網(wǎng)格本里的“一行”。一次讀或?qū)懖僮鞅仨氁砸粋€Page為單位進行?,F(xiàn)在的NAND Flash一個Page的大小通常是4KB、8KB、16KB甚至更大。每個Page后面還會附帶一塊區(qū)域叫做備用區(qū)Spare Area或OOBOut-Of-Band大小通常是主數(shù)據(jù)區(qū)的1/32到1/16比如4KB Page對應(yīng)128B或256B OOB。OOB是干什么的主要用來存放這個Page數(shù)據(jù)的ECC校驗碼、壞塊標記、文件系統(tǒng)元數(shù)據(jù)等關(guān)鍵管理信息。動OOB一定要小心里面的數(shù)據(jù)格式是控制器和文件系統(tǒng)約定好的亂寫可能導致數(shù)據(jù)無法識別。塊Block最小的擦除單元。這是NAND Flash最重要的一個特性也帶來了“寫前需擦”的麻煩。一個Block由幾十個到幾百個連續(xù)的Page組成例如128個、256個、512個Page。為什么擦除要以Block為單位因為擦除操作的高壓是施加在整個Block的P-well上的物理上無法只針對單個Page或幾個Page進行擦除。這就導致了著名的**“寫入放大Write Amplification”** 問題為了更新一個Page的數(shù)據(jù)你可能需要把整個Block里其他有效數(shù)據(jù)先搬走擦除整個Block再把新老數(shù)據(jù)一起寫回去。面Plane為了提升并行度和性能一個Die內(nèi)部可能會劃分成2個或4個Plane。每個Plane有自己獨立的頁緩沖寄存器Page Register。多平面操作Multi-Plane Operation允許對兩個Plane的相同Page地址同時進行編程或讀取有效吞吐量幾乎翻倍這是高性能NAND控制器必須利用的特性。晶圓Die一個獨立的NAND Flash芯片核心。一個物理封裝的芯片內(nèi)部可以封裝多個Die多晶圓封裝它們可以并行工作進一步提升速度和容量。理解這個層級關(guān)系至關(guān)重要。當你看到數(shù)據(jù)手冊上寫“Page Size: 4KB, Block Size: 256 Pages, Plane Size: 2 Planes per Die”你腦子里就應(yīng)該立刻浮現(xiàn)出它的物理圖像和操作限制讀/寫按4KB來但想重寫其中任何一部分都得至少以256*4KB1MB為單位進行擦除和重整。3. 核心概念深度剖析SLC/MLC/TLC/QLC、接口與ECC掌握了物理結(jié)構(gòu)我們再來拆解幾個讓初學者最容易混淆也最影響選型和開發(fā)的核心概念。3.1 存儲單元類型在密度與可靠性之間走鋼絲這是根據(jù)每個存儲單元能存放的比特數(shù)來劃分的直接決定了芯片的容量、成本、速度和壽命。SLCSingle-Level Cell每個單元存1比特2種狀態(tài)0或1。閾值電壓分布間隔寬狀態(tài)判斷非常容易。因此它具有極高的可靠性、超快的編程/讀取速度、超長的擦寫壽命通常10萬次以上。但代價是成本最高容量密度最低?,F(xiàn)在主要用于對可靠性、速度和壽命有極端要求的工業(yè)、軍事、企業(yè)級SSD緩存等場景。MLCMulti-Level Cell每個單元存2比特4種狀態(tài)00, 01, 10, 11。需要在更窄的電壓窗口內(nèi)區(qū)分4個狀態(tài)對電路精度和噪聲控制要求更高。速度、壽命典型3000-10000次和可靠性相比SLC有下降但成本更低容量翻倍。曾是消費級SSD和高端U盤的主流。TLCTriple-Level Cell每個單元存3比特8種狀態(tài)。電壓狀態(tài)更加擁擠需要更復(fù)雜的讀取算法如讀-重試和更強的ECC來保證數(shù)據(jù)正確性。擦寫壽命進一步降低典型500-1500次速度也更慢。但容量密度比MLC高50%成本更低是目前消費級固態(tài)硬盤和大部分大容量U盤、存儲卡的絕對主力。QLCQuad-Level Cell每個單元存4比特16種狀態(tài)。這是目前推向市場的民用極限。電壓狀態(tài)極其密集導致寫入速度慢尤其是從隨機寫入表現(xiàn)看、壽命短典型100-300次、對ECC依賴極強。它的主戰(zhàn)場是大容量、低成本、以順序?qū)懭霝橹鞯慕€存儲或消費級大容量SSD。選型心得不要只看容量和價格。對于頻繁寫入、需要快速響應(yīng)的系統(tǒng)如工業(yè)設(shè)備日志記錄、嵌入式數(shù)據(jù)庫即使用TLC容量夠也強烈建議考慮MLC甚至SLC否則后期維護和數(shù)據(jù)丟失的風險會成倍增加。對于幾乎只讀或極少更新的固件存儲QLC或許是個低成本大容量的選擇。3.2 接口類型并行與串行的演進異步并行接口Async Parallel經(jīng)典的老式接口有獨立的I/O數(shù)據(jù)線x8或x16、地址線、控制線CE#, CLE, ALE, WE#, RE#, R/B#等。優(yōu)點是協(xié)議簡單容易用GPIO模擬實現(xiàn)裸機驅(qū)動這也是很多學習者的起點。缺點是引腳多PCB走線復(fù)雜速度有瓶頸。現(xiàn)在主要見于低端、小容量的SLC/MLC芯片。ONFIOpen NAND Flash Interface與Toggle這是兩種主流的高速并行接口標準。它們引入了源同步時鐘DQS信號在時鐘邊沿采樣數(shù)據(jù)速率可以達到200MT/s、400MT/s甚至更高。ONFI是英特爾等公司推動的開放標準而Toggle是三星、東芝等廠商的標準。兩者互不兼容控制器需要分別支持。它們是目前高性能SSD內(nèi)部片間通信的主流方式。SPI NAND Flash近年來在嵌入式市場異軍突起。它使用簡單的SPISerial Peripheral Interface總線通常只需4根線CS#, CLK, DI, DO或6根線加上WP#和HOLD#。優(yōu)勢極其明顯引腳數(shù)極少封裝小常見8-SOP甚至WSON-8布線簡單可以直接與任何帶SPI控制器的主控連接無需專用的NAND控制器。這大大降低了硬件設(shè)計和系統(tǒng)集成的門檻。代價是性能受限于SPI時鐘頻率初期幾十MHz現(xiàn)在有高速模式能到200MHz以上峰值吞吐量遠低于并行接口。但對于很多成本敏感、性能要求不極端的IoT設(shè)備、消費電子、小容量嵌入式存儲來說SPI NAND是一個完美的平衡選擇。編寫SPI NAND裸機驅(qū)動核心就是理解其特定的命令集Read ID, Read Page, Program Page, Erase Block, Read Status等和如何通過SPI總線發(fā)送命令、地址和數(shù)據(jù)。3.3 錯誤校驗與糾錯ECC數(shù)據(jù)的守護神隨著存儲單元從SLC向QLC演進電荷量微小的差異、絕緣層老化導致的電荷泄漏、讀寫干擾等都會引起閾值電壓漂移導致讀取時誤判產(chǎn)生位錯誤Bit Error。ECC就是用來檢測和糾正這些錯誤的。必要性對于TLC/QLC出廠就可能存在一定比例的位錯誤隨著擦寫次數(shù)增加錯誤率RBER會上升。沒有ECC數(shù)據(jù)根本不可靠。ECC強度通常用能糾正的比特數(shù)來表示如“每512字節(jié)糾正4比特錯誤”。ECC強度必須與NAND Flash的原始誤碼率UBER要求匹配。TLC通常需要40比特/1KB以上的ECCQLC要求更高。實現(xiàn)位置片上ECC一些SPI NAND Flash芯片內(nèi)部集成了簡單的ECC引擎如1-bit/512B對于要求不高的應(yīng)用可以省去外部ECC計算??刂破鱁CC更常見的做法是在NAND Flash控制器無論是SoC內(nèi)置的還是獨立的SSD主控中實現(xiàn)強大的ECC算法如BCH碼或LDPC碼。控制器在寫入數(shù)據(jù)時計算ECC碼存入OOB讀取時再取出進行校驗和糾錯。這就是為什么裸讀NAND Flash的OOB區(qū)域你會看到一堆非零數(shù)據(jù)的原因。實操注意當你進行裸機驅(qū)動開發(fā)時如果主控沒有硬件ECC引擎你有兩個選擇1選用自帶ECC的SPI NAND芯片2在軟件中實現(xiàn)ECC算法如BCH但這會消耗大量CPU資源影響性能。在為現(xiàn)有主控適配新Flash時比如給全志T113適配一款新的NAND你必須確認主控的ECC能力支持多強的BCH或LDPC是否匹配新Flash的需求。如果不匹配要么換Flash要么面臨無法糾正的數(shù)據(jù)錯誤風險。這是適配工作中最容易踩坑的地方之一。4. NAND Flash控制器NFC的角色與工作原理NAND Flash芯片本身是一個“笨拙”的物理器件它需要一個大管家來管理其復(fù)雜的物理特性并向主機系統(tǒng)提供一個簡潔、可靠的塊設(shè)備接口。這個管家就是NAND Flash控制器。4.1 控制器的核心職責協(xié)議轉(zhuǎn)換與命令調(diào)度將主機發(fā)來的標準存儲訪問請求如ATA/SCSI命令或簡單的讀/寫扇區(qū)請求翻譯成NAND Flash芯片能聽懂的具體命令序列Command, Address, Data并處理復(fù)雜的時序。壞塊管理Bad Block Management, BBMNAND Flash出廠時就有一定比例的壞塊在使用過程中還會產(chǎn)生新的壞塊??刂破鞅仨毥⒉⒕S護一個壞塊表BBT將邏輯地址映射到物理地址時主動跳過這些壞塊。BBT本身必須存儲在NAND的某個可靠位置通常是在幾個固定好的Block的OOB里并在上電時加載。磨損均衡Wear Leveling, WL為了解決NAND Flash每個Block擦寫次數(shù)有限的問題控制器必須確保數(shù)據(jù)的寫入均勻地分布到所有物理Block上避免某些Block被“寫死”而其他Block還是新的。動態(tài)磨損均衡算法是控制器的核心算法之一。垃圾回收Garbage Collection, GC由于NAND Flash“寫前需擦”且擦除單位大當Block中只有部分數(shù)據(jù)無效時空間無法直接復(fù)用。垃圾回收進程負責將Block中仍然有效的數(shù)據(jù)搬移到新的位置然后擦除這個Block使其變?yōu)榭捎玫摹翱臻e塊”。這個過程會引發(fā)寫入放大。ECC校驗與糾錯如前所述在寫入時生成ECC碼在讀取時進行校驗和糾錯。這是保證數(shù)據(jù)可靠性的基石。讀寫緩存與緩沖利用RAM緩存數(shù)據(jù)優(yōu)化小數(shù)據(jù)寫入合并成整頁寫入提升性能。4.2 與主控的集成方式集成在SoC內(nèi)部如很多嵌入式MPU全志、瑞芯微、NXP i.MX系列等都內(nèi)置了NAND Flash控制器。開發(fā)者通常只需要配置好時序參數(shù)、頁大小、OOB布局、ECC強度等驅(qū)動起來相對方便。為T113適配新NAND Flash主要工作就是根據(jù)新Flash的數(shù)據(jù)手冊正確配置這些寄存器參數(shù)。獨立的SSD主控芯片在固態(tài)硬盤中它是一個功能極其復(fù)雜的獨立芯片集成了更高級的算法如更智能的WL、GCLDPC糾錯DRAM緩存接口等。軟件模擬FMC/FSMC在一些沒有專用NFC的STM32等MCU上可以通過靈活的靜態(tài)存儲器控制器FMC/FSMC用GPIO模擬NAND的時序來驅(qū)動但這通常性能較低且所有壞塊管理、ECC都需要軟件實現(xiàn)復(fù)雜度高。開發(fā)提示當你使用SoC內(nèi)置的NFC時數(shù)據(jù)手冊里關(guān)于NAND初始化的章節(jié)和NFC相關(guān)的寄存器描述是關(guān)鍵。重點關(guān)注時序參數(shù)寄存器如TCLS, TALS, TWR, TRR等這些值需要從Flash數(shù)據(jù)手冊的AC Characteristics表中計算得出、塊/頁大小配置寄存器、ECC使能與模式寄存器。配置錯誤會導致讀寫不穩(wěn)定甚至無法識別ID。5. 實戰(zhàn)SPI NAND Flash裸機驅(qū)動開發(fā)要點假設(shè)我們要在一塊STM32H7的板子上驅(qū)動一顆Winbond的SPI NAND Flash如W25N01GV。這是一個典型的裸機驅(qū)動場景。5.1 硬件連接與初始化連接非常簡單將Flash的/CS,CLK,DI(IO0),DO(IO1)分別連接到MCU的任意一個SPI外設(shè)的NSS, SCK, MOSI, MISO引腳即可。WP#和HOLD#引腳如果不用可以上拉到VCC。初始化順序SPI外設(shè)初始化配置為模式0或模式3CPOL0/1, CPHA0/1根據(jù)Flash數(shù)據(jù)手冊推薦設(shè)置。時鐘頻率初始可以設(shè)低一點如1MHz確保通信穩(wěn)定。讀取JEDEC ID發(fā)送0x9F命令連續(xù)讀取3-4個字節(jié)。第一個字節(jié)是制造商ID如Winbond是0xEF后續(xù)是設(shè)備ID。通過這個ID你可以在代碼中匹配已知的Flash參數(shù)表頁大小、塊大小、總?cè)萘康?。檢查狀態(tài)寄存器上電后發(fā)送0x0F讀狀態(tài)寄存器或0x05讀狀態(tài)寄存器-1。確保Flash不處于寫保護狀態(tài)或之前的編程/擦除操作已完成BUSY位為0。配置內(nèi)部寄存器可選一些SPI NAND有可配置的內(nèi)部寄存器比如ECC使能、緩存模式選擇等。例如W25N01GV可以通過0x06寫使能后跟0x1F寫特征寄存器來配置。務(wù)必仔細閱讀數(shù)據(jù)手冊確認默認配置是否滿足需求尤其是ECC是否開啟。5.2 實現(xiàn)基本操作函數(shù)驅(qū)動層需要實現(xiàn)以下幾個最基礎(chǔ)的函數(shù)spi_nand_read_id(): 如上所述。spi_nand_read_page(page_addr, *buffer, oob_buffer): 發(fā)送0x13讀頁加載命令和24位地址對于1Gb芯片地址為[PA17:PA0]然后發(fā)送0x03讀數(shù)據(jù)命令開始從SPI連續(xù)讀取數(shù)據(jù)。注意很多SPI NAND的讀操作是“加載到內(nèi)部緩存-從緩存讀出”兩步。地址是針對Page的。讀取時要連續(xù)讀完整個PageOOB的數(shù)據(jù)。spi_nand_program_page(page_addr, *buffer, oob_buffer): 先0x06寫使能然后0x02寫頁加載命令和地址接著連續(xù)寫入數(shù)據(jù)最后發(fā)送0x10寫頁執(zhí)行命令。關(guān)鍵點寫頁加載只是把數(shù)據(jù)放到內(nèi)部頁緩存0x10才是真正啟動編程注入電荷操作。執(zhí)行0x10后必須輪詢狀態(tài)寄存器直到BUSY位清零。spi_nand_erase_block(block_addr): 先0x06寫使能然后發(fā)送0xD8塊擦除命令和地址注意這里是塊地址需要根據(jù)芯片架構(gòu)將塊地址轉(zhuǎn)換為對應(yīng)的頁地址起始最后輪詢狀態(tài)。擦除是最耗時的操作通常需要幾毫秒到十幾毫秒。spi_nand_read_status()/spi_nand_wait_ready(): 輪詢狀態(tài)寄存器檢查BUSY位和FAIL位編程/擦除失敗標志。5.3 壞塊管理與OOB處理這是裸機驅(qū)動中最容易出錯的部分。壞塊檢測SPI NAND通常在出廠時會在每個Block的第一個或第二個Page的OOB區(qū)域的特定字節(jié)例如第0字節(jié)做標記不是0xFF比如0x00或0xF0來表示這是一個壞塊。你的驅(qū)動在初始化時應(yīng)該掃描所有Block的這個標記建立壞塊表BBT保存在RAM中。注意不同廠商的標記位置和值可能不同務(wù)必查數(shù)據(jù)手冊。OOB布局你的文件系統(tǒng)如UBIFS, YAFFS2或FTL層會定義OOB的用途。典型布局可能是前幾個字節(jié)放文件系統(tǒng)標記中間64字節(jié)放ECC數(shù)據(jù)最后幾個字節(jié)放壞塊標記。在read_page和program_page時你需要正確處理OOB緩沖區(qū)。一個黃金法則除非你明確知道你在做什么否則不要隨意覆蓋OOB中已有的數(shù)據(jù)。ECC處理如果Flash芯片內(nèi)部ECC已使能且能滿足你的需求那么你讀寫數(shù)據(jù)時可以不用管ECC。但如果你需要更強的ECC或者芯片沒有ECC那么你需要在program_page前計算好ECC碼填入OOB的指定位置在read_page后取出ECC碼進行校驗和糾錯。這通常需要軟件BCH庫的支持計算量較大。避坑指南時序問題SPI時鐘頻率不要一開始就設(shè)到最高。從低速開始測試穩(wěn)定后再逐步提高。確保/CS的建立和保持時間滿足數(shù)據(jù)手冊要求。狀態(tài)輪詢在執(zhí)行編程或擦除命令后必須等待操作完成。簡單的while(spi_nand_read_status() BUSY_MASK);可能會因為超時機制缺失而導致死循環(huán)。一定要加超時判斷。緩存未就緒有些操作如連續(xù)讀需要等待內(nèi)部緩存準備好。在發(fā)送讀數(shù)據(jù)命令0x03前可能需要先發(fā)送一個虛字節(jié)dummy byte或等待一小段固定時間。寫保護確保WP#引腳電平正確。意外拉低可能導致寫操作被拒絕。6. 為特定主控適配NAND Flash以全志T113為例為像全志T113這樣的SoC適配一款新的NAND Flash是嵌入式Linux BSP開發(fā)中的常見任務(wù)。這不僅僅是驅(qū)動一個芯片而是讓SoC內(nèi)置的NAND Flash控制器認識并正確操作這顆新的Flash。6.1 適配工作的核心步驟獲取關(guān)鍵參數(shù)拿到新NAND Flash的數(shù)據(jù)手冊提取以下信息設(shè)備ID通過Read ID命令返回的完整字節(jié)序列。頁大小Page Size如4096字節(jié)。塊大小Block Size頁大小 * 每塊頁數(shù)如4096*64256KB。OOB大小Spare Size如128字節(jié)或256字節(jié)。總?cè)萘坑嬎憧倝K數(shù)。時序參數(shù)關(guān)鍵的時間參數(shù)如tWC寫周期時間、tRC讀周期時間、tREA讀訪問時間、tR頁讀取時間、tPROG頁編程時間、tBERS塊擦除時間。這些值用于計算NFC的時鐘分頻和等待周期。ECC要求芯片的ECC比特/頁要求是多少例如要求每1KB數(shù)據(jù)提供40比特ECC能力。壞塊標記位置出廠壞塊標記在OOB中的哪個字節(jié)通常是第0個或第1個字節(jié)。修改內(nèi)核設(shè)備樹DTS這是最主要的工作。全志平臺NAND Flash的配置通常在arch/arm/boot/dts/sunxi/目錄下的某個DTSI或DTS文件中。添加Flash節(jié)點在nfc節(jié)點下添加或修改一個nand0子節(jié)點。配置參數(shù)關(guān)鍵屬性包括reg 0; // CS片選 allwinner,rb 0; // Ready/Busy引腳 nand-ecc-mode hw; // 使用硬件ECC nand-ecc-strength 40; // ECC強度根據(jù)Flash要求設(shè)置 nand-ecc-step-size 1024; // ECC步長通常為512或1024 nand-on-flash-bbt; // 使用Flash上的壞塊表 #address-cells 1; #size-cells 1;分區(qū)表在nand0節(jié)點下定義partitions子節(jié)點劃分出boot、env、rootfs等分區(qū)。配置NFC驅(qū)動參數(shù)可能需要修改NAND控制器驅(qū)動源碼通常是drivers/mtd/nand/raw/下的相關(guān)驅(qū)動全志可能有自己的平臺驅(qū)動。重點是確保驅(qū)動能正確識別你的Flash ID并為其分配合適的nand_chip結(jié)構(gòu)和nand_controller_ops操作集。如果Flash的指令集或特殊功能如QPI模式與標準不同可能需要添加新的nand_flash_dev結(jié)構(gòu)體到驅(qū)動列表中。調(diào)整時序配置在驅(qū)動或DTS中可能需要配置NFC的時鐘頻率、采樣相位等以匹配Flash的時序要求。這可能需要查閱T113的用戶手冊中關(guān)于NFC時鐘配置的章節(jié)。6.2 常見適配問題與排查問題系統(tǒng)無法識別NAND Flash啟動時卡住或報錯。排查檢查硬件連接數(shù)據(jù)線、控制線是否接對上拉電阻是否合適用示波器或邏輯分析儀抓取上電后NFC嘗試讀取ID時的波形。看CE#,CLE,ALE,WE#,RE#信號是否正常數(shù)據(jù)線上是否有ID數(shù)據(jù)返回。這是最直接的診斷方法。檢查DTS中nfc節(jié)點的時鐘和引腳復(fù)用pinctrl配置是否正確。確認內(nèi)核配置make menuconfig中已啟用MTD、NAND以及全志平臺的NAND驅(qū)動如CONFIG_MTD_NAND_SUNXI。問題能識別ID但讀寫數(shù)據(jù)出錯ECC糾錯失敗頻繁。排查首要懷疑ECC強度不匹配檢查DTS中nand-ecc-strength和nand-ecc-step-size是否嚴格按照新Flash的數(shù)據(jù)手冊要求設(shè)置。T113的NFC通常支持BCH編碼強度可選。如果Flash要求每1KB 40bit ECC你配置成了24bit那肯定出錯。檢查時序如果時序配置過于激進時鐘太快等待周期太短可能導致數(shù)據(jù)采樣不穩(wěn)定。嘗試降低NFC時鐘頻率或在DTS中增加nand-wr-hold-ns、nand-wr-delay-ns等時序參數(shù)如果驅(qū)動支持。檢查OOB布局內(nèi)核驅(qū)動對OOB的使用有默認布局。如果Flash出廠壞塊標記位置或文件系統(tǒng)要求的ECC存放位置與驅(qū)動默認不符需要修改驅(qū)動的OOB布局定義或使用nand-flash屬性指定。問題寫入速度極慢。排查檢查是否啟用了硬件ECC。軟件ECC會嚴重拖慢速度。檢查驅(qū)動是否支持并啟用了NAND_ECC_MAXIMIZE等優(yōu)化選項。確認Flash本身的速度等級。不同型號的編程時間tPROG差異很大。適配心得永遠不要假設(shè)。一切以數(shù)據(jù)手冊和實際波形為準。準備一個邏輯分析儀是進行NAND Flash調(diào)試的必備工具。先讓最基本的ID讀取和頁讀寫工作起來再逐步使能ECC、壞塊管理等高級功能。每次修改一個變量并做好測試記錄。全志社區(qū)和Linux MTD郵件列表是尋找類似適配案例和尋求幫助的好地方。