SPI介紹+軟體模擬SPI
1.什麼是SPI
SPI通常有一個主裝置和一個或多個從裝置,通常採用的是4根線,它們是MISO(資料輸入,針對主機來說)、MOSI(資料輸出,針對主機來說)、SCLK(時鐘,主機產生)、CS/SS(片選,一般由主機發送或者直接使能,通常為低電平有效)。全雙工。
2.SPI物理層
圖1 SPI物理層連線圖
一個主機可以連線多個從機,其中SCK,MOSI,MISO所有從機共用。SSx單獨連線主機。當主機需要和從機通訊時,主機把對應的從機的SSx線拉低。從機發現自己的SSx線被拉低,則表示主機要和它通訊了。對比IIC,SPI不需要外接上拉電阻,也不需要廣播地址來尋機。
3.SPI協議層
圖2 SPI 協議層訊號
SPI只有開始訊號,停止訊號,和資料有效性訊號,讀寫訊號(同步的)。相比IIC,少了應答機制。
(1)開始訊號:NSS被拉低的下降沿(SSx、CS。都叫做使能線,片選線。叫法很多,作用一樣 都是讓從機使能通訊)
(2)停止訊號:NSS被拉高的上升沿。
(3)觸發,轉移,一樣的意思。表示主機讀一位從機的資料,從機讀一位主機的資料。
(4)取樣,採集,讀取,一樣的意思,表示匯流排的上資料已就緒,可以讀了。取樣後,MISO、MOSI線上的資料被鎖存直到被轉移。
4.SPI的4種模式
4.1.極性和相位組合成4種模式
要說SPI的4種模式,就要先說一下兩個概念:時鐘極性CPOL和時鐘相位CPHA。CPOL和CPHA均有0 1兩種狀態,組合成4種狀態。
時鐘極性:時鐘極性 CPOL 是指 SPI 通訊裝置處於空閒狀態時,SCK 訊號線的電平訊號(即 SPI 通訊開始前、 NSS 線為高電平時 SCK 的狀態)。
CPOL=0 時, SCK 在空閒狀態時為低電平①,在SCK有效期間為高電平 ②
CPOL=1 時,SCK在空閒狀態時為高電平③,在SCK有效期間為低電平 ④
圖3 時鐘極性規定的空閒狀態的電平
時鐘相位:時鐘相位 CPHA 是指資料的取樣的時刻,
當 CPHA=0 時, MOSI 或 MISO 資料線上的訊號將會在 SCK 時鐘線的“奇數邊沿” 被取樣。
當 CPHA=1 時,資料線在 SCK 的“偶數邊沿” 取樣。
圖4 時鐘相位CPHA = 0時
當CPHA=0時,MOSI或MISO資料線上的訊號將會在SCK時鐘線的“奇數邊沿” 被取樣。根據時鐘極性的不同,奇數邊沿可能是上升沿也可能是下降沿。
可以看到,採集資料是邊沿觸發的,且沒有明確要求是上升沿還是下降沿。CPHA=0時,採集資料是在奇數邊沿,則轉換資料是在偶數邊沿。
圖5 時鐘相位 CPHA = 1時
當CPHA=1時,MOSI或MISO資料線上的訊號將會在SCK時鐘線的“偶數邊沿” 被取樣。根據時鐘極性的不同,奇數邊沿可能是上升沿也可能是下降沿。
可以看到 CPHA=1時,採集資料是在偶數邊沿,則轉換資料是在奇數邊沿。
關於幾個關鍵詞的描述:
(1)採集、取樣:當取樣時,主機要發給從機的資料已經在MOSI上了,從機要傳送給主機的資料已經在MISO上了。可以去讀取了。(什麼時候準備資料的,下面說)
(2)轉換:因為SPI是全雙工的,可以同時收發資料。主機在傳送出一位資料,就會接收到一位資料。在同一個時鐘週期同步轉換。
為什麼叫轉換?從下面圖6中看到,兩個裝置都有一個shift暫存器。比如當CPHA=0時,在第一個邊沿採集到了資料,在第二個邊沿轉換,
主機的shift暫存器的最高位移到了從機的shift暫存器的最低位。兩個暫存器都左移,迴圈8次。就能完成8位資料的交換,主機shift暫存器的資料都移到從記得shift暫存器裡面了。從機的也都移到主機裡了。(很巧妙 用互相轉移完成讀寫同步)
圖6 shift register
4.2.為什麼需要4種模式 以及什麼時候採集資料,什麼時候傳送資料
模式0:CPOL=0,CPHA =0 SCK空閒為低電平,資料在SCK的上升沿被取樣(提取資料) 模式1:CPOL=0,CPHA =1 SCK空閒為低電平,資料在SCK的下降沿被取樣(提取資料) 模式2:CPOL=1,CPHA =0 SCK空閒為高電平,資料在SCK的下降沿被取樣(提取資料) 模式3:CPOL=1,CPHA =1 SCK空閒為高電平,資料在SCK的上升沿被取樣(提取資料)
簡單;來說就是有些外設在被選中後(CS被拉低)就會把資料放到總線上,讓主機區讀。這個時候用CPHA=0模式。而有些在裝置傳送資料前需要一個SCK時鐘來啟用外設,外設在接收到第一個始終後才會把資料放到總線上。這個時候用CPHA=1模式。
CPHA=0時:主機從機給總線上準備資料,讀寫,轉移的過程(從摩托羅拉SPI協議4.4.2 翻譯過來的,大概翻譯,不完全)
(1)時鐘的第一個邊沿發生時,MOSI、MISO上的資料將被採集並被鎖存,在第一個時鐘邊沿發生之前,必須有個CS被拉低的訊號(裝置必須使能),從CS被拉低。到第一個時鐘邊沿發生,需要有個延時。為什麼需要延時?因為在CS被拉低到出現第一個邊沿這個過程中,被使能的從機裝置將會把自己的資料放在MISO上讓主機去讀。主機把自己的資料放在MOSI上讓從機去讀。
(2)當時鐘的第二個邊沿發生時,MISO、MOSI上被採集並鎖存的資料將會轉移。(交換一位,參考圖6)
(3)第二個時鐘沿發生後,從機的下一位資料將會被髮送到MISO上,主機上,我們需要主動把資料放在MOSI上。這個也就是說的在奇數邊沿採集,在偶數邊沿轉移。我們可以看到傳送8位資料,需要8個時鐘週期,16個時鐘邊沿。
(4)在第16個時鐘邊沿發生後,主機的shift暫存器和從機的shift暫存器的資料就完全交換了。
CPHA=1時:主機從機給總線上準備資料,讀寫,轉移的過程(從摩托羅拉SPI協議4.4.3 翻譯過來的,大概翻譯,不完全)
(1)在奇數數邊沿轉移,在偶數邊沿採集。按照權威的文件中說,有些裝置需要得到一個時鐘後才會把資料放到MISO線上。不像上面介紹的裝置一旦CS選中就發資料。
(2)這種裝置在第一個邊沿先轉移一下,用來啟用裝置,裝置才會把資料放到MISO線上。在第二個邊沿採集,又回到第一個邊沿轉移,裝置準備資料到MISO上,第二個邊沿採集,迴圈。
這裡還有點疑惑。先記錄一下吧。是不是隻第一次讀取從裝置的資料時需要一個時鐘啟用,啟用後,一旦發生轉移,從裝置的下一位資料就自動就緒了。可能是第一個時鐘轉移(啟用),轉移後自動準備下一位資料。我覺得可能是第二種,只要一個時鐘啟用就可以了。第一個時鐘啟用,第一個時鐘轉移,那轉移一次資料,從裝置就會被啟用。
4.3 什麼時候用哪種模式?
時鐘相位CPHA = 0。這種模式適合那種從裝置一旦被片選後就輸出資料到MISO線上。
時鐘相位CPHA = 0。這種模式適合那種從裝置被片選後還需要一個時鐘才能 輸出資料到MISO線上。
4.4軟體模擬
轉自內陸的鹹水魚
1 /* CPOL = 0, CPHA = 0, MSB first */ 2 uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat ) 3 { 4 uint8_t i, read_dat; 5 for( i = 0; i < 8; i++ ) 6 { 7 if( write_dat & 0x80 ) 8 MOSI_H; 9 else 10 MOSI_L; 11 write_dat <<= 1; 12 delay_us(1); 13 SCK_H; 14 read_dat <<= 1; 15 if( MISO ) 16 read_dat++; 17 delay_us(1); 18 SCK_L; 19 __nop(); 20 } 21 22 return read_dat; 23 } 24 25 26 /* CPOL=0,CPHA=1, MSB first */ 27 uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) 28 { 29 uint8_t i,Temp=0; 30 31 for(i=0;i<8;i++) // 迴圈8次 32 { 33 SCK_H; //拉高時鐘 34 if(byte&0x80) 35 { 36 MOSI_H; //若最到位為高,則輸出高 37 } 38 else 39 { 40 MOSI_L; //若最到位為低,則輸出低 41 } 42 byte <<= 1; // 低一位移位到最高位 43 delay_us(1); 44 SCK_L; //拉低時鐘 45 Temp <<= 1; //資料左移 46 47 if(MISO) 48 Temp++; //若從從機接收到高電平,資料自加一 49 delay_us(1); 50 51 } 52 return (Temp); //返回資料 53 } 54 55 /* CPOL=1,CPHA=0, MSB first */ 56 uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) 57 { 58 uint8_t i,Temp=0; 59 60 for(i=0;i<8;i++) // 迴圈8次 61 { 62 if(byte&0x80) 63 { 64 MOSI_H; //若最到位為高,則輸出高 65 } 66 else 67 { 68 MOSI_L; //若最到位為低,則輸出低 69 } 70 byte <<= 1; // 低一位移位到最高位 71 delay_us(1); 72 SCK_L; //拉低時鐘 73 Temp <<= 1; //資料左移 74 75 if(MISO) 76 Temp++; //若從從機接收到高電平,資料自加一 77 delay_us(1); 78 SCK_H; //拉高時鐘 79 80 } 81 return (Temp); //返回資料 82 } 83 84 85 /* CPOL = 1, CPHA = 1, MSB first */ 86 uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat ) 87 { 88 uint8_t i, read_dat; 89 for( i = 0; i < 8; i++ ) 90 { 91 SCK_L; 92 if( write_dat & 0x80 ) 93 MOSI_H; 94 else 95 MOSI_L; 96 write_dat <<= 1; 97 delay_us(1); 98 SCK_H; 99 read_dat <<= 1; 100 if( MISO ) 101 read_dat++; 102 delay_us(1); 103 __nop(); 104 } 105 return read_dat; 106 } 107
參考資料
文中圖片來自野火資料
軟體模擬SPI介面程式程式碼(4種模式) https://blog.csdn.net/zwj695535100/article/details/107303648/
摩托羅拉SPI匯流排協議規範 https://wenku.baidu.com/view/eb052d1289eb172dec63b700.html(4.4章節)