作者:Bird
我們花了好幾回的篇幅聊了 I2C(以下寫作 I2C) 的通訊協定,包括它的定址方法、傳輸格式、時脈擴展以及 bus 上的仲裁機制。這一回我們要回到 I2C bus 的實體層,來聊一下 I2C bus 的拉起電阻(pull-up resistors)。
至關重要的拉起電阻 #
我們在一開始說明 I2C 的 bus 架構時,就說過 I2C bus 是一個「wired-AND」的電路:bus 上的任何裝置都只能把 SCL 或 SDA 訊號拉 low,而不能讓訊號變爲 high 的狀態。
這個驅動訊號的特性是因爲 I2C 裝置的輸出是 open-drain 電路:它只有 low-side 的電晶體可以用來把輸出腳拉到 low,而當 I2C 裝置想要把 SCL 或 SDA 設爲 high 時,實際上只是關掉這顆 low-side 的驅動電晶體。

(圖片來源:Bird 提供)
因爲電路中並沒有 high-side 的驅動電晶體,因此當 I2C 裝置想要把 SCL 或 SDA 設爲 high 時,實際上輸出腳的特性就會變成高阻抗。什麼是高阻抗呢?就是這個裝置好像從人間蒸發一樣,不存在這個電路上了;換句話說,open-drain 輸出的 output high,事實上就只是「不驅動」電路而已。
如果沒有人驅動線路,那線路上的位準要怎麼變成 high 呢?這時候就輪到 pull-up 電阻登場了。在 I2C 的規範中有明確的提到,SCL 和 SDA 一定要各有一個 pull-up 電阻,將這兩根訊號線拉到 VCC,也就是系統的邏輯準位電源上。

(圖片來源:Bird 提供)
但這 pull-up 電阻究竟要放什麼值,才適合電路的運作呢?如果放太大的電阻,會發生什麼事?放太小的話,又會有什麼影響呢?
Output Low #
我們先來看看 output low 時的狀態。

(圖片來源:Bird 提供)
上圖是 I2C 裝置在輸出 low 時,驅動訊號線的等效電路:輸出 low 的裝置要用它裡面的 low-side 驅動電晶體,將訊號線的位準拉低。那要拉到多低呢?至少要拉到 I2C 規格中定義的 VIL,也就是 0.3 VCC,才能讓其它裝置覺得 bus 的狀態是 low。
上面這個電路其實可以解讀成 I2C 裝置裡的 low-side driver 在「對抗」pull-up 電阻 RP ,因爲當它想要把 SCL 或 SDA 拉到 low 時,RP 會在那邊從中作梗,想要把訊號拉到 high,而 low-side driver 能將訊號拉多低,則取決於它可以流過多少電流。
根據 I2C 的規範,在 100 KHz 的 standard mode 和 400 KHz 的 fast mode 下,I2C 裝置最少要能驅動 3 mA 的電流。假設我們的 VCC 是 3.3 V,根據以上資訊,我們就能算出最小該放什麼值的 pull-up 電阻。
首先我們先計算 VIL:VIL= VCC * 0.3 = 3.3 * 0.3 = 0.99 V
因此我們最少要將訊號線拉到 0.99 V。此時 RP 上的電位差就是:3.3 – 0.99 =2.31 V
如果 output driver 最大可以流過 3 mA 的電流,用 3 mA 的電流要造出 2.31 V 的壓差,電阻就是:
V = IR
2.31 = 0.003 * R
R = 770(Ω)
也就是說,當我們放一顆 770 Ω 的電阻,而 output driver 又剛好可以吸收 3 mA 時,它就可以剛剛好把 SCL 或 SDA 拉到 0.99 V。
如果我們放的 pull-up 電阻太小,那麼它就是一個太「強」的 pull-up,會讓 output driver 沒有足夠的能力去對抗它,而無法將訊號線拉到夠低的準位,就會導致 bus 上的訊號不正確。但凡事總要留點餘地,上面這個計算是完全不考慮任何 margin,沒留任何餘裕的,顯然不是一個好設計。
如果我們希望將 SCL 或 SDA 拉到 0 V,我們就要在 RP 上造出完整的 3.3 V 壓差,這時的電阻值就會變成:
V = IR
3.3 = 0.003 * R
R = 1100(Ω)
原來只要把 pull-up 電阻放大一點,它就會變成一個比較「弱」的 pull-up,讓 output driver 比較好驅動它。
根據上面的計算,如果 pull-up 電阻大於 1100 Ω,output driver 甚至不用吸滿 3 mA,就可以把訊號線拉到 0 V。
我們很常在 I2C 的範例電路中看到 2.7 KΩ 這樣的 pull-up 電阻,了解以上的計算後,我們就可以算算看當 pull-up 是這個值時,output driver 需要驅動多少電流:
V = IR
3.3 = I * 2700
R = 0.00122(A) = 1.22 mA
在這種情況下,output drver 只需要吸收 1.22 mA 左右的電流,就能輕輕鬆鬆將訊號線拉到 0 V。那爲什麼不放更大的 pull-up 電阻,比如說 10 KΩ 或 100 KΩ,讓 I2C 裝置內的 output 更輕鬆呢?因爲在 output high 時,還有另外一個問題…
Output High #
我們前面說過,當 I2C 裝置輸出 high 時,事實上是「不驅動線路」,而靠著 pull-up 電阻把訊號線拉到 high。此時,output driver 都已經關掉了,pull-up 電阻應該可以輕輕鬆鬆地把訊號線拉 high?
非也非也。這裡還有別的魔鬼。當 I2C bus 要從 low 變 high 時,等效電路是這樣的:

