簡介
I2C(Inter-integrated Circuit)總線支持設備之間的短距離通訊,用於處理器和一些外圍設備之間的接口,它只須要兩根信號線來完成信息交換。I2C最先是飛利浦在1982年開發設計並用於本身的芯片上,一開始只容許100kHz、7-bit標準地址。1992年,I2C的第一個公共規範發行,增長了400kHz的快速模式以及10-bit擴展地址。在I2C的基礎上,1995年Intel提出了「System Management Bus」 (SMBus),用於低速設備通訊,SMBus 把時鐘頻率限制在10kHz~100kHz,但I2C能夠支持0kHz~5MHz的設備:普通模式(100kHz即100kbps)、快速模式(400kHz)、快速模式+(1MHz)、高速模式(3.4MHz)和超高速模式(5MHz)。異步
與串行端口、SPI對比
串行端口
串行端口是異步的(不傳輸時鐘相關數據),兩個設備在使用串口通訊時,必須先約定一個數據傳輸速率,而且這兩個設備各自的時鐘頻率必須與這個速率保持相近,某一方的時鐘頻率相差很大都會致使數據傳輸混亂。
異步串行端口在每一個數據幀中都要插入至少一個起始位和一個終止位,意味着每傳輸8bits的數據實際要花費10bits的傳輸時間,從而下降了數據傳輸速率。
另外一個問題是異步串行端口的設計就是針對兩個設備之間通訊的,那麼若是有多個設備鏈接到一個串口上,就必須解決信號碰撞的問題(bus contention),一般要經過額外硬件來完成。
最後就是數據傳輸速率,異步串行通訊並無一個理論上的速率限制,大部分UART設備只支持一些特定的波特率,最高一般在230400bps左右。ui
SPI
SPI最明顯的缺點就是引腳數量,使用SPI總線相連的一個master和一個slave須要四根線(MISO/MOSI/SCK/CS),每增長一個slave,就須要在master上增長一個CS引腳。當一個master接多個slaves的時候,瘋狂增加的引腳鏈接是難以忍受的,而且對緊湊的PCB layout是一個挑戰。
SPI總線上只容許有一個master,但能夠有任意多個slaves(只受限於總線上設備的驅動程序的能力,以及設備上最多能有多少個CS引腳)。
SPI能夠很好的用於高速率全雙工的鏈接,對一些設備可支持高達10MHz(10Mbps)的傳輸速率,所以SPI吞吐量大得多。SPI兩端的設備一般是一個簡單的移位寄存器,讓軟件的實現很簡單。設計
I2C
I2C最少只須要兩根線,和異步串口相似,但能夠支持多個slave設備。和SPI不一樣的是,I2C能夠支持mul-master系統,容許有多個master而且每一個master均可以與全部的slaves通訊(master之間不可經過I2C通訊,而且每一個master只能輪流使用I2C總線)。master是指啓動數據傳輸的設備並在總線上生成時鐘信號以驅動該傳輸,而被尋址的設備都做爲slaves。 blog
I2C的數據傳輸速率位於串口和SPI之間,大部分I2C設備支持100KHz和400KHz模式。使用I2C傳輸數據會有一些額外消耗:每發送8bits數據,就須要額外1bit的元數據(ACK或NACK)。I2C支持雙向數據交換,因爲僅有一根數據線,故通訊是半雙工的。
硬件複雜度也位於串口和SPI之間,而軟件實現能夠至關簡單。接口
I2C協議
I2C協議把傳輸的消息分爲兩種類型的幀:
一個地址幀 —— 用於master指明消息發往哪一個slave;
一個或多個數據幀 —— 由master發往slave的數據(或由slave發往master),每一幀是8-bit的數據。
注:協議要求每次放到SDA上的字節長度必須爲8位,而且每一個字節後須跟一個ACK位,在下面會講到。
數據在SCL處於低電平時放到SDA上,並在SCL變爲高電平後進行採樣。讀寫數據和SCL上升沿之間的時間間隔是由總線上的設備本身定義的,不一樣芯片可能有差別。
I2C數據傳輸的時序圖以下: 開發
開始條件(start condition):
爲了標識傳輸正式啓動,master設備會將SCL置爲高電平(當總線空閒時,SDA和SCL都處於高電平狀態),而後將SDA拉低,這樣,全部slave設備就會知道傳輸即將開始。若是兩個master設備在同一時刻都但願得到總線的全部權,那麼誰先將SDA拉低,誰就贏得了總線的控制權。在整個通訊期間,能夠存在多個start來開啓每一次新的通訊序列(communication sequence),而無需先放棄總線的控制權,後面會講到這種機制。
地址幀(address frame):
地址幀老是在一次通訊的最開始出現。一個7-bit的地址是從最高位(MSB)開始發送的,這個地址後面會緊跟1-bit的操做符,1表示讀操做,0表示寫操做。
接下來的一個bit是NACK/ACK,當這個幀中前面8bits發送完後,接收端的設備得到SDA控制權,此時接收設備應該在第9個時鐘脈衝以前回復一個ACK(將SDA拉低)以表示接收正常,若是接收設備沒有將SDA拉低,則說明接收設備可能沒有收到數據(如尋址的設備不存在或設備忙)或沒法解析收到的消息,若是是這樣,則由master來決定如何處理(stop或repeated start condition)。
數據幀(data frames):
在地址幀發送以後,就能夠開始傳輸數據了。Master繼續產生時鐘脈衝,而數據則由master(寫操做)或slave(讀操做)放到SDA上。每一個數據幀8bits,數據幀的數量能夠是任意的,直到產生中止條件。每一幀數據傳輸(即每8-bit)以後,接收方就須要回覆一個ACK或NACK(寫數據時由slave發送ACK,讀數據時由master發送ACK。當master知道本身讀完最後一個byte數據時,可發送NACK而後接stop condition)。
中止條件(stop condition):
當全部數據都發送完成時,master將產生一箇中止條件。中止條件定義爲:在SDA置於低電平時,將SCL拉高並保持高電平,而後將SDA拉高。
注意,在正常傳輸數據過程當中,當SCL處於高電平時,SDA上的值不該該變化,防止意外產生一箇中止條件。
重複開始條件(repeated start condition):
有時master須要在一次通訊中進行屢次消息交換(例如與不一樣的slave傳輸消息,或切換讀寫操做),而且期間不但願被其餘master干擾,這時可使用「重複開始條件」 —— 在一次通訊中,master能夠產生屢次start condition,來完成屢次消息交換,最後再產生一個stop condition結束整個通訊過程。因爲期間沒有stop condition,所以master一直佔用總線,其餘master沒法切入。
爲了產生一個重複的開始條件,SDA在SCL低電平時拉高,而後SCL拉高。接着master就能夠產生一個開始條件繼續新的消息傳輸(按照正常的7-bit/10-bit地址傳輸時序)。重複開始條件的傳輸時序以下圖所示:
時鐘拉伸(clock stretching):
有時候,低速slave可能因爲上一個請求還沒處理完,尚沒法繼續接收master的後續請求,即master的數據傳輸速率超過了slave的處理能力。這種狀況下,slave能夠進行時鐘拉伸來要求master暫停傳輸數據 —— 一般時鐘都是由master提供的,slave只是在SDA上放數據或讀數據。而時鐘拉伸則是slave在master釋放SCL後,將SCL主動拉低並保持,此時要求master中止在SCL上產生脈衝以及在SDA上發送數據,直到slave釋放SCL(SCL爲高電平)。以後,master即可以繼續正常的數據傳輸了。可見時鐘拉伸其實是利用了時鐘同步的機制(見下文),只是時鐘由slave產生。
若是系統中存在這種低速slave而且slave實現了clock stretching,則master必須實現爲可以處理這種狀況,實際上大部分slave設備中不包含SCL驅動器的,所以沒法拉伸時鐘。
因此更完整的I2C數據傳輸時序圖爲: 同步
10-bit地址空間:
上面講到I2C支持10-bit的設備地址,此時的時序以下圖所示: it
在10-bit地址的I2C系統中,須要兩個幀來傳輸slave的地址。第一個幀的前5個bit固定爲b11110,後接slave地址的高2位,第8位仍然是R/W位,接着是一個ACK位,因爲系統中可能有多個10-bit slave設備地址的高2bit相同,所以這個ACK可能由多有slave設備設置。第二個幀緊接着第一幀發送,包含slave地址的低8位(7:0),接着該地址的slave回覆一個ACK(或NACK)。
注意,10-bit地址的設備和7-bit地址的設備在一個系統中是能夠並存的,由於7-bit地址的高5位不多是b11110。實際上對於7-bit的從設備地址,合法範圍爲b0001XXX-b1110XXX,’X’表示任意值,所以該類型地址最多有112個(其餘爲保留地址[1])。
兩個地址幀傳輸完成後,就開始數據幀的傳輸了,這和7-bit地址中的數據幀傳輸過程相同。io
時鐘同步和仲裁
若是兩個master都想在同一條空閒總線上傳輸,此時必須可以使用某種機制來選擇將總線控制權交給哪一個master,這是經過時鐘同步和仲裁來完成的,而被迫讓出控制權的master則須要等待總線空閒後再繼續傳輸。在單一master的系統上無需實現時鐘同步和仲裁。ast
時鐘同步
時鐘同步是經過I2C接口和SCL之間的線「與」(wired-AND)來完成的,即若是有多個master同時產生時鐘,那麼只有全部master都發送高電平時,SCL上才表現爲高電平,不然SCL都表現爲低電平。
總線仲裁 總線仲裁和時鐘同步相似,當全部master在SDA上都寫1時,SDA的數據纔是1,只要有一個master寫0,那此時SDA上的數據就是0。一個master每發送一個bit數據,在SCL處於高電平時,就檢查看SDA的電平是否和發送的數據一致,若是不一致,這個master便知道本身輸掉仲裁,而後中止向SDA寫數據。也就是說,若是master一直檢查到總線上數據和本身發送的數據一致,則繼續傳輸,這樣在仲裁過程當中就保證了贏得仲裁的master不會丟失數據。 輸掉仲裁的master在檢測到本身輸了以後也再也不產生時鐘脈衝,而且要在總線空閒時才能從新傳輸。 仲裁的過程可能要通過多個bit的發送和檢查,實際上兩個master若是發送的時序和數據徹底同樣,則兩個master都能正常完成整個的數據傳輸。