I2C (Inter-Integrated Circuit)
I2C 是 I2C Bus簡稱,也就是 Inter-Integrated Circuit Bus,也就是在 IC 之間的匯流排,使得 IC 跟 IC 可以通訊。
I2C 是一種串列通訊匯流排,使用多主從架構,由飛利浦公司在1980年代為了讓主機板、嵌入式系統或手機用以連接低速週邊裝置而發展。
I2C 使用兩條雙向漏極開路(Open Drain)線,如下:
1, SDA (Serial DAta line): 傳輸資料。
2, SCL (Serial CLock line): 啟動或停止傳輸以及傳送時鐘序列。
下圖為 I2C 線路範例,由兩個 master/slave 裝置 及兩個 slave 裝置組成,並搭配使用上拉電阻:

可以看到 SDA 及 SCL 都是雙向的。
I2C 的線路圖範例為:

在線路圖中,可以看到 SCL 是單向的,表示這個 I2C slave 裝置無法控制 SCL,也就是沒有支援 時脈擴展(clock stretching) 的功能。
I2C 的操作原理
I2C bus上的訊號邏輯有以下規則:
1、I2C bus 為 idle high,也就是當 bus 上沒有任何活動時,SCL 和 SDA 都維持在 high。
2、SCL 為 high 時,表示 SDA 上的資料為有效(Data Validity),此時 SDA 的狀態不能改變,以確保接收方可以取樣到正確的 SDA 狀態。
3、SCL 為 low 時,SDA 的狀態可以改變。

4、當 SCL 為 high 時,如果 SDA 變動,有兩種特殊狀況:
4-1、SCL high、SDA 下降代表 START 時序狀態。
4-2、SCL high、SDA 上升代表 STOP 時序狀態。

每一個 8-bit(I2C是以1-byte為單位傳送data) 的資料傳輸結束後,會跟著一個 acknowledge bit(第9個bit)。這個 acknowledge bit 固定由接收方產生,有兩種用法:

當 master 是傳送方(Transmitter)、slave 是接收方(Receiver),也就是說這個傳輸是 master 寫入資料到 slave 時,這個 acknowledge bit 是用來讓 slave 告訴 master「收到!了解!正確!」
當 master 是接收方、slave 是傳送方,也就是說這個傳輸是 master 從 slave 讀取資料時,這個 acknowledge bit 是用來讓 master 告訴 slave「我還要接著讀,請繼續準備下一筆資料」或者是「夠了,我讀完了」。
傳送方會在 ACK 的 SCL 時脈釋放 SDA 線(SDA 為 high),如果接收方正常收到 data 的話,會在第 9 個 bit 將 SDA 拉 low,也就是回應 ACK。
如果接收方有任何狀況,或是 bus 上面根本就沒有那個 address 的 slave 裝置,到了第 9 個 SCL 週期時,當傳送方釋放 SDA 後,就沒有人去驅動 SDA,這時 SDA 就會因為上拉電阻(Rp)的關係維持在 high,如此一來,傳送方就知道出問題了,不會繼續接下來的傳輸,而要進行錯誤處理,這種情況稱之為「non-acknowledge」,或簡稱為「NACK」。
I2C的傳輸流程
Slave Address
I2C 是一個多裝置的 bus,因此每當 master 發起傳輸時,它得先點名,就像老師叫特定座號的同學回答問題一樣,而這個座號就是 Slave的 address。在最早的 I2C 規格中,I2C address 是 7-bit,同一個 bus 上不可以有兩個 address 一樣的 slave 裝置,因此 I2C bus 上最多可以有 128 個 slave 裝置,實務上有一些 address 是保留的不能使用,因此可用的數量會比 128 略少一點;至於 master,它沒有、也不需要 address,因為沒有人會點名老師起來回答問題。因此所有的 I2C 傳輸週期,第一個 byte 都是用來點名的,它的內容就是被點到裝置的 address。

