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