簡單快速的匯流排協議——SPI
這是IC君的第24篇原創文章 (同步於微信公眾號 icstudy )
連續幾日大雪,IC君可以在家好好寫文章了。但是想想項目分配的活還是要準時高質量的完成,真是頭大啊。
之前有一篇文章介紹了簡單優雅的匯流排協議——I2C,這篇文章來聊一聊SPI協議。標準SPI協議比I2C協議就多了2根線,但它的協議生涯就起了翻天覆地的變化。
在網上搜了一下SPI的協議,基本上都是這樣寫的
SPI是串列外設介面(Serial Peripheral Interface)的縮寫。是 Motorola 公司推出的一 種同步串列介面技術,是一種高速的,全雙工,同步的通信匯流排。
高速和同步可以理解,全雙工是什麼鬼?
全雙工是指host(主設備)與外圍從設備之間的發送線和接受線各自獨立,發送數據的同時也能夠接收數據,兩者同步進行。
SPI協議主要用於短距離的通信系統中,特別是嵌入式系統,比如以下晶元:
存儲器:RAM,EEPROM,Flash等
數模轉換:A/D,D/A轉換器等
驅動介面:LED顯示驅動器、I/O介面晶元、UART收發器等。
2017年哪類晶元最缺貨啊?存儲器相關的啊!好吧,就選它了:SPI Flash。SPI Flash的本質就是使用SPI的協議去對Flash 存儲器進行各種讀寫操作。結合Flash有助於我們更好的理解SPI協議。
首先我們從國內最大的SPI NOR Flash公司兆易創新網站上下載一份datasheet(公司看到可以給我打廣告費了):
http://www.gigadevice.com/product/download/368.html?locale=en_US
datasheet對應的是一顆存儲容量為512M-bit SPI NOR Flash。
從datasheet第4頁的特徵介紹可以看出這顆產品支持標準單埠(1IO)、Dual SPI(2IO)、Quad SPI(4IO)模式的SPI協議。
從datasheet第5頁的封裝方式可以看到,晶元包含以下輸入輸出埠:SCLK, CS#, SI, SO, WP#, HOLD#
從datasheet第6頁的封裝方式可以看到對輸入輸出pin功能的描述:
其中CS#是一個晶元選擇信號,#表示這個pin輸入low的時候才會選中當前晶元,其它pin的輸入才可能有效;如果為high,則不選中該晶元,其它pin的輸入是完全無效的。
SCLK是一個輸入時鐘,是由外部的主器件輸入的;
SI是輸入信號,也是有外部的主器件輸入的;
SO是輸出信號,是由從器件輸出到主器件的;
通常標準SPI協議(1IO)只包含上面4個信號。對於這顆晶元中的Dual SPI (2IO)/Quad SPI(4IO) 模式還會用到另外2個pin:WP#和HOLD#。這裡我們可以簡單的認為WP#和HOLD#就是跟SI/SO地位平等的2個信號。
接著我們來看看這幾個輸入輸出信號之間的時序關係,如下圖所示:
晶元選擇信號CS#和時鐘信號SCLK有相對關係,用來確定輸入SCLK有效和無效。
tSLCH :定義了CS# go low 到第一個CLK go high的時間,只有主器件給的時間大於這個時間,輸入的CLK信號才算有效。這個參數在datasheet上要求最小是5n。如果主器件給的時間小於5n,則輸入的第一個CLK有可能無效,整個傳輸過程就有可能發生錯誤。
tDVCH和tSLCH:定義了輸入數據SI和輸入時鐘CLK之間的setup/hold 時間,這個跟我們數字電路裡面的DFF觸發器的setup/hold概念是相同的。這2個參數在datasheet上定義的最小值分別是2n/2n。
SPI協議的整個工作過程如下:
當CS# go low之後,輸入到從器件的CLK開始有效,全雙工的傳輸過程開始。主器件在信號線SI上輸入數據並被從器件讀取,從器件輸出數據到SO信號線並被主器件讀取。當CS# go high之後,從器件不再被選中,結束整個傳輸過程。
在傳輸的時候,不管是輸入輸出,通常都是以一個byte的最高有效位(MSB)開始傳輸:
比如主器件輸入bit7->6->5->4->3->2->1>0,從器件接受每個bit之後再向右shift,最終一個byte傳完之後,從器件看到的順序是bit[0:7]。從器件的輸出方式類似。
在datasheet的第9頁有這樣一句話:
SPI匯流排支持mode 0和3。這裡的mode 0和3是指時鐘模式,SPI協議通常有4種模式,可以通過CPOL(時鐘極性 Clock Polarity)和CPHA(時鐘相位 Clock Phase)來定義:
Mode0:CPOL=0,CPHA=0
Mode1:CPOL=0,CPHA=1
Mode2:CPOL=1,CPHA=0
Mode3:CPOL=1,CPHA=1
CPOL表示SPI匯流排空閑的時候時鐘的default狀態,對於SPI NOR Flash而言就是CS# go high之後 SCLK的值。
如果是Mode0, SCLK 為0;
如果是Mode3 ,SCLK 為1;
CPHA表示用第幾個邊沿去採樣數據,0表示第一個,1表示第二個:
對於Mode0而言,SCLK go high的時候去採樣數據,就像一個正沿的dffp;
對於Mode3 而言,因為SCLK初始值為1,而採樣沿為第二個,所以SCLK必須有1->0, 0->1的過程,同樣也是在SCLK上升沿採樣輸入的數據;
對於Mode1和Mode2,大家可以自行推斷匯流排空閑時CLK的初始值和採樣數據的時鐘沿。
不得不說SPI Flash的協議支持時鐘的模式是精心挑選的,都是CLK的上升沿採樣數據,沒有坑設計人員。如果所有的時鐘模式都支持,設計和驗證的工作量可能會大大增加。有時候datasheet上面的隨便一句話,對於我們設計人員可能要付出很大的面積和大量的驗證時間的代價,更悲劇的是這個功能95%的時間都用不到。
既然上升沿用來採樣輸出數據,那輸出數據只能是下降沿了:
對於SPI Flash而言,有一個參數tCLQV 用來定義在一定的負載電容下 Clock Low 到 Output Valid 的時間,實際應用中你必須大於這個時間來採樣數據。如果系統的時鐘頻率(Host 和SPI Flash都是用的這個頻率)比較慢,那你在下一個clk的上升沿就可以採集上一筆數據;如果系統的時鐘頻率比較快(百Mhz量級),只能在下一個時鐘的下降沿去採集數據。
一般SPI的協議比較快的時鐘頻率可能能到幾百Mhz,再快的IC君沒見過。相對於I2C的幾Mhz速度快了很多,速度越快要求驅動負載loading越輕。
這顆SPI Flash的時鐘最快頻率是104MHz,在最差的工藝角下模擬結果也要達到這個頻率。
舉一個讀的例子來解釋SPI協議在Flash中的應用,CS# go low, 利用SPI的協議輸入8 bit的讀command code 03H,再輸入想讀的地址(門牌號),Flash開始輸出內容(房間裡面有什麼東西),輸出一段時間後,主器件不再需要數據了, CS# go high 退出這個command。
SPI協議可以操作在主器件對單個或者多個從器件的條件下:
這個時候晶元選擇信號有多個,但同一個時間只能有一個SS# (CS#)有效,選中一個從器件,從器件的輸出信號MISO(SO)埠都是三態驅動的:
輸出高電平 "1";
輸出低電平 "0";
如果SS# (CS# 為high,不選中該從器件 )則輸出高阻態;
被選中的從器件驅動MISO埠輸出到主器件的時候,其它從器件的輸出都是高阻態。
下面是一種CMOS三態驅動門的電路:
可以看到,EN=0的時候輸出沒有驅動能力,處於高阻狀態。
最後總結一下,SPI協議的優缺點:
優點
- 協議簡單利於硬體設計與實現,比如不需要像I2C協議中每個從器件都需要一個地址;只用到4根線,封裝也很容易做
- 全雙工的協議,既能發送數據也能接受數據
- 三態輸出的驅動能力強,相對I2C的開漏輸出,抗干擾能力強,傳輸穩定;
- 相對於I2C協議,時鐘速度快,沒有最大限制
- 輸入輸出的bit數也沒什麼限制,不局限於一個byte
缺點
- 信號線4根,比I2C多,晶元選擇線會隨著從器件的個數的增加而增加
- 傳輸的過程沒有確認信號,擼起柚子加油傳,不管從器件收不收到;在SPI Flash中會有read status 這個命令確認從器件的狀態,是否處於busy狀態
- 沒有校驗機制,I2C也沒有,難兄難弟啊
推薦閱讀: