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章節)