步驟1:什么是SPI閃存?
我要去痛苦地快速解釋下一部分。我在英特爾的第一份工作是在1993年的閃存組中,自那時起20年來,這項技術(shù)發(fā)生了很大變化,但有些概念仍然保持一致。
閃存是一種非易失性存儲基于MOSFET技術(shù)的存儲器。非易失性意味著器件在未上電時會保留其值。
MOSFET
如果您不熟悉MOSFET晶體管的工作原理,我將嘗試用一句話來解釋:一塊硅片如果兩端之間有電位差,則兩端有兩個端子,則不會導(dǎo)電,但是如果您將另一塊金屬粘貼在該平板的頂部,并將電介質(zhì)夾在中間,然后在該金屬上施加電壓它會產(chǎn)生一個場,電流可以在兩個終端之間流動。端子稱為源極和漏極,金屬稱為柵極。這是一個超簡單的解釋,推論了50年的量子物理學(xué),但從邁克爾·法拉迪(Michael Farady)的角度來看,這是合理可行的。
閃光燈晶體管
閃存通過將一堆電荷載流子噴射到柵極和襯底之間的電介質(zhì)上來進行操作。這稱為編程,通常使用更高的電壓。它實際上損壞了材料,在100k程序循環(huán)后,門將失效。為了去除電介質(zhì)中的電荷載流子,應(yīng)使用同樣高的電壓但反向電位將載流子從柵極拉出。這稱為擦除。
編程的閃存位的值為0,擦除的位的值為1,擦除的閃存字節(jié)為十六進制的0xFF。 (如今,閃存可以使用多個電壓電平在每個單元中存儲多個位,但這確實很復(fù)雜。)
閃存架構(gòu)
通常,閃存存儲器包含一個巨大的晶體管陣列,可以單獨編程,但只能分組(扇區(qū),塊或整個芯片)擦除。這只是擦除電路工作方式的一個副作用:逐位擦除將需要過多的金屬密度,并且并不是全部有用(實際上,擦除較大的塊就可以了)。
由于對單個晶體管進行編程會由于升高高電壓以及隨之而來的所有控制而變慢,因此通常在頁面中對閃存進行編程。通常,閃存設(shè)備將具有小的SRAM頁面緩沖區(qū)(256位),主機將首先快速填充數(shù)據(jù),然后主機發(fā)出頁面寫入命令,并且閃存芯片在大批量作業(yè)中寫入所有頁面字節(jié)。該批處理電路在較大數(shù)量的位上分配啟動寫入延遲。提供兩個或多個頁面緩沖區(qū)使主機可以使用雙緩沖區(qū)技術(shù)來隱藏閃存設(shè)備的寫入延遲。
SPI
串行外圍接口是一項了不起的發(fā)明。它是一個簡單的串行接口,使用片選,時鐘,數(shù)據(jù)IN和數(shù)據(jù)OUT。 SPI設(shè)備有很多種,因為它是一個非常流行的接口,并且所有SPI設(shè)備都使用一個公共庫:一旦您知道如何與一個SPI設(shè)備通信,就可以與任何SPI設(shè)備通信。
SPI的優(yōu)勢在于它的軟件簡單性,代碼基本上在時鐘的上升沿分別將數(shù)據(jù)移入和移出DI和DO引腳。時鐘由主機控制,它不需要花哨的時鐘電路:只要您遵守設(shè)備的最小周期寬度要求,相位就可以像您想要的那樣不對稱。
FLASH SPI
閃存SPI內(nèi)存簡單地結(jié)合了兩者的優(yōu)點。請注意,SD卡使用SPI以及此分立芯片。驚喜!編程界面沒有太大區(qū)別,但是實際的指令和時間有所不同。
步驟2:WinBond設(shè)備界面
上面顯示的引腳排列取自WinBond數(shù)據(jù)表。
引腳1:片選(/CS,有時稱為/SS,用于“串行選擇”)
CS是“片選”引腳。當(dāng)您想要與該設(shè)備通信時設(shè)置CS引腳,因為您可能有十幾個SPI設(shè)備共享同一總線,并且您通過其CS引腳唯一地識別每個設(shè)備。 CS前面的斜線表示“低電平有效”:與該器件通信,將該引腳拉至邏輯電平零;將其從共享總線中移除,驅(qū)動邏輯1級。
引腳2:數(shù)據(jù)輸出(DO)
從該引腳讀取串行數(shù)據(jù)。它將連接到總線的MISO(主輸入/從輸出)線。通常,您以預(yù)定的順序向SPI設(shè)備寫入命令。在該序列完成后,根據(jù)序列中的指令,然后從DO引腳讀取數(shù)據(jù)。
引腳3:寫保護(/WP)
此引腳禁用寫入。有時您會看到連接到此引腳的跳線,以便對編程/擦除機制提供非常嚴(yán)格的控制:如果設(shè)置為低電平,則無法對器件進行編程或擦除。我通常將它硬連接到Vdd并允許我的軟件通過串行命令控制寫入啟用/禁用(稍后我們將討論)。
編輯(2016-12-16)感謝用戶velsoft捕獲一個錯字:我把極性混淆了。
引腳4:接地
這只是接地引腳。
引腳5:數(shù)據(jù)輸入(DI)
這是輸入串行引腳。它將連接到總線的MOSI(主輸出/從輸入)線。主機系統(tǒng)將命令和數(shù)據(jù)寫入該引腳。
引腳6:時鐘(CLK)
時鐘引腳決定數(shù)據(jù)位的傳輸方式在DI和DO引腳上。 DI/DO引腳在時鐘引腳的上升沿上采樣。
引腳7:保持(/HD)
我從沒用過pin,但它允許主機設(shè)備暫停正在進行的任何事務(wù)。您可能永遠不需要使用該引腳,因此我將其連接到VCC(低電平有效)。
引腳8:VCC
源電壓。
步驟3:如何讀取時序圖
現(xiàn)在我已經(jīng)解釋了flash,SPI,以及SPI閃存器件的具體實現(xiàn),接下來需要了解的是通信時序圖*。時序圖解釋了引腳上數(shù)據(jù)的排序,以向器件發(fā)出指令。每個SPI設(shè)備都響應(yīng)其自己的指令集(例如,閃存設(shè)備將具有讀或擦除指令),時序圖是該指令的概念行為與執(zhí)行該指令的實際硬件協(xié)議之間的鏈接。 p》
在本節(jié)的圖表中,我復(fù)制了數(shù)據(jù)手冊中的芯片擦除時序圖,因為這是最容易理解的。
底部軸是時間,垂直軸代表四個SPI引腳,隨著時間的推移,序列數(shù)據(jù)應(yīng)出現(xiàn)在它們上以執(zhí)行指令。注意:“高阻抗”意味著您可以忽略該信號(它被驅(qū)動為非0或1,但是電阻極高,因此實際上是開路)。兩條線出現(xiàn)的情況(如DI),簡單表示某種轉(zhuǎn)變正在發(fā)生但未知;單行表示存在特定的高值或低值。
讓我們從左到右,從上到下查看圖表。
為了與任何SPI設(shè)備通信,必須將芯片選擇置于高電平然后驅(qū)動為低電平(記住/CS表示低電平有效)。當(dāng)/CS變?yōu)榈碗娖綍r,請注意,圖中的時鐘已非常明確地繪制為顯示八個階段。這意味著您必須將時鐘脈沖八次,每位一次。在時鐘頻閃時,數(shù)據(jù)從高到低變?yōu)楦?。我認為DI圖是錯誤的,因為如果你在每個時鐘的上升沿畫一條垂直線并計算這些點的DI的二進制值,你應(yīng)該得到值11000111或0xC7。這是告訴芯片擦除自身的指令。一旦將芯片選擇拉高,內(nèi)部電路將開始執(zhí)行0xC7/芯片擦除功能。該指令大約需要1到2秒的時間。
請記住,您實際上不需要將時鐘引腳切換8次以發(fā)送8位字節(jié),SPI庫會執(zhí)行此操作當(dāng)你使用函數(shù)SPI.transfer()時為你。您仍然需要使用digitalWrite()手動驅(qū)動/CS,但SCK,MOSI和MISO都由SPI函數(shù)處理。
您將在源代碼中注意到一個名為“not_busy()”的函數(shù)。該功能不斷發(fā)出“讀控制寄存器#1”并檢查位0,指示內(nèi)部操作是否已完成,閃存不忙。此操作的時序與數(shù)據(jù)表的圖9.2.8相符。
*注意我并不是指電氣時序圖,它向納秒級解釋了內(nèi)部數(shù)字邏輯的建立和保持時間;我所指的圖是忽略納秒并描述邏輯事件序列的邏輯圖。 SPI接口的實際電氣時序由Arduino SPI庫處理。老實說,該代碼不是很復(fù)雜,如果您要針對一種特定的設(shè)備進行設(shè)計,則可以進一步簡化該代碼。
步驟4:使用Level-Shifters與Arduino Uno接口
Arduino Uno的數(shù)字輸出分別以邏輯低電平和高電平傳輸0V和5V。 WinBond閃存芯片僅在2.7V至3.6V之間工作。每當(dāng)不同電壓平面上的邏輯電路需要通信時,我們都必須使用電平轉(zhuǎn)換器。
電平轉(zhuǎn)換器最簡單的形式是一個簡單的齊納二極管鉗位。世界上還有許多其他類型的電平移位器,有些更快,有些用功率更少,齊納鉗方法快速簡便。
所有二極管都具有反向擊穿電壓,此時它們開始進行。齊納二極管專門設(shè)計用于在精細調(diào)諧的電壓下?lián)舸>臀叶?,我?.3V齊納二極管與每個芯片的數(shù)字輸入并聯(lián)(參見原理圖)。 (至于其他四個引腳,地是0V,Uno板為VCC提供3.3V電源,所以這些引腳不需要二極管,我硬連線/WP和/HOLD到3.3V Vcc。) 》更新:我忘了將330歐姆電阻與Uno驅(qū)動器的輸出串聯(lián)。通常,如果您將Uno的數(shù)字輸出連接到另一臺設(shè)備的數(shù)字輸入,則只需一條簡單的電線就可以了(因為您將一個數(shù)字邏輯信號連接到另一個,請參見ATmega328數(shù)據(jù)手冊的第13.1節(jié)“等效于I/O引腳”原理圖“)。但是由于輸出路徑現(xiàn)在通過齊納二極管分支,因此您需要一個電阻來限制由Uno/ATmega芯片的邏輯輸出驅(qū)動的最大電流。如果沒有電阻,這條接地路徑可能會超過器件的最大輸出電流。雷,那會不好。
現(xiàn)在,每當(dāng)Uno將5V邏輯高電平驅(qū)動到/CS引腳時,齊納二極管就會切換到擊穿模式,從而將電壓鉗位到3.3V,因此保護這些閃存芯片的輸入邏輯。
使用這些夾具,我將Arduino Uno的數(shù)字輸出引腳10(SS)連接到/CS,引腳11(MOSI)連接到DI,引腳12(MISO)連接到/CS。 DO和引腳13(SCK)到CLK。 (請注意,Atmega328的引腳與Uno的引腳不同,例如,Atmega引腳#19是Uno引腳#13。)SPI軟件庫假定引腳10 = SS,等等。
第5步:代碼代碼代碼!
我寫了一個草圖,允許我通過串行監(jiān)視器(或什至通過串行TTY通信)與Uno通信。一個Unix提示符,你可以看到)。這是一種調(diào)試新硬件的有用方法,因為我可以交互式發(fā)出命令。
“serialEvent()”函數(shù)是一個內(nèi)置的回調(diào)函數(shù),只要在默認的Serial對象上發(fā)生某些事情就會調(diào)用它。我使用此回調(diào)來構(gòu)造命令字符串并設(shè)置一個布爾標(biāo)志(當(dāng)回調(diào)從流中讀為分號“;”時,字符串的逐字節(jié)構(gòu)造完成;我使用它代替換行符,因為沒有辦法從串行監(jiān)視器發(fā)出換行符)。當(dāng)回調(diào)構(gòu)造字符串并設(shè)置標(biāo)志時,“l(fā)oop()”函數(shù)執(zhí)行解碼器。解碼器根據(jù)命令字符串確定調(diào)用哪個函數(shù),并解析命令字符串中的任何其他參數(shù),并調(diào)用該函數(shù)。
每個函數(shù)本質(zhì)上是WinBond的低級實現(xiàn)的包裝器SPI功能時序圖。我使用了一個包裝器,以便低級函數(shù)保持通用:我可以在其他草圖中使用簡單的剪切和粘貼再次使用它們。此外,包裝器會向用戶輸出一些反饋,這對于調(diào)試非常有用。
上面的屏幕截圖顯示了與串行監(jiān)視器的交互式會話。我發(fā)出了四個命令,“get_jedec_id;”,“read_page 0;”,“write_byte 0 2 8;”和“read_page 0;”你實際上沒有看到命令(串行監(jiān)視器沒有回聲,我沒有打印確切的命令。.我可能應(yīng)該有),但你確實看到了響應(yīng)。當(dāng)我讀/寫/讀第0頁時應(yīng)該最清楚。“read_page;”命令只是轉(zhuǎn)儲指定的頁面(十進制)。 “write_byte;”函數(shù)有點奇怪,因為參數(shù)指定頁碼,該頁的偏移量和字節(jié)。由于16位Atmega中沒有本機32位寄存器,因此我不打算進行邏輯到物理轉(zhuǎn)換,但您需要在某些時候考慮這種轉(zhuǎn)換。無論如何,請注意頁面零的第三個字節(jié)現(xiàn)在是“08h”。
我本可以發(fā)出“chip_erase;”然后“read_page 0;”為了說明擦除周期,但希望你得到圖片。
低級函數(shù)以“_”開頭,并命名為“_read_page”或“_write_page”或“_erase_chip”。這些函數(shù)明確地排序了數(shù)據(jù)表時序圖中的SPI命令。每個函數(shù)都以調(diào)用“not_busy()”結(jié)束,以防止執(zhí)行在芯片完成內(nèi)部操作之前繼續(xù)執(zhí)行。
編輯(2014年3月11日):_read_page低級函數(shù)出現(xiàn)問題,我忘了在功能開始時將CS拉高,然后將其拉高,就像其他功能一樣。這意味著如果_read_page是您調(diào)用的第一個函數(shù),則CS可能尚未為高,因此如果沒有有效的/CS 1-》 0轉(zhuǎn)換,_read_page將無法正常運行,第一次調(diào)用它。第二次可以正常工作,因為它將/CS保留為1。小但煩人的錯誤。
步驟6:使用TTY下載數(shù)據(jù)
此Instructable的真正原因是演示如何將整個閃存下載到單個文件中。為此,我使用了Unix函數(shù)“ tail -f”和重定向。
Unix函數(shù)“ tail”將打印文本文件的最后10行。當(dāng)給定參數(shù)“-f”時,“tail”將保持連接到重定向,直到它捕獲SIGINT(例如,Ctrl-C)。
此屏幕截圖中打開了三個窗口:Arduino IDE左側(cè)是串行監(jiān)視器,在右上方,而OSX POSIX終端在右下方。在OSX/POSIX平臺上,Uno的USB控制器顯示為/dev/tty設(shè)備,在這種情況下為“/dev/tty.usbmodem1411”。我將“tail -f”連接到此設(shè)備并將輸出重定向到文件。
然后我發(fā)出了“read_page 0;”在串口監(jiān)視器中命令,并且輸出通過“尾”發(fā)送,因為它連接到TTY的輸出,然后發(fā)送到文件。然后我用“ cat”文件來證明已捕獲了串行流。
現(xiàn)在,我要轉(zhuǎn)儲整個IREIRE閃存芯片所需要做的就是在終端提示符下鍵入以下內(nèi)容:
%tail -f/dev/tty.usbmodem1411》 1MB_of_flash.txt
然后在“串行監(jiān)視器”窗口中鍵入以下內(nèi)容:
read_all_pages;
然后鍵入CTRL -C在終端窗口中停止“尾部”過程。
完成并完成!這就是為什么Unix比任何其他操作系統(tǒng)都要優(yōu)越得多,恕我直言。
第7步:結(jié)論
這是期待已久的數(shù)據(jù)記錄器Instructables的續(xù)集。我已經(jīng)答應(yīng)了一種即將采用的方法將數(shù)據(jù)從閃存芯片中拉出來,就在這里。
我希望你發(fā)現(xiàn)這個Instructable非常有用:我所知道的99%是通過閱讀這樣的東西來學(xué)習(xí)的。其他人花時間寫的網(wǎng),我非常感謝他們的努力。
責(zé)任編輯:wv
-
閃存
+關(guān)注
關(guān)注
16文章
1789瀏覽量
114950
發(fā)布評論請先 登錄
相關(guān)推薦
評論