SPI是是一種高速的,全雙工,同步的總線通信方式。STM32F1低中容量設備的SPI模塊支持主從兩種模式。
一、SPI協議介紹
1.硬件連接
SPI使用三條數據總線和一條片選線: MOSI、MISO、SCK、NSS(CS)
MOSI(SDO):主設備輸出/從設備輸入。用于將數據從主機輸出到從機。
MISO(SDI):主設備輸入/從設備輸出。數據經此由從機至主機,主機接收數據。
NSS:片選信號線。由主機通過此線使能從機。在一主多從的通訊模式下,只能同時有一個從機被使能。
SPI器件間的連接很簡單,如圖,只要名字相同線相連即可,主也可以比較方便地反轉。
2.通信時序
SPI傳輸模式的精髓在時鐘極性(CPOL)和時鐘相位(CPHA)
CPOL控制空閑狀態下時鐘總線SCK的電平:
CPOL=0(LOW);時鐘線空閑為低電平
CPOL=1(HIGH);時鐘線空閑為高
CPHA控制采樣位置和信號跳變位置:
※SPI傳輸從高位(MSB)開始還是低位(LSB)開始可以由用戶設置
二、STM32F1的SPI模塊
1.在CubeMX中進行配置
數據位可選擇8或16
CPHA可選擇從第一個數據沿開始(CPHA=0)或從第二個數據沿開始(CPHA=1)
可選擇高位先發送或是低位先發送
可選擇是否使用NSS以及NSS功能(輸入、輸出用)。用戶也可以用普通IO的中斷輸入/輸出功能模擬NSS,這種方法相對更加靈活。
※ 按照個人開發經驗,SPI一般配置為雙線雙向全雙工情況比較多。
※STM32的 NSS引腳說明和工作極其復雜,建議開發者禁用硬件NSS,自行定義普通GPIO實現片選功能。(NSS腳禁用后可以進行GPIO配置當作普通IO控制實現CS功能)
2.相關寄存器
API:
1.初始化結構體LL_SPI_InitTypeDef
typedef struct
{
uint32_t TransferDirection;/*
數據線配置;通過調用LL_SPI_SetTransferDirection()實現;
@ref: LL_SPI_FULL_DUPLEX //全雙工,雙線雙向
LL_SPI_SIMPLEX_RX //雙線雙向模式下禁止輸出,僅能輸入
LL_SPI_HALF_DUPLEX_RX //單線,僅能接收
LL_SPI_HALF_DUPLEX_TX //單線,僅能發送
※單線模式下,工作于Master時使用MOSI腳;Slave時為MISO腳
*/
uint32_t Mode;/*
設置主從模式,通過LL_SPI_SetMode()實現;
@ref: LL_SPI_MODE_MASTER //主模式,配置時若NSS由軟件管理會將電平置高
LL_SPI_MODE_SLAVE
*/
uint32_t DataWidth;/*
設置數據長度;通過LL_SPI_SetDataWidth()實現;
@ref: LL_SPI_DATAWIDTH_8BIT //8位
LL_SPI_DATAWIDTH_16BIT //16位
*/
uint32_t ClockPolarity;/*
設置時鐘極性(CPOL),通過LL_SPI_SetClockPolarity()實現
@ref: LL_SPI_POLARITY_LOW //低電平(CPOL=0)
LL_SPI_POLARITY_HIGH //高電平(CPOL=1)
*/
uint32_t ClockPhase;/*
設置時鐘相位,通過LL_SPI_SetClockPhase()實現
@ref: LL_SPI_PHASE_1EDGE //CPHA =0
LL_SPI_PHASE_2EDGE //CPHA=1
*/
uint32_t NSS;/*
配置NSS(CS),通過LL_SPI_SetNSSMode()實現;
@ref: LL_SPI_NSS_SOFT //通過軟件管理NSS;※此時NSS引腳無法進行I/O操作控制
//CubeMx配置為Disable時配置為此模式(相當于禁用了NSS)
//此時可以通過操作SPI_CR1- >SSI位控制該位電平;LL庫未提供函數;
LL_SPI_NSS_HARD_INPUT //說不清除,手冊和庫函數說明沖突,建議不用
LL_SPI_NSS_HARD_OUTPUT//同樣,不建議配置
//鑒于片選復雜性,推薦開發者直接通過GPIO直接模擬NSS(CS)功能,可用原NSS
*/
uint32_t BaudRate;/*
配置波特率分頻,通過LL_SPI_SetBaudRatePrescaler()實現;
@ref: LL_SPI_BAUDRATEPRESCALER_DIVx //x為2^n,max=128
*/
uint32_t BitOrder;/*
配置發送位順序,通過LL_SPI_SetTransferBitOrder()實現;
@ref: LL_SPI_LSB_FIRST //低位先
LL_SPI_MSB_FIRST //高位先
*/
uint32_t CRCCalculation;/*!< Specifies if the CRC calculation is enabled or not.
This parameter can be a value of @ref SPI_LL_EC_CRC_CALCULATION.
This feature can be modified afterwards using unitary functions @ref LL_SPI_EnableCRC() and @ref LL_SPI_DisableCRC().*/
uint32_t CRCPoly;/*!< Specifies the polynomial used for the CRC calculation.
This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFFFF.
This feature can be modified afterwards using unitary function @ref LL_SPI_SetCRCPolynomial().*/
} LL_SPI_InitTypeDef;
2.初始化函數
ErrorStatus LL_SPI_Init(SPI_TypeDef *SPIx, LL_SPI_InitTypeDef *SPI_InitStruct);/*
初始化SPI;
*/
void LL_SPI_StructInit(LL_SPI_InitTypeDef *SPI_InitStruct)/*
初始化SPI配置結構體
*/
ErrorStatus LL_SPI_DeInit(SPI_TypeDef *SPIx)/*
初始化SPI模塊
*/
3.開啟/關閉模塊
__STATIC_INLINE void LL_SPI_Enable(SPI_TypeDef *SPIx);/*
開啟SPI模塊
*/
__STATIC_INLINE void LL_SPI_Disable(SPI_TypeDef *SPIx);/*
關閉SPI模塊
*/
__STATIC_INLINE uint32_t LL_SPI_IsEnabled(SPI_TypeDef *SPIx);/*
檢測開啟狀態
*/
※與UART不同,目前版本CubeMX自動生成代碼不會開啟SPI,需用戶手動開啟
關閉SPI需要在傳輸完成后
4.標志位/狀態位
MODF:主模式失效錯誤標志。在NSS引腳硬件模式管理下,主設備的NSS腳被拉低時;或者在NSS引腳軟件模式管理下,SSI位被置0時被置位。同時SPI模塊被關閉。 在使用LL庫時若不使用NSS功能,則不會出現置位情況
※RXNE:接收緩沖非空。與USART類似,當※接收數據寄存器完全完成一次數據接收時,該位被置位。※對讀取數據寄存器RDR的讀取操作可以硬件清零該位。
※TXE:發送緩沖空。當發送數據寄存器數據被送出時,該位被置位。對發送數據寄存器TDR的寫入操作可以硬件清零該位。
BSY:忙標志。SPI在通訊時該位為1。該位完全由硬件控制。在主模式的雙向接收模式下 (MSTR=1、BDM=1并且BDOE=0),在接收期間BSY標志保持為低。不要使用BSY標志處理每一個數據項的發送和接收,最好使用TXE和RXNE標志。
OVR:溢出錯誤。接收數據時,當發送端設備已經發送了數據字節,而STM32還沒有清除前一個數據字節產生的RXNE時,即為溢出錯誤。
當溢出時,讀SPI_DR寄存器返回的是之前未讀的數據,所有隨后傳送的數據都被丟棄。
※與USART不同,SPI模塊TXE與RXNE位是只讀的,其值由硬件管理。
__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_BSY(SPI_TypeDef *SPIx);/*
檢測BSY是否置位,該位無法軟件控制
*/
__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_OVR(SPI_TypeDef *SPIx);/*
檢測OVR是否置位(發生過載錯誤)
*/
__STATIC_INLINE void LL_SPI_ClearFlag_OVR(SPI_TypeDef *SPIx);/*
置位OVR
*/
__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_TXE(SPI_TypeDef *SPIx);/*
檢測TXE是否置位
*/
__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_RXNE(SPI_TypeDef *SPIx);/*
檢測RXNE是否置位
*/
__STATIC_INLINE uint32_t LL_SPI_IsActiveFlag_MODF(SPI_TypeDef *SPIx);
__STATIC_INLINE void LL_SPI_ClearFlag_MODF(SPI_TypeDef *SPIx);
5.中斷控制
__STATIC_INLINE void LL_SPI_EnableIT_ERR(SPI_TypeDef *SPIx);/*
使能ERR錯誤中斷*/
__STATIC_INLINE void LL_SPI_DisableIT_ERR(SPI_TypeDef *SPIx);/*
禁用ERR錯誤中斷*/
__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_ERR(SPI_TypeDef *SPIx);/*
檢測是否開啟ERR中斷*/
__STATIC_INLINE void LL_SPI_EnableIT_RXNE(SPI_TypeDef *SPIx);/*
使能RXNE接收緩沖非空中斷*/
__STATIC_INLINE void LL_SPI_DisableIT_RXNE(SPI_TypeDef *SPIx);/*
禁用RXNE接收緩沖非空中斷*/
__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_RXNE(SPI_TypeDef *SPIx)/*
檢測是否開啟RXNE接收緩沖非空中斷*/
__STATIC_INLINE void LL_SPI_EnableIT_TXE(SPI_TypeDef *SPIx);/*
使能TXE發送緩沖空中斷*/
__STATIC_INLINE void LL_SPI_DisableIT_TXE(SPI_TypeDef *SPIx);/*
禁用TXE發送緩沖空中斷*/
__STATIC_INLINE uint32_t LL_SPI_IsEnabledIT_TXE(SPI_TypeDef *SPIx)/*
檢測是否開啟TXE發送緩沖空中斷*/
6.SPI 收/發函數
__STATIC_INLINE uint8_t LL_SPI_ReceiveData8(SPI_TypeDef *SPIx);/*
從接收寄存器(緩沖區)DR中讀取8位數據;
*/
__STATIC_INLINE uint16_t LL_SPI_ReceiveData16(SPI_TypeDef *SPIx);/*
從接收寄存器(緩沖區)DR中讀取16位數據;
*/
__STATIC_INLINE void LL_SPI_TransmitData8(SPI_TypeDef *SPIx, uint8_t TxData);/*
向發送寄存器(緩沖區)DR中寫入8位數據
*/
__STATIC_INLINE void LL_SPI_TransmitData16(SPI_TypeDef *SPIx, uint16_t TxData);/*
向發送寄存器(緩沖區)DR中寫入16位數據
*/
SPI模塊DMA的使用
相關函數:
待實驗
__STATIC_INLINE void LL_USART_EnableDMAReq_RX(USART_TypeDef *SPIx);/*
使能接收DMA,啟用后DR有數據時將允許發送DMA請求;具體見示例用法*/
__STATIC_INLINE void LL_USART_DisableDMAReq_RX(USART_TypeDef *SPIx);/*
禁用接收DMA*/
__STATIC_INLINE uint32_t LL_USART_IsEnabledDMAReq_RX(USART_TypeDef *SPIx);/*
檢測是否使能接收DMA*/
__STATIC_INLINE void LL_USART_EnableDMAReq_TX(USART_TypeDef *SPIx);/*
使能發送DMA*/
__STATIC_INLINE void LL_USART_DisableDMAReq_TX(USART_TypeDef *SPIx);/*
禁用發送DMA*/
__STATIC_INLINE uint32_t LL_USART_IsEnabledDMAReq_TX(USART_TypeDef *SPIx);/*
檢測是否使能發送DMA*/
/**************************************************/
__STATIC_INLINE uint32_t LL_USART_DMA_GetRegAddr(USART_TypeDef *SPIx);/*
返回SPI模塊數據寄存器DR地址;無論是否啟用DMA均可用
*/
發送時,在每次TXE被設置為’1’時發出DMA請求,此時軟件控制DMA寫數據至SPI_DR寄存器,TXE標志因此而被清除。
接收時,在每次RXNE被設置為’1’時發出DMA請求,在開啟情況下DMA控制器從SPI_DR寄存器讀出數據,RXNE標志因此而被清除。
LL的DMA使用與UART相似,可以參考之前的文章。
SPI在雙向全雙工傳輸數據的時候,每發出一字節數據的同時也會接收一字節數據,因此在作為主機接收的時候,應當考慮 如何處理接收到的無用數據。否則會出現OVR。
另外,由于在雙向模式下配置為主機時,只有當SPI在寫數據時時鐘信號才能產生。處于master工作模式下,SPI的時鐘只有在往DR寄存器里面寫數據的時候才會產生,讀是不會產生的。所以要讀取slave shift out的數據,master必須先發一個“DUMMY”數據以產生時鐘。
建議配置STM32為雙向主機、從機; 配置為主機接收前讀取一次DR,再發送DUMMY(建議發0x00或0xFF,不要增加沒必要的干擾)
-
數據寄存器
+關注
關注
0文章
33瀏覽量
7966 -
SPI接口
+關注
關注
0文章
262瀏覽量
35264 -
CPHA
+關注
關注
0文章
8瀏覽量
9487 -
USART串口
+關注
關注
0文章
32瀏覽量
7024 -
stm32f1
+關注
關注
1文章
58瀏覽量
12438
發布評論請先 登錄
STM32F1的I2C模塊協議簡介

STM32F1 & SHT3x溫濕度模塊

評論