伴隨著 7 個 bit 的 slave address 而來的第 8 個 bit,則是一個表示讀或寫的 bit,0 是寫入、1 是讀取;其中點名的 byte 永遠是寫入,因此在 slave address 後的 R/W bit 的值一定是 0。
寫入(Write)實例
I2C master 用 START 狀態發起傳輸後,接著是 slave address 以及 R/W bit,因爲這時是寫入 slave,因此 R/W bit 是 0,到了第 9 個 bit 時,傳輸方向會換過來,變成由 slave 向 master 傳送 acknowledge bit。

Master 收到 acknowledge 後,就會繼續切換 SCL,並在每一個 SCL 爲 high 的脈波週期中,依序送出資料的每一個 bit,總共 8 個 bit。
一樣到了第 9 個 bit 時,傳輸方向會換過來。Master 會在 SCL 變成 high 的第 9 個時脈週期中,放掉 SDA 不去驅動它(SDA 為 high),並監聽來自 slave 的狀態;如果 slave 在此時有把 SDA 驅動到 low,就代表 slave 有正確地收到了這個 byte 的資料傳輸。
最後,master 送出 STOP 狀態結束這一回合的傳輸,成功寫入 1 個 byte 的資料到 slave。
在寫入週期中,只要 master 沒有送出 STOP 狀態,而是持續不斷地切換 SCL 並將資料送出,就會變成一個連續寫入 data 的傳輸。

至於可以連續寫入多少筆資料,則要看 slave 這邊晶片的設計,當寫入太多筆資料,超過 slave 可以允許的範圍,它就會發 NACK 喊停,告訴 master 不要再寫了。
讀取(Read)實例
讀取和寫入流程類似,I2C master 用 START 狀態發起傳輸後,接著是填寫 slave address 以及 R/W bit,因爲這時是讀取 slave,所以 R/W bit 是 1,到了第 9 個 bit 時,傳輸方向會換過來,變成由 slave 向 master 傳送 acknowledge bit,之後就是 slave 向 master 傳送 data,當 master 讀完後,會發 ACK=0 告訴 slave 收到 data 了。

在連續讀取時,只要後面還會繼續讀,master 就要送出 ACK=1 的 acknowledge bit 告訴 slave 要準備提供接下來的資料,只有當後面不再讀取而接著 STOP 狀態時,ACK 才會是 0。

實例分析
下圖是一個典型的 I2C 波形:

