作者:Bird
這是 I2C(以下寫作 I2C)界面系列文章的最後一回,我們要來聊一下 I2C bus 的準位轉換(level shifting),也就是如何連接不同邏輯準位的 I2C bus,讓它們可以一起工作。
準位轉換的難題 #
典型的單向邏輯位準轉換電路長這樣:

(圖片來源:Bird 提供)
這種電路利用兩個各自適合來源、目標邏輯準位電壓的 buffer,來連接兩側的電路;而另外一種雙向的邏輯準位轉換電路,則需要多一個方向的控制訊號,來告訴轉換器要往哪一個方向轉換:

(圖片來源:Bird 提供)
上面兩顆 buffer 在 DIR 訊號爲 high 時會啓動,因此轉換的方向是由 A 到 B。下面兩顆 buffer 的 enable 訊號上有一顆小圓圈,代表它是負邏輯,也就是在 DIR 訊號爲 low 時才啓動,轉換方向 由 B 到 A,因此 DIR 可以用來控制這個電路的轉換與驅動方向。
但以上兩種位準轉換電路,都無法適用在 I2C bus 上。I2C bus 中並沒有一個訊號明確地指出 bus 的驅動方向,對每一個裝置來說,SCL 和 SDA 訊號隨時都有可能是輸入或輸出,瞬息萬變。
舉例來說,對 master 裝置來說,當它送完 START condition 以及接下來 8 個 bits 的 slave address 後,SDA 就會在第 9 個 SCL 週期變爲輸入,用來接收 slave 裝置傳來的 ACK bit;而 SCL 訊號雖然始終都是由 master 裝置送出,但事實上它在每一個 clock 送出後,都會持續監聽 SCL,看看有沒有 slave 裝置發出 clock stretching(忘了什麼是 clock stretching 的讀者,可以回頭翻一下【Maker電子學】I2C 界面解密 — PART 5 時脈擴展)。
事實上 master 裝置就算在驅動 SDA,也會同時監聽 SDA 的狀態以辨別是否有 bus arbitration 的狀況發生(忘了什麼是 bus arbitration 的讀者,可以回頭翻一下【Maker電子學】I2C 界面解密 — PART 6 仲裁協定)。
由於 I2C bus 的 wired-AND 的特性,不管是 SCL 還是 SDA,它們都沒有明確的驅動方向;也可以說,對所有的裝置來講,SCL 和 SDA 在任何時候都同時是輸入和輸出。
我們強調過很多次,I2C bus 的輸出驅動方式是 open drain,裝置只能把 bus 訊號拉 low,或者不拉;當大家都不拉時,bus 的狀態才會靠拉起電阻的作用而變成 high。這樣的設計,讓 bus 上的邏輯 0 比邏輯 1 有更高的優先權,因爲只要有任何一個裝置發出 0,bus 就會是 0;只有當大家都發出 1 時,bus 才會是 1。
優雅的解決方法 #
提出 I2C bus 標準的 NXP 半導體(前身爲飛利浦半導體 Philips Semiconductors)早在 I2C bus 問市之初,就已經爲大家設想好了邏輯位準轉換的做法。在一份編號爲 AN10441 的 application note 中,NXP 爲大家示範了只用兩顆 MOSFET 就達成 I2C bus 位準轉換的巧妙做法。
我們直接引用 AN10441 裡面的圖片來說明,這個電路長這樣:

(圖片來源:Bird 提供)
第一眼看到這個電路,都會覺得它簡單得不可思議,光這兩顆電晶體就有辦法做到 I2C bus 的位準轉換嗎?我們來分析一下這個電路的運作就知道了。
電路的左側是電壓較低的 3.3 V 系統,右側是電壓較高的 5V 系統。電路中的四個 RP 電阻則是 I2C bus 的拉起電阻,各自講 3.3 V 和 5 V 的 bus 拉到對應的電源電壓。
這裡要特別注意的是,MOSFET 會有一個從 source 向 drain 導通的 body diode,在這個電路中,MOSFET 的 source 要接在電壓較低的一側,drain 要接在電壓較高的一側。這個電路有三種狀態:
- 如果 5 V 側有裝置將 bus 拉到 low,5 V 側就會變成接近 0 V,本來逆偏壓而不導通的 MOSFET body diode 就會變成順偏壓,因而開始導通。導通之後,3.3 V 側的電壓就會開始下降,當 3.3 V 側的電壓低於某個程度時,由於 MOSFET 的 gate 是接在 3.3 V 電源上,導致 Vgs 大於 MOSFET 的Vth,MOSFET 就會開始導通,更進一步地讓 5 V 側將 3.3 V 側的 bus 電壓拉低,直到兩邊電壓相等為止。這是由 5 V 側驅動 3.3 V 側的狀態。
- 如果 3.3 V 側有裝置將 bus 拉到 low,由於 MOSFET 的 gate 接在 3.3 V 上,當 source 電壓降低到某個程度,一樣會導致 Vgs 大於 MOSFET 的 Vth,MOSFET 就會開始導通,此時 3.3 V 側就會透過 MOSFET 將 5 V 側的 bus 拉低,直到兩邊電壓相等為止。這是由 3.3 V 側驅動 5 V 側的方法。
- 如果兩邊都沒有裝置去拉 bus 的話,因為兩邊都有各自的拉起電阻,3.3 V 側的電壓就會是 3.3 V,5 V 側的電壓就會是 5 V,而圖中的 MOSFET,gate 和 source 的電壓都是 3.3 V,因此它的 Vgs 等於 0,MOSFET 就不會導通;至於 MOSFET 的 body diode,因為是在逆偏壓的狀態下,因此也不會導通,這讓 bus 的兩邊都能被拉到各自的電源電壓,而不會有互相影響的問題。
講完了,是不是簡單得令人驚訝?有時候複雜的問題不一定要用複雜的解決方法,它可能有很精巧且優雅的簡單解法。我曾經看過設計 IC 的工程師爲了要解決 I2C bus 的位準轉換問題,用 Verilog 寫了一整個狀態機去追蹤 I2C bus 的所有狀態、判斷 bus 驅動的方向,再產生方向訊號去驅動邏輯位準轉換的 buffer。這樣的做法在某些 Fast+ 或更快的 I2C bus 設計上有其必要,但在 400 KHz 以下的 I2C bus 上就顯得太過複雜了,尤其原廠早在數十年前就提供了這樣簡單又優雅的解決方法。
小結 #
這一系列關於各種常用通訊界面的文章,就結束在這一回了。回顧過去這半年多,我們花了四回的篇幅討論 UART、四回的篇幅討論 SPI,又花了八回的篇幅討論 I2C,希望這一系列的文章能對讀者有所幫助。
(責任編輯:賴佩萱)