基本特點
- 通信方式:同步、串行(串行、并行、并發,別再傻傻分不清了!_串行和并行的區別-CSDN博客)、全雙工 (也可以選擇半雙工)
- 速率:50MHZ以下
- 數據格式:8位/16位
- 傳輸順序:MSB先行/LSB先行
通信
spi通信需要四個引腳,MOSI MISO SCK NSS。
- MOSI: master output slave input 主設備數據輸出 從設備數據接收
- MISO:master input slave output
- SCK:時鐘線 只有主設備能控制。不同的設備支持的最高時鐘頻率不一樣,如?STM32?的 SPI 時鐘頻率最大為 fpclk/2,兩個設備之間通訊時,通訊速率受限于低速設備
- NSS(CS):片選不同的從設備 可選擇硬件NSS和軟件NSS
一對一:
一對多:
SCK
時鐘線 空閑電平取決于工作模式的設置(見后)
NSS
原理:NSS保持高電平,如果想發起通信,主設備就去拉低對應從機的NSS信號線使能從機 開始與其通信(即MOSI 與 MISO 的信號只在 NSS 為低電平的時候才有效)
NSS可以選擇是硬件模式還是軟件模式,硬件模式就是一個固定的引腳作為NSS,直接與外界從設備的GPIO口相連,軟件自選管腳
NSS模式的選擇是由SPI_CR1寄存器中的ssm位和SPI_CR2寄存器中的SSOE位控制的。
區分一下NSS和CS
雖然大概上說這兩者差不多(或者可以直接看做相同) 但還是有些微妙的差別。
NSS指的是芯片硬件上的那個真實存在的片選管腳,而CS雖然也起到片選從機的作用 但是它主要是強調主從之間實際連接的那個片選線,用軟件手動控制。
具體的通信過程
- 主機首先拉低對應從機的NSS信號線,表示與該設備進行通信。
- 然后主機發送SCLK時鐘信號,通知從機讀/寫數據。(SCLK時鐘信號可能是低電平有效,也可能是高電平有效,見【spi四種工作模式】)
- 主機(Master)將要發送的數據寫到發送數據緩存區(Menory),緩存區經過移位寄存器(0~7),串行移位寄存器通過MOSI信號線將字節一位一位的移出去傳送給從機,同時MISO接口接收到的數據經過移位寄存器一位一位的移到接收緩存區。
- 從機(Slave)也將自己的串行移位寄存器(0~7)中的內容通過MISO信號線返回給主機。同時通過MOSI信號線接收主機發送的數據,這樣,兩個移位寄存器中的內容就被交換。
Warning
SPI沒有嚴格意義上的讀寫操作 只有發送和接收 而且無論是對主還是從設備 發送和接收都是一起進行的。
以主設備為例 主設備移位寄存器一位位把數據傳到MOSI信號線上同時 MISO信號線上的數據也被一位位移進數據移位寄存器 然后再傳給緩沖區這樣
所以無論是主還是從設備 發送(接收)一個字節必須同時接收(發送)一個字節
如果是要主設備只輸出 就得忽略掉從設備發送的字節。同理主設備只接收 從設備就得忽略掉主設備發送的字節(不過這個知道就好 hal庫函數已經配備好了 如果不是自己寫軟件SPI的話其實不用考慮)
四種工作模式
SPI的工作模式由CPOL(時鐘極性)和CPHA(相位)控制。
CPOL=0:低電平空閑高電平讀取 =1:高電平空閑
CPHA=0:第一個沿采樣 =1:第二個沿采樣
模式 | CPOL | CPHA | 說明 |
---|---|---|---|
0 | 0 | 0 | 高電平的上升沿讀取 |
1 | 0 | 1 | 高電平的下降沿讀取 |
2 | 1 | 0 | 低電平的下降沿讀取 |
3 | 1 | 1 | 低電平的上升沿讀取 |
這四種工作模式的選擇不是自己喜歡哪個選哪個 而是要根據從設備的數據幀規格設定。
STM32 SPI硬件架構
幾個相關的寄存器:
- 控制寄存器:SPI_CR1 和SPI_CR2。控制整個SPI模塊的工作狀態
- SPI_CR1:
- CPHA:時鐘相位,0:第一個邊沿采樣 1:第二個邊沿
- CPOL:時鐘極性(0: 空閑時為低電平;1: 空閑時為高電平)
- MSTR:主從選擇(1:主機)
- BR[2:0]:波特率設置,控制 SCK 的分頻
- SPE:使能SPI
- SSM:軟件NSS管理。SSM=1,軟件NSS。此時是否選中從機由下面的SSI位決定^^
- SSI:在SSM=1時有效。SSI=1,相當于軟件拉高MSS,如果設置為0相當于拉低NSS(開始通信)
- LSBFIRST:是否小端傳輸
- SSI/SSM:軟件控制 NSS(用于不連接外部 NSS)
- RXONLY:接收模式(1 = 僅接收 也就是半雙工,只有MISO能使用)(0:全雙工
- DFF:數據幀格式(0: 8bit,1: 16bit)
- CRCEN:CRC 校驗使能
- BIDIMODE :=0:全雙工;=1:單線模式,只能使用MOSI來進行雙向傳輸
- BIDIOE:僅在BIDIMODE=1時有效。=1:單線處于主機發送模式;=0:單線處于從機接收模式
- SPI_CR2:
- TXEIE :開啟后當TXE=1(發送緩沖區為空)時觸發中斷 讓cpu發數據
- RXNEIE:開啟后當RXNE=1(接收緩沖區費控)時觸發中斷 讓cpu讀數據
- ERRIE: 錯誤中斷使能
- SSOE:硬件 NSS 輸出使能(主機自動控制 NSS)
- TXDMAEN / RXDMAEN:發送/接收 DMA 使能
- SPI_CR1:
- 狀態寄存器SPI_SR
- RXNE:接收緩沖區非空(表示可以讀取)(rx no empty)
- TXE:發送緩沖區空(表示可以寫入)
- BSY:忙標志位(1 = 正在通信)
- OVR:溢出錯誤(接收緩沖未讀取就新數據來了
- MODF: 模式錯誤(如主從沖突)
- CRCERR:CRC錯誤
- 數據移位寄存器/串并轉換器shift register:把數據一位位的移入/移出 實現數據串行和并行之間的轉換
- tx buffer:發送緩沖區,由 CPU 或 DMA 寫入數據。
- rx buffer:接收緩沖區,接收到的數據存放在這里,等待 CPU 或 DMA 讀取。
- Baud Rate Generator(波特率發生器):?控制 SCK(串行時鐘)的頻率,由 CR1 寄存器中的 BR[2:0] 決定,通過分頻選擇 SPI 的時鐘速度。
- Master Control Logic(主控邏輯),由 CR1 中的 MSTR、SPE 控制。MSTR:選擇主/從設備(1 = 主機,0 = 從機)。SPE:SPI 使能。
再解釋一下軟件NSS
硬件NSS下內部是直接根據NSS引腳上的電平來進行狀態判斷的。
軟件NSS下因為不知道你選的是哪個GPIO口 所以不能直接去讀對應引腳的電平了 內部就只能通過SPICR1寄存器里的ssi位來模擬NSS線上的電平變化。這部分是要你自己寫的。
硬件SPI和軟件模擬SPI
硬件
硬件spi就是打開cubemx上的spi配置,自帶CRC校驗(可選)和DMA(可選)。
- 先使能spi
模式這里選擇的是全雙工 右邊自動亮起三個固定引腳對應SCK MISO MOSI,NSS默認不顯示(即使用軟件NSS)
2.
如果打開硬件NSS(可以選擇NSS是輸入還是輸出 主設備的話就是NSS輸出 從設備的話就是NSS輸入,無論輸出還是輸入NSS都是用那一個引腳)。
如果堅持使用軟件NSS,就在右邊隨便選一個引腳設置為GPIO_OUTPUT.
3.參數設置(參數設置我瞎選的 不用跟著我來 要跟著從機)
- frame format幀格式。可以選擇motoroia和TI兩種。
- 選TI會變成這樣
摩托羅拉比TI多一個時鐘極性和相位的選擇還有first bit。
一般默認使用摩托羅拉。(TI模式蠻麻煩的我沒仔細看 但是應用上其實會簡單點 因為少了挺多配置)
- 選TI會變成這樣
- data size:SPI 每次數據傳輸可以 8 位或 16 位為單位,每次傳輸多少個單位無限制。
- first bit:選擇字節序。MSB或者LSB都可以?跟著從設備選
MSB和LSB - prescaler:通過配置它使波特率適配從機
- baud rate :線上的波特率 是根據你的時鐘配置 和 prescaler的選擇 自動計算得到?跟著從機走
- CPOL:時鐘極性 設置0或1
- CPHA:相位。
- CRC calculation:crc校驗是否開啟
- 開啟它后會出現一個CRC Polynomial 默認即可
CRC校驗 - nss signal typedef:自動跟著之前的配置
具體使用見:
硬件SPI的HAL庫函數調用
軟件模擬
就是自己在keil5里寫代碼 選4個引腳分別代表SCK MOSI MISO NSS,寫對應的發送/接收/時鐘拉高/拉低/數據讀取等等操作。
軟件比起硬件SPI大概只有一個自選引腳的優點 其他全是缺點(特別是時序上需要非常精確)so不建議用。
而且軟件SPI沒法用DMA,數據一多讀起來很占用CPU。
SPI使用過程中的一些注意
-
主從設備的MOSI和MOSI是對應相連 而不是交叉相連(be like MOSI——MISO)
-
主機在SPI初始化后必須先拉低從機的NSS再發送(因為SPI一enable馬上就會輸出時鐘脈沖……)否則很容易會丟數據,發送完成后需要等待BSY標志位為0才能把NSS拉高
-
硬件NSS的話hal庫函數里是能實現第二條的 但是沒有BSY==0后再升高NSS的邏輯 so如果是一些時序嚴格的設備就不要用硬件NSS了……自己寫吧
-
軟件NSS不僅自己拉高/拉低NSS要自己寫 SPI_CR1寄存器中SSI位的1or0判斷也要自己寫
參考:
【STM32 HAL庫SPI/QSPI協議學習,基于外部Flash讀取】_stm32 hal qspi-CSDN博客
SPI中NSS/CS使用和SPI常見問題_spi cs-CSDN博客
【STM32】HAL庫 STM32CubeMX教程十四---SPI-CSDN博客
STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 advanced Arm?-based 32-bit MCUs - Reference manual