spi通訊協議
學微控制器必須要掌握的集中序列通訊協議中spi就是其中之一。
下面主要是講解下個人對於spi通訊時序圖以及通訊協議的理解(有說錯的請大指出,小弟也是剛學的有很多不懂)。
下面進入正題:
SPI簡介
SPI就是序列外圍裝置介面,它是一種高速的,全雙工,同步的通訊匯流排,並且在晶片的管腳上只佔用四根線,這四根線的定義分別是:
MISO:主裝置資料輸入,從裝置資料輸出;
MOSI:主裝置資料輸出,從裝置資料輸入;
SCLK:時鐘訊號,由主裝置產生;
CS:從裝置片選訊號,由主裝置控制;
SPI為了和外設進行資料交換,根據外設工作要求(具體得看外設spi讀寫時序圖,有時序圖編寫驅動程式碼
spi內部結構圖:
SPI匯流排資料傳輸時序圖如下圖:
總結:spi通訊為4線全雙工,spi通訊由於時鐘極性(CPOL)時鐘相位(CPHA)的不同可以配置為4種模式。完成一位資料傳輸是在一個週期兩個跳變沿內完成的,一個跳變沿取樣(可以理解為:內部移位暫存器讀取io值),一個跳變沿資料輸出(可以理解為:內部移位暫存器將最高位移動到io口上)。
具體移動過程參考此帖子:http://bbs.elecfans.com/jishu_441914_1_1.html
時鐘前沿輸出:
時鐘後沿取樣:
就這樣一個週期完成一位資料的交換。
stm32spi主模式下資料的傳送與接收:
資料傳送過程
當寫入資料至傳送緩衝器時,傳送過程開始。
在傳送第一個資料位時,資料字被並行地(通過內部匯流排)傳入移位暫存器,而後序列地移出到MOSI腳上; MSB在先還是LSB在先,取決於SPI_CR1暫存器中的LSBFIRST位的設定。資料從傳送緩衝器傳輸到移位暫存器時TXE標誌將被置位,如果設定了SPI_CR1暫存器中的TXEIE位,將產生中斷。
資料接收過程
對於接收器來說,當資料傳輸完成時:
● 傳送移位暫存器裡的資料到接收緩衝器,並且RXNE標誌被置位。
● 如果設定了SPI_CR2暫存器中的RXNEIE位,則產生中斷。
在最後取樣時鐘沿, RXNE位被設定,在移位暫存器中接收到的資料字被傳送到接收緩衝器。讀SPI_DR暫存器時, SPI裝置返回接收緩衝器中的資料。讀SPI_DR暫存器將清除RXNE位。
一旦傳輸開始,如果下一個將傳送的資料被放進了傳送緩衝器,就可以維持一個連續的傳輸流。在試圖寫傳送緩衝器之前,需確認TXE標誌應該為’1’。
總結; 傳送端:資料---DR暫存器---->緩衝區----->移位暫存器------>一位一位的傳送到主機輸出口
接收端:讀取miso口資料(從機發來)到移位暫存器---->讀取8位後放入緩衝區-----DR暫存器
程式的讀寫資料都是對緩衝區操作的。傳送緩衝暫存器為空TXE=1,接收緩衝暫存器不為空RXNE=1,所以spi讀寫資料過程:
傳送資料時:判斷髮送緩衝暫存器是否為空為空則傳送,
接收資料時:判斷接收緩衝暫存器是否非空,是則讀取資料。
例如:
u8 SPI1_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //檢查指定的 SPI
//標誌位設定與否:傳送快取空標誌位
{
retry++;
if(retry>200)
return 0;
}
SPI_I2S_SendData(SPI1, TxData); //通過外設 SPIx 傳送一個數據
retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//檢查指定的
SPI 標誌位設定與否:接受快取非空標誌位
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI1); //返回通過 SPIx 最近接收的資料
}
stm32 spi初始化過程:
配置步驟
1. 通過SPI_CR1暫存器的BR[2:0]位定義序列時鐘波特率。
2. 選擇CPOL和CPHA位,定義資料傳輸和序列時鐘間的相位關係(見圖212)。
3. 設定DFF位來定義8位或16位資料幀格式。
4. 配置SPI_CR1暫存器的LSBFIRST位定義幀格式。
5. 如果需要NSS引腳工作在輸入模式,硬體模式下,在整個資料幀傳輸期間應把NSS腳連線
到高電平;在軟體模式下,需設定SPI_CR1暫存器的SSM位和SSI位。如果NSS引腳工作
在輸出模式,則只需設定SSOE位。
6. 必須設定MSTR位和SPE位(只當NSS腳被連到高電平,這些位才能保持置位)。
在這個配置中, MOSI引腳是資料輸出,而MISO引腳是資料輸入。
例如:
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //設定 SPI 全雙工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //設定 SPI 工作模式:設定為主 SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位幀結構
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//選擇了序列時鐘的穩態:時鐘懸空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //資料捕獲於第二個時鐘沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 訊號由硬體管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //預分頻 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //資料傳輸從 MSB 位開始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值計算的多項式
SPI_Init(SPI1, &SPI_InitStructure); //②根據指定的引數初始化外設 SPIx 暫存器
SPI_Cmd(SPI1, ENABLE); //③使能 SPI 外設