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