(圖片來源:Bird 提供)
怎麼冒了一個電容器 CBUS 出來呢?
這個電容器就是整個 bus 的等效電容,它包括了 bus 上所有裝置接腳的輸入電容,以及電路板上的銅箔、線路等連接線造成的寄生電容等。
由於現今大多數的 IC 都是 CMOS 製程,它裡面的電路包含 output driver、input buffer 等,都是 MOSFET 構成的,因此接腳的輸入電容特性會相當明顯。
大部分的 I2C 裝置的 datasheet 中一定會標明 SCL 和 SDA 的等效電容量,讓你在設計 bus 電路時有數據可以參考。以我們之前介紹過的 I2C I/O extender PCF8574 爲例,它的 datasheet 中就有這樣的說明:

(圖片來源:Bird 提供)
可以看出來 PCF8574 的 SCL/SDA 接腳輸入等效電容最大會到 7 pF 左右。由於 I2C bus 上所有裝置的 SCL 和 SDA 接腳都各自接在一起,因此這些輸入電容就像是全部並聯在一起似的。你放了幾顆 PCF8574,就有幾個 7 pF 並聯在一起,變成一個很大的電容。
至於電路板銅箔造成的寄生電容,則要看線寬、線長、板厚以及板材等參數來決定。精確的計算模型非常複雜,但一般來說只要板子的尺寸不大,線路不要走太長,PCB 走線本身的寄生電容跟 IC 的輸入等效電容比起來都小到可以忽略。
我們舉個例子來看看。一個常用的估計方式是,在 1 Oz 厚銅箔的板子上,板厚 0.8 mm,也就是說線路距離參考 ground 平面 0.8 mm,線寬 0.6 mm 的線路,它的寄生電容大約是 67 pF/m,也就是每米的線長會有 67 pF 的寄生電容,但在一般的小型電路板上,I2C 線路的長度了不起幾公分,因此實務上 PCB 走線造成的寄生電容都在數個 pF 左右的尺度。
PCB 走線寄生電容與物理量的關係是:走線越長、越寬,電容量越大(這個很符合直覺,因爲面積越大電容量當然越大);板子越薄,電容量也會越大(如果你對電容量的物理定義和特性不熟,這一點就沒那麼直覺,但它確實是這樣)。
好,現在假設我們電路中有 5 顆輸入電容是 7 pF 的 IC,再加上走線造成了 5 pF 的寄生電容,bus 上的電容量總共是 CBUS= 7 * 5 + 5 = 40(pF)。
此時 pull-up 電阻要將 bus 訊號線拉到 high 時的等效電路就變成:

(圖片來源:Bird 提供)
對,這就是個典型的 RC 定電壓充電電路。
這個電路中,電容器上的電壓可以用一個看起來很恐怖但其實很簡單的數學式來表示:
V(t)= VCC(1 − e−(t / RC))
VCC 的電壓是固定的,而隨著電容上的電壓越來越高,電阻上的壓差就會越來越小,因此流過電阻對電容充電的電流就會越來越小,越到後來,電容的電壓上升的速度就會越慢。
如果我們把電容上的電壓對時間畫成圖,曲線會長這樣:

(圖片來源:Bird 提供)
其縱軸是電壓對 VCC 的比例,而橫軸則是一個常數的倍數,這個常數叫做 RC time constant(時間常數):TC = R * C(計算 TC 時,R 的單位是歐姆,而 C 的單位則是法拉第,算出來的 TC 單位則是秒)。假設 RP 是 100 KΩ,這是個超大的 pull-up 電阻,而 CBUS 是 40 pF,我們先來計算一下它們的 RC time constant:TC = R * C =100 * 103 * 40 * 10-12 = 4000 * 10-9(S),也就是 4 us 左右。
換句話說,當 RP 開始對 CBUS 充電後,經過 4 us,CBUS上的電壓會達到 63% VCC 左右。因爲 I2C bus 的 VIH 是 0.7 VCC,因此還差一點點才能讓其它裝置認爲這個訊號是 high。
事實上一般在 I2C bus 的時間參數估算時,我們大概都用 1.2 倍的 RC 時間常數來估算將 bus 拉到 0.7 VCC 所需要的時間,以上面那個例子來說,就是 4.8 us 左右。假設 SCL 從 low 到 high 和從 high 到 low 所需的時間是對稱的,那麼一個 clock cycle 就會變成 4.8 us * 2 = 9.6 us,而這在這樣的條件下能跑到最快的 SCL 頻率就是:1 / 9.6us = 104 KHz
發現了嗎?如果我們放了太大的 pull-up 電阻,就會限制 bus 訊號從 low 變成 high 的轉換時間,從而限制了最快的 clock 速度。
小結 #
I2C bus 的 pull-up 電阻設計,看起來似乎是一個兩難的局面:
- RP 很小:low-to-high 的變化速度可以很快,但是 low 的位準可能會受到影響
- RP 很大:low 的位準沒有問題,但是 low-to-high 的變化速度可能會太慢,進而影響 clock 速度
因此如何根據 bus 上的裝置數量、寄生電容量、裝置的驅動能力,以及所需要跑的 clock 頻率,來選擇適合的 pull-up 電阻,就變成了 I2C bus 電路設計上很重要的課題。
在 3.3 V、400 KHz 以下,且裝置數量少於 10 個、電路板又不大的狀況下,2.2 KΩ 到 4.7 KΩ 這樣的數值幾乎可以滿足大部分的設計,但經過本文,希望讀者可以更加了解 pull-up 電阻與 I2C bus 電路設計之間的關係,並在需要時知道如何計算。
本篇文章中的計算仍然有許多簡化過的假設,有興趣深入探究的讀者可以參考 I2C Specification 的 7.1 節,裡面對 pull-up 電阻的計算有非常詳細的說明(本來這一回還要聊聊 I2C bus 的位準轉換,也就是如何連接不同電壓的 I2C bus,不過因爲篇幅有限,這個題目就留到下回再聊了)。
(責任編輯:賴佩萱)