STM32学习笔记(15)——SPI协议
STM32學習筆記(15)——SPI協議
- 一、SPI協議簡介
- 1. 物理層
- 2. 協議層
- (1) 通訊的開始與停止
- (2)時鐘極性CPOL、時鐘相位CPHA
- 二、STM32的SPI外設
- 1. 通訊引腳
- 2. 時鐘控制邏輯
- 3. 數據控制邏輯
- 4. 整體控制邏輯
- 5. STM32的SPI通訊過程
- (1)從主機發送數據到從機的詳細過程(以 CPHA=1、CPOL=1 為例)
- (2)從從機接收數據到主機的詳細過程(以 CPHA=1、CPOL=1 為例)
- 三、SPI的初始化結構體和庫函數
- 1. SPI的初始化結構體
- 2. SPI的常用庫函數
一、SPI協議簡介
SPI(Serial Peripheral Interface)即串行外設總線接口,是由摩托羅拉公司提出的一種高速通訊協議,采用全雙工、同步通信方式。其通訊協議較 I2C 簡單,常常在單片機系統和一些要求通訊速率較高的場合中應用。
1. 物理層
SPI的物理層由一個主機和一個或多個從機組成。主機和每臺從機之間均有 4 條線組成,其中 SCK、MISO、MOSI 這三條線是共用的,而 SS 線是每臺從機與主機單獨連接。下面來一一介紹這 4 條線(信號):
-
SS/NSS/CS(片選信號):每個從機都有一條單獨的 SS 線與主機相連。當主機要選中某臺從機進行通訊時,需要發送低電平信號給從機的 SS,從機的片選信號有效,即從機被選中,接著主機開始與從機進行 SPI 通訊。當 SS 信號為高電平時,從機片選信號為禁止,此時通訊結束。因此,SPI 通訊以 SS 為低電平信號開始,以高電平信號結束。
-
SCK/SCLK(時鐘信號):主機產生時鐘信號,用于通訊的同步。它決定了通訊的速率,兩個設備進行通訊時,通訊速率會受限于低速設備。需要注意的是,只有主機控制時鐘信號,從機的時鐘完全由主機提供,當時鐘信號發生跳變時,從機才會采集數據;當沒有發生跳變時,從機不會采集數據。另外,SPI 協議并沒有硬性規定時鐘的頻率范圍是多少,這也是 SPI 協議的通訊速率快的原因。通訊狀態下 SCK 處于互補推挽輸出狀態;空閑狀態下處于高阻態。
-
MOSI(Master Output & Slave Input,主設備輸出/從設備輸入):主機的數據從 MOSI 線輸出后,從機從 MOSI 線讀入數據,此時的通訊方向為從主機到從機。通訊狀態下 MOSI 處于互補推挽輸出狀態;空閑狀態下處于高阻態。
-
MISO(Master Input & Slave Output,主設備輸入/從設備輸出):從機的數據從 MISO 線輸出后,主機從 MISO 線讀入數據,此時的通訊方向為從從機到主機。對于主機而言,MISO 總是處于高阻輸入狀態。
2. 協議層
下圖為 SPI 協議通訊圖,為方便說明已在圖中標出紅色數字:
(1) 通訊的開始與停止
標號 1 處是NSS信號由高電平跳變為低電平,說明SPI通訊開始。當從機檢測到 NSS 信號變為低電平后,就知道自己被主機選中了,開始與主機進行通訊。
標號 6 處是NSS信號由低電平跳變為高電平,說明SPI通訊結束。當從機檢測到 NSS 信號變為高電平后,就知道自己的選中狀態被取消了,結束與主機進行通訊。
(2)時鐘極性CPOL、時鐘相位CPHA
SPI 傳輸協議中一個很重要的問題是:傳輸的數據是什么時候被采集呢?是上升沿還是下降沿呢?這個與時鐘極性和時鐘相位有關,首先來介紹一下兩者的功能。
-
時鐘極性CPOL:SCLK 在空閑狀態下是一直為高電平或低電平的,通過時鐘極性 CPOL 可以控制空閑時 SCLK 的極性,進而決定了起始信號與停止信號的觸發方式。當 CPOL = 0 時,空閑狀態下的 SCLK 處于低電平,起始信號由 SCLK 的上升沿觸發,停止信號由 SCLK 的下降沿觸發;當 CPOL = 1 時,空閑狀態下的 SCLK 處于高電平,起始信號由 SCLK 的下降沿觸發,停止信號由 SCLK 的上升沿觸發。
-
時鐘相位CPHA:數據的采集可以在 SCLK 的上升沿觸發,也可以在下降沿觸發,通過時鐘相位 CPHA 可以控制 MISO 和 MOSI 數據采樣的觸發方式。當 CPHA = 0 時,數據采樣發生在 SCLK 的奇數邊沿,偶數邊沿則切換到下一位數據;當 CPHA = 1 時,數據采樣發生在 SCLK的偶數邊沿,奇數邊沿則切換到下一位數據。
按照這種方式,CPHA 和 CPOL 共同決定了數據采樣時的觸發邊沿。下面我們來看看兩者是如何影響數據采樣的觸發方式的:
如上圖所示,當 CPHA = 0,CPOL = 0 時,數據采樣發生在上升沿,切換數據位則發生在下降沿;當 CPHA = 0,CPOL = 1 時,數據采樣發生在下降沿,切換數據位則發生在上升沿。空閑狀態時 SCLK 始終為低電平。
如上圖所示,當 CPHA = 1,CPOL = 0 時,數據采樣發生在下降沿,切換數據位則發生在上升沿;當 CPHA = 1,CPOL = 1 時,數據采樣發生在上升沿,切換數據位則發生在下降沿。空閑狀態時 SCLK 始終為高電平。
因此,SPI 實際上被分為了四種不同的工作狀態,我們以表格形式總結一下:
| 0 | 0 | 0 | 上升沿 | 低電平 |
| 1 | 0 | 1 | 下降沿 | 高電平 |
| 2 | 1 | 0 | 上升沿 | 低電平 |
| 3 | 1 | 1 | 下降沿 | 高電平 |
通常情況下,模式 0 和模式 3 用的較多。只有主機和從機采用相同的模式才能夠正常通訊。
二、STM32的SPI外設
STM32 有多個 SPI 外設,STM32F10x 系列就擁有 3 個 SPI。SPI 的功能框圖如下圖所示:
1. 通訊引腳
SPI 一共有 4 個引腳,不同 SPI 對應的引腳也不同:
| NSS | PA4 | PB12 | PA15下載口的TDI |
| CLK | PA5 | PB13 | PB3下載口的TDO |
| MISO | PA6 | PB14 | PB4下載口的NTRST |
| MOSI | PA7 | PB15 | PB5 |
實際應用中,一般不使用 SPI 外設的標準 NSS 信號線,而是更簡單地使用普通的 GPIO,軟件控制它的電平輸出,從而產生通訊起始和停止信號。
注意 SPI3 中有些引腳與 SWD 下載引腳重合了,這對我們使用和學習有影響,因此在做 SPI 實驗時應避免使用 SPI3。STM32中文參考手冊也對此給出了提示:
警告:由于SPI3/I2S3的部分引腳與JTAG引腳共享(SPI3_NSS/I2S3_WS與JTDI,SPI3_SCK/I2S3_CK與JTDO),因此這些引腳不受IO 控制器控制,他們(在每次復位后)被默認保留為被默認保留為JTAG用途。如果用戶想把引腳配置給SPI3/I2S3必須(在調試時)關閉JTAG并切換至SWD接口,或者(在標準應用時)同時關閉JTAG和SWD接口。
2. 時鐘控制邏輯
之前說過,時鐘信號由 SCK 提供,而 SCK 又是由波特率發生器提供,它是由控制寄存器SPI_CR1的BR[2:0] 控制。可以得知:波特率與PCLK(即APB)的頻率有關。
那么如何確定 PCLK 的值呢?我們可以查看總線架構圖:
如圖所示,SPI1 掛載到 APB1(即PCLK1),SPI2、SPI3掛載到 APB2(即PCLK2)。對于 SPI1,因為 APB1 最高為 36MHz,所以 SPI1 時鐘最高為36MHz / 2 = 18MHz;對于SPI2、SPI3,因為 APB2 最高為 72MHz,所以兩者時鐘最高為72MHz / 2 = 36MHz。
3. 數據控制邏輯
SPI 的 MOSI 及 MISO 都連接到數據移位寄存器上,數據移位寄存器的數據來源來源于接收緩沖區及發送緩沖區。
數據寄存器SPI_DR 對應兩個緩沖區:一個用于寫(發送緩沖);另外一個用于讀(接受緩沖)。寫操作將數據寫到發送緩沖區;讀操作將返回接收緩沖區里的數據。
我們可以通過寫數據寄存器SPI_DR 把數據填充到發送緩沖區中;通過讀數據寄存器SPI_DR,可以獲取接收緩沖區中的內容。
數據幀長度可以通過控制寄存器SPI_CR1的DFF位配置成8位及16位模式;而 LSBFIRST位可配置移位寄存器的發送方向:選擇 MSB(高位數據)發送還是 LSB(低位數據)先發送。
4. 整體控制邏輯
控制邏輯根據外設的工作狀態修改狀態寄存器SPI_SR,只要讀取狀態寄存器相關的寄存器位,就可以了解 SPI 的工作狀態了。除此之外,控制邏輯還根據要求,負責控制產生 SPI 中斷信號、DMA 請求及控制 NSS 信號線。
5. STM32的SPI通訊過程
當 STM32 作為主機時,與從機的通訊過程如下圖:
首先需要知道一個大概的過程:主機輸出的數據都要通過緩沖區(對應數據寄存器SPI_DR)才能進入移位寄存器,最后再發送;主機讀入的數據都要通過移位寄存器,再移入緩沖區。因此,緩沖區和移位寄存器中的數據在同一時刻是不一樣的,它們正好相差了一次通信時間。
(1)從主機發送數據到從機的詳細過程(以 CPHA=1、CPOL=1 為例)
- 往發送緩沖區(即數據寄存器SPI_DR)寫入一個數據(比如圖中的 0XF1),此時觸發 SCK 信號進入忙碌狀態。此時狀態寄存器SPI_SR的BSY(忙標志,Busy flag)位為 1,表示 SPI 開始通信;TXE(發送緩沖為空,Transmit buffer empty)位為 0,表示發送緩沖非空。
- 由于移位寄存器還沒有數據,因此發送緩沖區很快將數據 0xF1 轉移到移位寄存器中。此時TXE位為 1,表示發送緩沖為空。移位寄存器將數據一位一位傳到 MOSI 線。
- 等待至TXE位為 1后,軟件往發送緩沖區寫入第二個數據(比如 0xF2),TXE位變為 0,表示發送緩沖非空。由于移位寄存器還沒將前一個數據 0xF1 全部發送出去,因此新數據 0xF2 暫時存到緩沖區。
- 前一個數據發送完畢后,新數據 0xF2 轉移到移位寄存器中,此時TXE位為 1,表示發送緩沖為空。移位寄存器將數據一位一位傳到 MOSI 線。
- 如此往復:等待TXE位由0變為 1,軟件往發送緩沖區寫入新數據,前一個數據發送完,新數據就往移位寄存器補,并將其一位一位發出去。發送出去的數據總比新寫入緩沖區的數據少一次發送周期。
(2)從從機接收數據到主機的詳細過程(以 CPHA=1、CPOL=1 為例)
- 必須先使 SPI 啟動(即讓 SCK 處于忙碌狀態),才能接收數據。因此,需要先往發送緩沖隨意寫入一個數據,以觸發 SCK 信號進入忙碌狀態。寫入數據后,狀態寄存器SPI_SR的BSY位為 1,表示 SPI 開始通信;RXNE(接收緩沖非空,Receive buffer not empty)位為 0,表示接收緩沖為空。
- 移位寄存器一位位接收到從 MISO 來的數據 0xA1,將數據轉移到接收緩沖區中,然后進行下一次數據接收;此時RXNE位為 1,表示接收緩沖非空,表明軟件可以開始讀取數據 0xA1。
- 待數據讀取完后,RXNE位為 0,表示接收緩沖為空。此時移位寄存器將新數據 0xA2 轉移到接收緩沖區中,RXNE位為 1,表示接收緩沖非空,表明軟件可以開始讀取數據 0xA2
- 如此往復:移位寄存器一位位接收數據,然后將數據轉移到接收緩沖區,然后繼續接收下一次數據;軟件等待RXNE位由 0 變為 1 后,從接收緩沖區讀取數據。接收到的數據總比新讀取緩沖區的數據多一個發送周期。
三、SPI的初始化結構體和庫函數
1. SPI的初始化結構體
以下為 SPI 的結構體定義:
typedef struct {uint16_t SPI_Direction; /*!< 配置 SPI 的單/雙向模式 */uint16_t SPI_Mode; /*!< 配置 SPI 的主/從機模式 */uint16_t SPI_DataSize; /*!< 配置 SPI 的數據幀長度(8/16位) */uint16_t SPI_CPOL; /*!< 配置 SPI 的時鐘極性(高/低電平) */uint16_t SPI_CPHA; /*!< 配置 SPI 的時鐘相位(奇/偶邊沿采樣) */uint16_t SPI_NSS; /*!< 配置 SPI 的 NSS 引腳由軟件控制還是硬件控制 */uint16_t SPI_BaudRatePrescaler; /*!< 配置 SPI 的時鐘分頻因子 */uint16_t SPI_FirstBit; /*!< 配置數據是高位先行(MSB)或低位先行(LSB) */uint16_t SPI_CRCPolynomial; /*!< 配置 CRC 校驗表達式 */ }SPI_InitTypeDef;- SPI_Direction(單/雙向模式):可配置為雙線全雙工、雙線只接收、單線只接收、單線只發送模式。
- SPI_Mode(主/從機模式):若配置為主機模式,則 STM32 將提供 SCLK 時序信號;若配置為從機模式,則 STM32 將接收外來的 SCLK 信號。
- SPI_DataSize(數據幀長度):可配置 8 位數據幀或 16 位數據幀。
- SPI_CPOL(時鐘極性)和SPI_CPHA(時鐘相位):可參考 SPI 相關頭文件和本文章的相關內容,不再贅述。
- SPI_NSS(NSS引腳使用模式):若選擇硬件模式,則 SPI 片選信號由 SPI 硬件自動產生;若軟件模式,則需要手動把相應的 GPIO 端口置 1 或置 0 以產生禁止片選或允許片選信號。
- SPI_BaudRatePrescaler(時鐘分頻因子):可設置為 PCLK 的 2、4、6、8、16、32、64、128、256分頻。
- SPI_FirstBit(數據先行模式):不再贅述。
- SPI_CRCPolynomial(CRC校驗):這是 SPI 的 CRC 校驗中的多項式,若我們使用 CRC 校驗時,就使用這個成員的參數(多項式),來計算 CRC 的值。
2. SPI的常用庫函數
// 與初始化相關: void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);// 與接收、發送數據相關: void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);// 與標志位相關: FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG); void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);// 與中斷標志位相關: ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT); void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);未完待續···
總結
以上是生活随笔為你收集整理的STM32学习笔记(15)——SPI协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果手机投影_会议室投影机最常用的一款无
- 下一篇: 怎么用科学计算机算反三角函数值域,反三角