1、協議介紹
??SPI,是英語 Serial Peripheral interface 的縮寫,顧名思義就是串行外圍設備接口。是 Motorola 首先在其 MC68HCXX 系列處理器上定義的。
??SPI,是一種高速的,全雙工,同步的通信總線。主節點或子節點的數據在時鐘上升沿或下降沿同步。主節點和子節點可以同時傳輸數據。SPI 接口可以是 3 線或 4 線。本文重點介紹流行的 4 線 SPI 接口
??串行外設接口 (SPI) 是微控制器與外設 IC(如傳感器、ADC、DAC、移位寄存器、SRAM 等)之間使用最廣泛的接口之一。

4 線 SPI 設備有四種信號:
- 時鐘(SPI CLK、SCLK)
- 片選(CS)
- 主節點輸出,子節點輸入 (MOSI)
- 主節點輸入,子節點輸出 (MISO)
??產生時鐘信號的設備稱為主設備。主節點和子節點之間傳輸的數據與主節點產生的時鐘同步。與 I2C 接口相比,SPI 設備支持的時鐘頻率要高得多(時鐘頻率和傳輸速度有著直接的關系)。用戶應查閱產品數據手冊以了解 SPI 接口的時鐘頻率規格。
??SPI 接口只能有一個主節點,可以有一個或多個子節點。
??主節點的片選信號用于選擇子節點。這通常是低電平有效信號,拉高可斷開子節點與 SPI 總線的連接。當使用多個子節點時,主節點需要為每個子節點提供單獨的片選信號。在本文中,片選信號始終是低電平有效信號。
??MOSI 和 MISO 是數據線,MOSI 將數據從主節點傳輸到子節點,MISO 將數據從子節點傳輸到主節點。
下表總結了 SPI 的關鍵特性:
特性 | 規格 |
---|---|
導線 | 4 |
最大速度 | SPI 傳輸速度沒有協議的限制,但會受硬件設計的影響。可能是 10MHz、50MHz、100MHz 等 |
同步或異步? | 同步 |
串行或并行? | 串行 |
最大主器件數 | 1 |
最大節點數 | 無限制 |
2、數據傳輸
??要開始 SPI 通信,主設備必須發送時鐘信號并通過啟用 CS 信號選擇子節點。
主機沒有數據傳輸(數據發送)的情況下,通常是沒有 CLK 信號的
??通常,芯片選擇是低電平有效信號;因此,主設備必須在此信號上發送邏輯 0 來選擇子節點。SPI 是一個全雙工接口;主節點和子節點可以分別通過 MOSI 和 MISO 線路同時發送數據。在 SPI 通信期間,數據同時傳輸和接收。串行時鐘沿同步數據的移位和采樣。
??SPI 接口為用戶提供了靈活性,可以選擇時鐘的上升沿或下降沿來采樣和/或發送數據。請參閱設備數據表以確定使用 SPI 接口傳輸的數據位數。
2.1 時鐘極性
??極性,會直接影響 SPI CLK 總線空閑時的時鐘信號是高電平還是低電平。
- CPOL = 1:表示空閑時是高電平
- CPOL = 0:表示空閑時是低電平
??當 CPOL 時鐘極性控制位被拉低時,它會使 SCK 管腳產生一個穩定的低電平。如果 CPOL 時鐘極性控制為被拉高,當沒有數據傳輸時,它會使 CLK 管腳產生一個穩定的高電平。即確定 SCK 在不傳輸數據時,是默認高電平或者默認低電平
2.2 時鐘相位
??一個時鐘周期會有 2 個跳變沿。而相位,直接決定 SPI CLK 總線從那個跳變沿開始采樣數據。
- CPHA = 0:表示從第一個跳變沿開始采樣
- CPHA = 1:表示從第二個跳變沿開始采樣
SPI mode | CPOL | CPHA |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
2 | 1 | 0 |
3 | 1 | 1 |
可以參考 W25Q64FW 中使用 0x9f 命令讀 ID 的傳輸過程示意圖:
2.3 數據交換
??SPI 設備間的數據傳輸之所以又被稱為數據交換,是因為 SPI 協議規定一個 SPI 設備不能在數據通信過程中僅僅只充當一個 “發送者(Transmitter)” 或者 “接收者(Receiver)”。
??一個 Slave 設備要想能夠接收到 Master 發過來的控制信號,必須在此之前能夠被 Master 設備進行訪問 (Access)。所以,Master 設備必須首先通過 SS/CS pin 對 Slave 設備進行片選, 把想要訪問的 Slave 設備選上。 在數據傳輸的過程中,每次接收到的數據必須在下一次數據傳輸之前被采樣。如果之前接收到的數據沒有被讀取,那么這些已經接收完成的數據將有可能會被丟棄,導致 SPI 物理模塊最終失效。因此,在程序中一般都會在 SPI 傳輸完數據后,去讀取 SPI 設備里的數據, 即使這些數據(Dummy Data)在我們的程序里是無用的(雖然發送后緊接著的讀取是無意義的,但仍然需要從寄存器中讀出來)。
- 如果不對接收進行讀取操作可能會導致溢出,將使以后發送出的數據全部無效
- 在每個 SPI 時鐘周期內,都會發生全雙工數據傳輸
- SPI 只有主模式和從模式之分(提供時鐘的為主設備 Master,接收時鐘的設備為從設備 Slave),沒有讀和寫的說法,因為實質上每次 SPI 是主從設備在交換數據。也就是說,你發一個數據必然會收到一個數據;你要收一個數據必須也要先發一個數據
- 發一個字節任意值數據是為了在 CLK 總線上產生時鐘,給從機的 SPI 信號提供時鐘用的,從機 SPI 不會自己產生 CLK 信號的
在 CS 片選有效的情況下才會有數據傳輸,有一種特殊情況,如果 CS 片選無效,設備硬件 FIFO 中的數據都會丟失。如果兩次寫操作中間 CS 一直有效,設備硬件 FIFO 中的數據不會丟失。這里要注意
??特別要注意的是,關于 Transfer Mode,是一個很奇怪的東西。這個玩意違背了“發送就一定需要接收”的邏輯,即上面所說“數據交換”的邏輯在一定程度上是問題的。這也給 SPI 總線驅動、包括 SPI 設備驅動帶來了很多變數。所以,寫設備驅動前,最好對總線驅動的發送與接收過程有個了解。
例如 rk3568 SPI 控制器中的 SPI_CTRLR0 寄存器:
- Transmit & Receive(就是我們上面提到,只要有發送,就一定會有接收,即使是臟數據,也需要讀出來):
In transmit-and-receive mode,both transmit and receive data are valid. The transfer continues until the transmit FIFO is empty. Data received from the external device are stored into the receive FIFO memory, where it can be accessed by the host processor
- Transmit Only:
In transmit-only mode,data received from the external device is not valid and is not stored in the receive FIFO memory; it is overwritten on the next transfer
- Receive Only:
In receive-only mode,transmitted data are not valid. After the first write to the transmit FIFO,the same word is retransmitted for the duration of the transfer
- EEPROM Read:
In eeprom-read mode, receive data is not valid while control data is being transmitted. When all control data is sent to the EEPROM, receive data becomes valid and transmit data becomes invalid. All data in the transmit FIFO is considered control data in this mode. This transfer mode is only valid when the DW_apb_ssi is configured as a master device
還有一個 SPI_CTRLR1 寄存器:
??這個只針對于 Receive Only 模式和 EEPROM Read 模式有效。該寄存器含義是指定 SPI 控制器一次連續接收的數據幀數量。通常情況下,是需要接收的幀數 -1 。
例如 EEPROM Read 模式:發送數據用于傳輸命令碼和地址到 EEPROM 設備,一般需要 3 個數據幀(8-bit 操作碼,8-bit 高位地址,8-bit 低位地址)。在操作碼和地址傳輸的過程中,控制器不會從串行總線上接收數據。當發送 FIFO 中的條目發送完畢,接收數據才開始被采樣,采樣的數據幀數是 NDF+1(也就是上面的 ndm 寄存器值 + 1)。
2.4 關于幀長度
??在發起一個 SPI 傳輸前,通常還需要設置本次傳輸的幀長度( Data Frame Size ) ,通常是 8 或 16 位。
struct spi_message {......unsigned frame_length;......
};
??SPI 協議本身并沒有幀長度(Frame Length)的固定概念,因為 SPI 是一種流式(streaming)傳輸協議,它是一個基于主從模式的時鐘同步串行通信協議,只關心 時鐘脈沖(SCK)和數據位(MOSI、MISO) 的同步,并不會主動分割數據。然而,在具體的 SPI 控制器、驅動程序或某些應用場景下,幀長度的概念被引入。這里要注意。