1. 程式人生 > 實用技巧 >SPI介紹+軟體模擬SPI

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時,MOSIMISO資料線上的訊號將會在SCK時鐘線的“奇數邊沿” 被取樣。根據時鐘極性的不同,奇數邊沿可能是上升沿也可能是下降沿。

可以看到,採集資料是邊沿觸發的,且沒有明確要求是上升沿還是下降沿。CPHA=0時,採集資料是在奇數邊沿,則轉換資料是在偶數邊沿。

  圖5 時鐘相位 CPHA = 1時

CPHA=1時,MOSIMISO資料線上的訊號將會在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章節)

https://www.cnblogs.com/fedorayang/p/8564792.html

https://www.sohu.com/a/270796067_288206