在 SCL 為 high 時,SDA 從 high 變為 low,代表 START 時序狀態。
後續的 I2C 波型,直接讀取結果為:0b 1011 1010 0 1000 0001 0。
可以分為 4 個步驟來解讀:
1、其中前八個位元 0b 1011 1010,表示 8-bit slave address 為 0b 1011 1010 = 0xba。
進一步分析,前 7-bit 為此 I2C slave 裝置的 7-bit slave address,也就是 0b 1011 1010 >> 1 = 0b 0101 1101 = 0x5d。
而第 8 bit 為,R/W bit,其值為為 0,表示為寫入(write)。
2、後邊緊跟着的 0b 0 ,表示 slave 裝置回應 ACK,表示該 slave 裝置存在。
3、接著的八個位元 0b 1000 0001,為要寫入的數據 0b 1000 0001。
4、最後緊跟着的 0b 0 表示 slave 裝置回應 ACK,表示該 slave 裝置已有收到數據。
以目前的測量經驗來看,如果 I2C 的頻率為 100K,則 I2C 的單位間隔時間可以設為 20 us,如此可以輕鬆觀察到 I2C Data 及 I2C Clock 搭配下,所傳送的訊息內容。
以頻率為 100k 來看,每個 I2C 週期為 1 / 100000 s = 0.00001 s = 0.01 ms = 10 us。
在 linux 上,常使用的 i2c 指令有: i2cdetect, i2cget, i2cset, i2cdump, i2ctransfer,可以參考以下文章:
Linux 的 I2C 指令
時脈擴展 (clock stretching)
時脈擴展是用來讓 slave 裝置在忙不過來時,可以通知 master 暫時停止傳送資料的方法。
要注意的是,此功能只有在 I2C master 及 slave 同時都有支援 clock stretching 的情況下,才能順利運作。
在一個正常的 I2C 傳輸週期中,SCL 會穩定地由 master 產生。
當 SCL 爲 low 時,SDA 的狀態可以變化;當 SCL 爲 high 時,SDA 的狀態必需維持穩定不變,以便接收方可以在 SCL 爲 high 的這段時間中偵測、取樣 SDA 的狀態。
如果 slave 在接收資料的過程中,覺得忙不過來,需要暫停接收資料,它就會驅動 SCL,把 SCL 拉到 low 的狀態。
slave 藉由拉住 SCL 讓它不要變成 high,而 master 在放掉 SCL 後,會監控 SCL,如果發現 SCL 持續為 low,此時,master 會暫停發送資料,並持續監控 SCL,直到 SCL 為 high 時,才繼續發送資料。
如此,slave 就可以有多餘的時間處理 master 送過來的資料或是進行內部的其他工作,直到 slave 有能力繼續接收 master 傳來的資料時,它才會放掉 SCL,讓它變成 high,並進入下一個 bit 的讀取週期。
I2C 在 SCL 及 SDA 的訊號上,都有一樣的特性,而 clock stretching 就是利用這個 SCL 的這個特性來實作的:
1,只有當所有的裝置都輸出 high 時,bus 上的狀態才會是 high。
2,只要有任何一個裝置輸出 low,bus 上的狀態就會是 low。
I2C 匯流排上可以有多個 master (multi-master I2C-bus interface)
I2C 匯流排具備了匯流排仲裁能力, 因此 I2C 匯流排上可以有多個 master。
要具備仲裁能力的最基本作法是 master 要能避免干擾別人,因此所有的 I2C master 都需要監聽匯流排上的 start 訊號及 stop 訊號。
當一個 master 要產生 START condition 時,它一定會先確認 bus 上面有沒有別人在傳送資料。
雖然「先確認再傳送」的策略大概可以避免 99% 以上的同時傳送、互相打斷的問題,但總是有意外,比如兩個 master 剛好同時要送資料。
真正使 I2C 匯流排具備 multi-master 能力的是下列的二個機制:
1,時脈同步 (SCL Synchronization)
一個 bus 上的兩個 master 之間是完全不會有任何互相關聯的 clock source,不管是頻率、相位,兩者之間都不會有關聯。
時脈同步就是爲了讓多個 master 之間至少用同樣速度、同步的 clock 來發送資料。
同步時脈的機制為:
當 SCL 從 high 變 low 時,這一回合想在 bus 上傳送資料的所有 master 就會開始利用 SCL 的 low counter 來計算 SCL low 的長度。
等到最慢的裝置終於放掉 SCL 時,整個 bus 的 SCL 變爲 high,此時 SCL low 的長度計算完成,開始計算 SCL 爲 high 的時間。
同樣地,即使不同的裝置有快有慢,但由於 wired-AND 電路的特性,只要有任何一個裝置把 SCL 拉低,大家就會同時收到 SCL 變低的狀態,這時 SCL 爲 high 的時間就結束了。
藉由以上這一個週期,每個裝置內的 SCL low counter 和 high counter 都會變成一樣的長度,也就是 low 的話是採用最慢的那個週期,high 的時間是採用最快的那個週期。
有了一致的 clock,大家傳送的 data bits 才對得齊,才能有接下來的仲裁機制。
2,匯流排仲裁 (Bus Arbitration)
每個經過時脈同步 master 在傳送資料時,除了照著 SCL 的節奏去驅動 SDA 外,同時也會逐個 bit 監聽 SDA 上的狀態。
如果 SDA 上的狀態與它驅動 SDA 的狀態不符,它就知道有其它 master 在傳送資料,並中止繼續傳送資料,也就是說先把 SDA 拉 high 的 master 需要自行中止繼續傳送資料。
如果兩個 master 同時要對同一個 slave 執行同樣的動作,那麼在第一個 byte 這個回合中就分不出勝負,仲裁會繼續進行到下一個 byte,直到比出結果。
Reference
Serial Buses Comparison: JTAG, SPI, and I2C
I2C bus 簡介 (Inter-Integrated Circuit Bus)
