邊緣系統VLM視覺理解推論實作工作坊
|
View Categories

I2C 界面解密 — PART 2

閱讀時間: 3 min read

作者:Bird

上一回【Maker電子學】I2C 界面解密 — PART 1,我們聊了 I2C(以下寫為 I2C)界面的發展歷史,以及它的實體層訊號格式,這一次我們要進入 I2C 通訊邏輯的底層,來看看它在這個只有兩根線的 Wired-AND 線路上,是利用什麼樣的邏輯訊號進行通訊。

八位元時代的痕跡 #

I2C 和 SPI 一樣,都是在 8-bit CPU 當道的年代發展出來的東西,因此它的傳輸單位和 SPI 相同,都是以 byte 為單位。每一次 I2C 的傳輸可以包含很多個 bytes,但它最基本的單位就是 byte,每一個 byte 的後面會附加一個額外的 bit,稱為「acknowledge bit」,它是接收方用來通知傳送方「是的,我收到前面這個 byte 的資料了」或是「好了!夠了!別再送資料了」。大部分的 acknowledge bit 都屬於第一種狀況,只有少部分的通訊方式會用到第二種,我們之後說明通訊協定時會再詳述。

除了資料外,I2C bus 上還有另外兩種狀態,分別稱之為「start」和「stop」,用來指示傳輸的開始與結束。I2C 是 master/slave 的結構,所有的通訊只能由 master 發起,但由於 I2C 允許 bus 上可以有多個 master,而為了避免這些 master 們同時發起傳輸而打架,start 和 stop 便成為它們之間溝通協調的重要機制。

基本時序 #

下圖是 I2C 傳輸一個 byte 時的典型時序圖:

(圖片來源:Bird 提供)

I2C bus 上的邏輯訊號有幾個原則:

  1. I2C bus 為 idle high:當 bus 上沒有任何活動時,SCL 和 SDA 都維持在 high
  2. SCL 為 high 時,表示 SDA 上的資料為有效,此時 SDA 的狀態不能改變,以確保接收方可以取樣到正確的 SDA 狀態
  3. SCL 為 low 時,SDA 的狀態可以改變
  4. 當 SCL 為 high 時,如果 SDA 變動,有兩種特殊狀況:SCL high、SDA 下降—START;SCL high、SDA 上升—STOP

因為 I2C bus 為 idle high,當一個 master 要發起傳輸時,它會先把 SDA 拉到 low,而 SCL 維持不變,這時,根據上面的第 4 個原則,這是一個 START 狀態,也就是用來通知 bus 上的其它裝置,有一個傳輸要開始了。

接下來,master 會開始切換 SCL 訊號,在 SCL 上造出連續 8 個方波。根據上面的第 2 個和第 3 個原則,當 SCL 為 low 時,master 會變動 SDA 的狀態,以便讓要傳送的資料出現在 SDA 上,而當 SCL 為 high 時,SDA 的狀態就會保持不動,以便接收方讀取到 SDA 的狀態。

至於接收方會在什麼時候讀取到 SDA 的狀態呢?它可以在 SCL 為 high 時的任何一個時刻去讀取 SDA。對,就是整段 SCL 為 high 時,那一段 SCL 平平的時間,接收方都可以讀取 SDA,如下圖所示:

(圖片來源:Bird 提供)

說到這裡,大家有沒有覺得有件事怪怪的?一般用 clock 訊號控制通訊時,資料取樣的時間都規定在 clock 的上升緣或下降緣的那一瞬間,就像我們之前聊過,SPI 在 CPOL = 0 時,會在 clock 的上升緣讀取 MISO/MOSI 上的狀態(它其實也只有在 clock 變化時取樣的那一瞬間,加上前面一點點的 setup time、後面一點點的 hold time 保持不變,時間非常短暫)。

但 I2C 的資料取樣看起來卻非常隨性,只要在 SCL 為 high 的期間,接收方都可以讀取 SDA,沒人管你在這段時間中的哪一個 moment 讀取,反正根據前面的第 2 個原則,在這段時間內 SDA 不能變動,不管哪個 moment 讀取,都應該要讀到一樣的結果。

像 SPI 那樣利用 clock 訊號的邊緣取樣的系統,稱之為同步(synchronous)的通訊系統,這種系統因為有明確的資料取樣點,要設計成較高速的傳輸系統相對來說較為容易;相對來說,I2C bus 上的 SCL 訊號沒有那麼像同步通訊系統中的 clock,反而比較像邏輯的狀態訊號,用來指示接收方「現在可以取樣」或「現在不能取樣」以及「現在是特別狀態的 START 或 STOP」。

因此嚴格來說,I2C 並不是一個同步的通訊系統,其 SCL 訊號的工作方式也和一般通訊系統中的 clock 訊號不太一樣(儘管它還是稱為 clock),這樣的設計雖然造成日後 I2C 要升級到高速版本時的困難,但當年飛利浦半導體這麼設計是有它的目的的,我們之後談到通訊協定的細節時會再詳細說明。

很重要的 Acknowledge #

