隨著科技的演進,在單晶片微控制器及 SoC 的領域中,SPI 及 I2C 這二種串列 (序列) 介面變得十分常見。這二者與主機間通訊用的非同步串列通訊埠 RS-232 (UART) 非常不一樣。
- 二個都是同步傳輸介面,主要是用於 CPU 和週邊晶片之間。
- SPI 及 I2C 二者設計的主要目的在於減少 CPU 和週邊晶片之間的接腳數。
- SPI 一般需要 4 條接線 (至少三條),而 I2C 則只要二條線,這和早期常用的並列匯流排動輒十數條接線有著明顯的差異。
- SPI 的硬體結構簡單而且傳輸速度快,一般是 5M/10M/20Mbps 或是更快 (可以到 200Mbps),I2C 的傳輸速度則只有 100Kbps/400Kbps/1Mbps(/3.4Mbps/單向 5Mbps)。
- SPI 是全雙工,I2C 則是半雙工.
- SPI 使用硬體線路來指定 slave 晶片,I2C 則在傳送的第一個位元組上指定 (7bit位址)。
- SPI 不提供交握機制,無法確認 slave 晶片是否有跟上。I2C 則有雙向的確認機制。
SPI 簡介
SPI 是 Serial Peripheral Interface 的縮寫,中文意思是串列週邊介面,該介面是由 Motorola 公司設計發展的高速同步串列介面,原先是應用在其 68xx 系列的 8 位元處理器上 (1985 年首次出現在 M68HC11 處理器上,並提供了完整之說明文件),用以連接 ADC、DAC、EEPROM、通訊傳輸 IC...等週邊晶片。由於具備有低接腳數,結構單純,傳輸速度快,簡單易用...等特性,目前已經成為業界慣用標準。不只是單晶片微控制器上有,許多新的 SoC 晶片直接就支援多組 SPI 介面,甚至普及到連模組化的產品 (如:手機用的 LCD 模組 (SDI 介面),相機模組) 及 3C 產品 (如: 數位相機用的記憶卡) 也都是使用 SPI 介面。
SPI 架構及介面接腳
SPI 為一主從式架構,通常有一個 Master (主設備) 和一個 (或多個) Slave (從設備)。介接方法及內部硬體結構很簡單, 如下面的示意圖:
SPI 接腳名稱及意義
接腳名稱 | 中文名稱 | 說明 |
---|---|---|
MOSI | 主出從入 | master 數據輸出、slave 數據輸入。 |
MISO | 主入從出 | master 數據輸入、slave 數據輸出入。 |
SCLK | 時脈訊號 | 時脈信號、由 master 產生並控制。 |
/SS | 晶片致能 | slave 選擇信號,由 master 控制。slave 只有在 /SS 信號為低電位時,才會對 master 的操作指令有反應。 |
介接時只要把相同名稱接腳接在一起即可。
- SPI 的接腳有另一套常用的名稱:
- SDO:Serial Data Out, 資料輸出 (不分主從)
- SDI:Serial Data In, 資料輸入 (不分主從)
- SCK:對應 SCLK
- /CS:對應 /SS
由於這種標示方法不分主從,資料輸出都是 SDO,資料輸入都是 SDI,所以介接時必需把二個設備的 SDO 和 SDI 接腳對接:master 的 SDO 接到 slave 的 SDI,master 的 SDI 接到 slave 的 SDO。
在實際應用上,如果不需要由 slave 讀回資料時 (如:Output Port Expander,或者 DAC 晶片),則 MISO 接腳可以省略。有看到一部份資料說:只有一主一從時,/SS 訊號可以省略,只要將 slave 的 /SS 直接接地即可。對某些 slave 晶片來說這是不對的,因為有些 slave 晶片會拿 /SS 訊號的下降緣來識別 master 送來的第一個 bit。這是非常重要的錯誤回復機制,遇到這類 slave 晶片只把 /SS 接腳直接接地是不會動作的。另外後述的 Daisy-Chain 接法也需要這個 /SS 訊號的上昇緣才能運作。Daisy-Chain 模式用它 (/SS 訊號的上昇緣) 來栓鎖指令,如此多個 slave 晶片才能同時載入不同的指令。
由上面的結構示意圖,我們很清楚的看出它其實是利用二組頭尾相連的位移暫存器 (Shift Rigister) 來完成 master 和 slave 之間的資料交換,而且是接收與發送同時進行 (全雙工)。而 SCLK 就是用來控制二者同步位移的時脈信號,它是由 master 產生送出給雙方的位移暫存器。這樣子的結構允許資料一位元一位元的傳送,可快可慢,甚至允許暫停 (可以暫停在任意點上,完全沒有限制),因為 SCLK 沒有變動時,雙方的 shift register 是不會有動作的。所以如果你的微控制器沒有硬體式的 SPI 可以用,直接用軟體加一般的 GPIO 接腳,就可以模擬 SPI master。(用軟體模擬 SPI slave 則不建議,因為如果我們不知道對方會送多快的 SCLK)。
在介接方面,除了簡單的一主一從架構之外,SPI 也可以一個 master 連接多個 slave。接法上有二種,一種是利用多條獨立的 /SS 訊號,另一種則利用 Daisy-Chain 的方式。
使用 Daisy-Chain 的方法,不需要額外的硬體接線腳來擴充 /SS 訊號,但是傳送及接收程式需要大改,非常的麻煩。另外還有一個障礙是,slave 晶片必需在同一個模式下工作,還有也不能有接腳缺省的情形 (有許多 DAC 晶片沒有 MISO 接腳),也因此常見的應用 Daisy-Chain 的例子都是用來串連多個同一型號的晶片,例如: 需要多組 DAC 或者是 ADC 一起工作的情況。另外要注意的是:並非每一顆 SPI 晶片都可以支援 Daisy-Chain 的接法,必需詳細檢視晶片的使用手冊是否有支援 Daisy-Chain 介接方法,或者是檢視讀取的指令格式是否符合 Daisy-Chain 的需求。否則到時候硬體接線接好了,Master 卻怎樣也無法命令 slave 晶片正常的工作。
Daisy-Chain 的運作方法是以倍數擴充每次傳輸的指令/資料長度 (有二個 slave 晶片串在一起,傳輸長度就 x2;三個 slave 晶片串在一起,傳輸長度就 x3)。由於上一顆 slave 晶片的 MISO 是連接到下一顆 slave 晶片 MOSI,所以多出來的傳輸訊號很自然把先前的訊號擠出來,送到下一顆晶片。等到所有訊號都送出去了,再來就是利用 /SS 訊號的上昇緣來通知每一顆 slave 晶片:要給你的指令/資料已經準備好了,請把它栓鎖 (latch) 起來了。同樣的讀回資料也會串在一起。所以原本的驅動程式必需把要給各個 slave 晶片的指令暫存起來然後依 slave 晶片串連的次序將指令串起來再送出,收回來的資料也必需先裁切好再依 slave 晶片串連的次序分配給對應的接收單元。
是故比較常用的是多條獨立的 /SS 訊號。有的 master 晶片是直接提供額外的 /SS1,/SS2,/SS3... 等接腳。有的則需要利用原本的 /SS 再以一組 3 to 8 解碼器 (或者是 4 to 16 解碼器) 配合 3~4 條 GPIO 接腳來產生需要的多組 /SS。更有的 SoC 乾脆提供多組 SPI 單元及多條獨立的 /SS 訊號 (當然的,代價是 master 晶片的接腳數比較多,單價拉高)。
SPI 工作模式及時序圖
使用 SPI,最麻煩一件事是確認周邊晶片的工作模式。SPI 一共有 4 種工作模式,但這 4 種模式的時序圖差異非常小,常令初學者 '霧剎剎' 抓不到重點。如下圖:
上圖的上半部是 SCLK 的時序,有兩種選擇: CPOL=0 或者 CPOL=1。中間及下半部是 MOSI MISO 的時序,一樣是有兩種選擇:中間是 MOSI MISO 是在 SCLK 的奇數次變化栓鎖資料,下半部則是 MOSI MISO 是在 SCLK 的偶數次變化栓鎖資料。
- 解說:
- SPI slave 晶片一般只支援一種工作模式,所以通常 master 必需牽就 slave 把工作模式設成和 slave 一致,才能正常運作。(因為二者內部均是位移暫存器,所以 MOSI 和 MISO 的時序需求是一樣)
- 首先,第一個不同是 SCLK 的極性 (polarity),所謂極性其實是指 SPI 不工作時,SCLK 是停留在高電位還是低電位。CPOL=0 是 SCLK 在不工作時停留在低電位,CPOL=1 則是停留在高電位。
- 再來要注意 slave 晶片是在 SCLK 的下降緣栓鎖資料,還是在 SCLK 的上升緣。要讓對方栓鎖資料,我們就必需把資料 Hold 住,保持穩定,所以 Slave 晶片在 SCLK 的下降緣栓鎖資料,相對的 master 就必需要在上升緣送出資料。反之,slave 晶片在 SCLK 的上升緣栓鎖資料,相對的 master 就必需要在下降緣送出資料。
- 但是 CPHA 的定義並不是依上升緣/下降緣。CPHA 設定的是晶片栓鎖資料的時機是在 /SS 訊號下降之後,SCLK 的奇數次變化 (CPHA=0),還是偶數次變化 (CPHA=1)。
- 所以 CPHA 配合 CPOL (SCLK 的極性) 設定,組合起來一共有 4 種工作模式。不過模式的命名順序出現了分歧沒有統一,現有的晶片出現了二種順序 (參閱 Wiki 網站 Serial Peripheral Interface Bus)。所以撰寫程式時不要只是把 Mode 設成相同的數值,小心 master 晶片和 slave 晶片二者的模式順序不同。不過仔細對照一下,差異只有 mode 的數值不同而已,CPOL 及 CPHA 的定義並無不同。
SPI Mode
Mode # of
Model AMode # of
Model BCPOL CPHA 資料栓鎖時機 MISO MOSI
時序圖1 0 CPOL=0 CPHA=0 奇數次 上升緣 上半組 0 1 CPOL=0 CPHA=1 偶數次 下升緣 下半組 3 2 CPOL=1 CPHA=0 奇數次 下升緣 上半組 2 3 CPOL=1 CPHA=1 偶數次 上升緣 下半組 Model A:For ARM-based and Microchip PIC
Model B:其他 - 一旦正確辨識出 slave 晶片的工作模式,只要把 master 設定成一樣的工作模式即可正確的傳送指令及接收資料。
結語:
- 總結一下辨識的技巧:
- 先確認 slave 晶片需求的 SCLK 極性,不工作時是在低電位還是高電位, 由此確認 CPOL 為 0 或 1。
- 再由 slave 晶片 datasheet 中的時序圖確認 slave 晶片是在 SCLK 的下降緣栓鎖資料,還是在 SCLK 的上升緣。
- 直接比對上面的模式表,確認出 CPHA 值為 0 或 1。
- 確認傳輸時序圖是否正確 (是奇數組 SCLK 變化,還是偶數組 SCLK 變化)。
補充說明一點,從 /SS 的下降緣到第一個 SCLK latch edge 有一小段時間的 delay,這一小段 delay 必需滿足 slave device 的規格需求,尤其是 SCLK 的頻率偏高的時候。否取 slave device 會無法正常工作。有些 MCU 的 SPI 硬體模組把這一段設成固定的 CLK 數; 有些 MCU 的 SPI 硬體模組則可以讓使用者自行調整。(2018/06/14)
還有一點在圖中有標示,但上文沒有提到的是: SPI 的資料是 msb (Most Significant Bit)bit7 (MSB) 先傳 (傳輸的資料格式是 8 Bits 就 bit7 先傳,是 16 Bits 就 bit15 先傳,是 24 Bits 就 bit23 先傳),如果你是用軟體來模擬 SPI master 需注意到這一點。話雖如此,有些許 MCU 的 SPI port 是允許你把它改為 lsb (Least Significant Bit) 先傳,這是為了要能應付一些沒有依照標準設計的晶片,並不是標準狀況,也請小心。
另外 SPI 只是硬體的傳輸協定,完全沒有提及定址(選擇晶片/暫存器位址),指令,資料長度...等等,這一部份是完全由 salve 晶片制定,master 想要控制 slave 動作必需完全依據 slave 晶片 datasheet 上的規範。
下二張圖是 SPI Daisy-Chain 部份的接線圖及其時序圖。其中 SPI Master (MCU) 串接了二顆 Slave 晶片,Slave 晶片的指令/資料格式為 16 bits。接線圖上我們標示了 ➀ ➁ 二個點,就是後面時序圖的量測點。時序圖中的 (DOUTM)DINS1 是 SPI Master (MCU) 的 MOSI 及 Slave1 的 MOSI (DIN) 輸入接腳連線上的時序 (接線圖上點 ➀ 所量測到的訊號),(DOUTS1)DINS2 是 Slave1 的 MISO (DOUT) 輸出接腳和 Slave2 的 MOSI (DIN) 輸入接腳連線上的時序 (接線圖上點 ➁ 所量測到的訊號)。
如前面說的 Slave 晶片的指令/資料格式為 16 bits,所以時序圖上的 Byte1 及 Byte2 二個合起來才是一組 16 bits 的 SPI 指令/資料。Byte3 及 Byte4 則是另一組。由於 SPI 的電路結構使用的是串列位移暫存器,所以我們其實可以把 Slave1 和 Slave2 合起來看,變成一個長度為 32 bits 的串列位移暫存器 (點 ➀ 的時序圖)。由 Slave1 的觀點來看: 前 16 bits 資料 ( Byte1 及 Byte2) 當然是先把自己的串列位移暫存器填滿,可是 Master 又接著送 Byte3 及 Byte4 進來,所以先前的 Byte1 及 Byte2 就又都被擠出去給 Slave2 了。由 Slave2 的觀點來看: 狀況看 Slave1 是一樣的,只不過前 16 bits 是原先 Slave1 肚子裡的垃圾,後 16 bits 才是由 Master 送來的 Byte1 及 Byte2。
所以 Master 送完 4 bytes 資料時,Slave1 收到了後二個 bytes,Slave2 收到了前二個 bytes。接著 /SS 接腳訊號向上拉,Slave1 和 Slave2 一起把資料栓鎖,開始解碼及相關動作。
- 總結 SPI Daisy-Chain 的注意事項有三:
- 傳輸時,給遠端晶片 (離 MCU 的 MOSI 接腳比較遠的,即 Slave2) 的資料要先送 (Byte1 及 Byte2),再接著送給近端 (Slave1) 的資料 (Byte3 及 Byte4)。
- 每一次傳輸都必需是完整的 N 組晶片所需的指令/資料 (N 為 Chain 裡的 slave 晶片數,圖示為 N=2),否則遠端晶片會收到別人的資料 (上一次傳輸所送出的資料),產生不正確的動作。
- 還有一個狀況是除非晶片有支援 NOP (no operation) 的指令,否則無法只針對 chain 裡其中一顆晶片下達指令/資料 (原因如上一項所述)。例如:74HC595 就沒有 NOP 指令;但是 MAX 7219/7221 就有 NOP 指令可用。