每一個 8-bit 的資料傳輸結束後,會跟著一個 acknowledge bit。這個 acknowledge bit 固定由接收方產生,有兩種用法:

  1. 當 master 是傳送方、slave 是接收方,也就是說這個傳輸是 master 寫入資料到 slave 時,這個 acknowledge bit 是用來讓 slave 告訴 master「收到!了解!正確!」
  2. 當 master 是接收方、slave 是傳送方,也就是說這個傳輸是 master 從 slave 讀取資料時,這個 acknowledge bit 是用來讓 master 告訴 slave「我還要接著讀,請繼續準備下一筆資料」或者是「夠了,我讀完了」。

為什麼會有這樣的差別呢?因為 I2C 的傳輸都是由 master 發起的!如果接收方是 slave,那麼 master 可以藉由讀取這個 acknowledge bit 來知道 slave 有沒有收到資料,進而決定下一步的動作;如果傳輸的過程中發生錯誤,導致 slave 沒有收到資料時,master 就可以先結束這一個傳送,重新來過,或是要回報錯誤什麼的。

但如果接收方是 master,也就是這是一個 master 對 slave 的讀取週期,master 在收到資料後對 slave 發送 acknowledge 其實沒有什麼意義,因為就算 master 沒有收到 slave 送來的資料,slave 也不能做什麼,整個傳輸的控制權還是掌握在 master 手上,因此在 master 對 slave 的讀取週期中,acknowledge bit 並不是用來 acknowledge,而是 master 用來通知 slave 是否需要準備下一筆資料。

Acknowledge bit 的狀態定義是:low 或者 0 是「好、OK、收到、請繼續」;high 或者 1 則是「出錯了、沒有人在家、不要繼續」。

用 Address 點名 #

I2C 是一個多裝置的 bus,因此每當 master 發起傳輸時,它得先點名,就像老師叫特定座號的同學回答問題一樣,而這個座號就是我們上次提過的 I2C address。在最早的 I2C 規格中,I2C address 是 7-bit,同一個 bus 上不可以有兩個 address 一樣的 slave 裝置,因此 I2C bus 上最多可以有 128 個 slave 裝置,實務上有一些 address 是保留的不能使用,因此可用的數量會比 128 略少一點(另外,I2C 還有一種 10-bit address 的模式,我們後面講協定的時候再詳述);至於 master,它沒有、也不需要 I2C address,因為沒有人會點名老師起來回答問題。

因此所有的 I2C 傳輸週期,第一個 byte 都是用來點名的,它的內容就是被點到裝置的 address。

(圖片來源:Bird 提供)

而伴隨著 7 個 bit 的 slave address 而來的第 8 個 bit,則是一個表示讀或寫的 bit,0 是寫入、1 是讀取;其中點名的 byte 永遠是寫入,因此在這裡 R/W bit 的值一定是 0。

當我們要和一個 I2C 裝置通訊時,首先得知道它的 I2C address,才能送出正確的點名 byte,但當我們查閱裝置晶片的資料時,常常會有個容易搞混的狀況,比方說一個晶片的 I2C address 是 0x20(二進位的 00100000),如果這個 0x20 叫做「7-bit I2C address」,就代表 0x20 佔據的是上圖的 bit 1 到 bit 7,如果再加上一個為 0 的 R/W bit,實際上要送出的資料就會是 0x40,也就是二進位 0100000 後面再加一個 0。

但如果這個 0x20 叫做「8-bit I2C address」,就代表它已經包含了那個 R/W bit,因此當你要點名寫入時,就直接送 0x20,而要點名讀取時,則要把最後一個 bit 變成 1,稱為 0x21。

至於 IC 的 datasheet 上寫的地址到底是 7-bit address 還是 8-bit address 呢?通常它會寫明白,但偶爾會遇到一些寫得不清不楚的 datasheet,就需要一些智慧來理解了。

當 master 在點名時,它會一邊切換 SCL 訊號,一邊送出 8 個 bit 的點名地址,在第 8 個 bit 的 SCL 週期結束後,master 會把 SDA 設成 high,這時候就輪到 slave 表演了。我們上次說過,以 Wired-AND 方式接在一起的 I2C bus,當輸出 high 時,其實就是放手不去驅動 bus,此時 slave 如果有正確收到前面送來的點名 byte,它就會在第 8 個 SCL 週期結束後(SCL 變為 low 時),開始驅動 SDA,將 SDA 拉到 low;而 master 則會在 SCL 進入第 9 個 high 週期時,去讀取 SDA 的狀態,看看 slave 有沒有把 SDA 拉下來,如果有的話,就代表點名成功,可以繼續下面的傳輸。

如果 slave 有任何狀況,或是 bus 上面根本就沒有那個 address 的 slave 裝置,到了第 9 個 SCL 週期時,當 master 放掉 SDA 後,就沒有人去驅動 SDA,這時 SDA 就會因為 pull-up 電阻的關係維持在 high,如此一來,master 就知道出問題了,不會繼續接下來的傳輸,而要進行錯誤處理,這種情況稱之為「non-acknowledge」,或簡稱為「NAK」。

小結 #

以上就是 master 在 I2C bus 上發起傳輸的第一個步驟:點名。接下來根據要寫入或讀取的方式不同,會有一些不同的傳輸協定和狀態,我們下一回再繼續探討接下來的協定。

(責任編輯:賴佩萱)

Powered by BetterDocs

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *