幾種最常用的串行數據傳輸總線 - I2C

我第一次知道I2C總線是1995年,項目中用到電視機高頻頭(也叫調諧器、Tuner),能夠方便買到的高頻頭要麼是飛利浦(Philips)的,要麼是日系廠商的,但日系廠商聯繫起來比較費勁。Tuner其實就是通過I2C總線送控制字來改變其本振頻率(LO)選擇你需要的頻段,當時知道I2C的鼻祖就是飛利浦半導體(NXP-恩智浦半導體的前身),也是第一次使用MC34063這顆後來如同555一樣撲街的開關穩壓芯片,用來產生高頻頭所需要的12V DC。

典型的電視機調諧器,採用I2C來進行調諧

板子上的器件之間也需要Talk

器件和器件之間的也需要溝通信息,尤其是需要MCU/DSP等對其它外設進行控制的時候。工程界的大神們基於MCU/DSP開發了一系列的協議比如UART、USART、SPI、I2C、CAN等. . . .每種協議都有各自擅長的地方,也有其侷限性,因此要做系統設計的硬件工程師就應該對每種接口協議有大概的認識(即便沒有機會吃豬肉,也要知道各種豬是如何跑的),這樣才能夠幫助你在做方案選擇的時候能夠選用最合適的協議接口方式,這也是你需要閱讀我寫的文章的原因。

在同一個PCB板子上的不同器件之間進行通信最常用的有三種形式 - SPI、I2C和UART,上篇文章我們簡單介紹了SPI,今天就來看看I2C,我們先看一下I2C最基本的一些特性,然後再跟其它的通信協議方式進行一下比較。 

兩條通過上拉電阻吊在電源的線,上面可以掛多個器件進行通信

簡約而不簡單的I2C總線

I2C來自於英文inter–integrated circuit,有時也寫爲IIC,字面意思也可以理解爲IC之間進行交流用的,跟SPI對比,I2C沒有天生的主、從之分,也就是說掛在兩根線(數據線SDA和時鐘線SCL)上的所有器件都是生而平等的。這個協議最早由飛利浦半導體推出來,幾年後Intel又弄了一個SMBus(系統管理總線)協議,其實基本跟I2C一模一樣,算是其擴展吧,一丟丟的差別而已。 

I2C總線傳輸時序

有哲學家說 - 越是看起來簡單的東西,背後處理的問題越複雜。I2C其實也是如此,雖然我們看到的是2根線能掛起一大串的器件,但就像一個沒有了老師的課堂,沒有一個好的管理機制一定會出現亂哄哄的局面,要讓任何兩個同學之間進行有序地交流,沒有明確的協議是肯定會亂掉的。

最簡單的情況就是在這個系統中有1主1僕,但如果有多個僕(從設備)呢?如果多個“從設備”不知道哪個是“主設備”呢?如果出現了多個“主設備”呢?如果一個“主設備”正由“從設備”獲取數據,中途由於種種原因突然掛了怎麼辦呢?一個“從設備”正發着數據掛掉了怎麼辦呢?一個“主設備”獲取了總線使用權用以數據的發送,在釋放使用權之前崩潰了怎麼辦呢? 

這種看似非常簡單的結構其實會遭遇各種可能

在實際的運行環境中會有各種意外導致系統出現問題,我們在學習使用I2C的時候一定要做到心中有數 - 簡單的架構背後有着複雜的結構來保證這個協議的順利執行,才能讓其成爲靈活、可擴展、魯棒、極少管腳的串行通信方案。

示波器上捕捉到的I2C總線上的數據讀取

I2C協議概要

以下是I2C的主要特徵:

  • 不論總線上掛多少個設備,只需要兩根信號線(時鐘SCL和數據SDA)就搞定;

  • 兩根信號線都通過合適阻值(這個值的正確選取很重要)的上拉電阻連接到正電源上;

  • 每個設備的接口都是通過漏極開路(或集電極開路)的輸出驅動連接到時鐘和數據信號線上;

  • 每個從設備都有一個7位的地址,可供尋址用。主設備必須知道這些從設備的地址以便同指定的一個從設備進行通信。

  • 所有傳輸均由“主設備”發起和終止; “主設備”可以將數據寫入一個或多個“從設備”或從“從設備”請求數據。

  • 在系統中“主”和“從”不是固定的,任何一個設備都可以作爲“主”或“從”,只要它配置了適當的硬件或固件,實際上在嵌入式系統中最常採用的架構就是一個“主設備”向多個“從設備”發送命令或由多個“從設備”採集數據。

  • 數據信號在時鐘的下降沿更新,並在上升沿被採樣,如下圖。

 I2C協議中數據和時鐘的時序關係

  • 數據是以一個字節進行傳輸的,每一個字節跟着1位的握手信號,作爲ACK/NACK(應答/無應答)位.

同UART和SPI相比,I2C有何優勢?

I2C的主要優勢如下:

  • 管腳/信號數量少,即便掛了很多的設備,也只用兩根線;

  • 可以適應不同的從設備的要求;

  • 可以支持多個主設備;

  • 引入了ACK/NACK功能以提升應對錯誤的能力

當然也有一些劣勢的地方:

  • 增加了固件和底層硬件的複雜度

  • 增加了協議的負荷,降低了數據傳輸的吞吐率

  • 需要上拉電阻,會導致如下的後果

    • 限制了時鐘的速度

    • 增加了功耗

由此可以看到I2C比較適合複雜、多樣化、需要通信設備靈活擴展的場景;UART比較適合單點對單點的連接,因爲UART沒有標準的方式來尋址不同的設備或共享管腳。SPI比較適合系統中有一個主設備和少量的從設備,而且每一個從設備都有一個單獨的“從設備選擇”信號,當總線上有多個設備的時候會需要更多的管腳,佈線的難度也會增加,當你需要支持多個主設備的時候,SPI用起來也會非常尷尬。

如果你需要較高的傳輸速率,使用I2C就不太合適,SPI能夠支持更高的時鐘頻率,數據負載開銷也最小。如果你想使用FPGA從頭設計串行數據傳輸,SPI和UART的底層硬件設計要簡單得多,迫不得已再用I2C。

I2C硬件電路特色

I2C的一個特性是總線上的每個器件都必須通過漏極開路(或集電極開路)輸出驅動器連接時鐘信號(縮寫爲SCL)和數據信號(縮寫爲SDA)。這也就意味着:

  • 信號缺省始終爲邏輯高電平,如果I2C主設備嘗試與已失效的從設備通信,則數據信號永遠不會進入未定義狀態,如果從設備沒有驅動信號,它將被讀爲邏輯高電平。 同樣,如果主設備在傳輸過程中斷電,SCL和SDA將返回邏輯高電平,其它設備可以通過觀察SCL和SDA在一定時間內邏輯高電平來確定總線是否可用於新的傳輸。

  • 即使另一個設備試圖將它們驅動爲高電平,總線上的任何設備都可以安全地將信號驅動爲邏輯低電平,這是I2C“時鐘同步”或“時鐘延長”功能的基礎:主器件產生串行時鐘,但如果需要,從器件可以將SCL保持爲低電平,從而降低時鐘頻率。

  • 具有不同電源電壓的器件可以共存於同一總線上,只要較低電壓的器件不會被較高的電壓損壞即可。 例如,如果SCL和SDA上拉至5V,3.3V的器件就可以與5V的器件進行通信 - 即使3.3V的器件無法驅動來自典型的推輓輸出級的5V,漏極開路的配置可以讓邏輯高電壓達到5V。

有電阻R,就會有RC

由於漏極開路輸出驅動器存在着明顯的缺點,並不是數字IC的標準配置。電壓的變化會受到與特定節點相關的電容充電或放電所需的時間的限制。 SCL和SDA上的上拉電阻限制了充電的電流量 - 也就是說,我們在RC時間常數中可以更多地通過R來控制從邏輯低到邏輯高的轉換。

 輸出從低到高時向電容充電

輸出從高到低時由電容放電

從這個圖可以看出從低到高的轉換比從高到低的轉換要慢很多,導致出現常見的I2C鋸齒波形:

由I2C信號線上的上拉電阻以及節點電容引起的上升沿變緩

下圖爲示波器上捕捉到的實際的時鐘信號波形 - 採用1kΩ的電阻做上拉,即便最小的電容效應(總線上只有兩個器件,且很短的PCB走線)的時候I2C時鐘信號的低到高以及高到低的變化。

上拉電阻的值如何選擇?

可見,上拉電阻限制了數據傳輸的最大時鐘速率。實際上,電阻和電容都有影響,我們無法控制電容,因爲它主要取決於總線上有多少器件以及這些器件之間互連的方式。那問題來了,考慮到所需的數據傳輸速率要求以及可能帶來的功耗,使用多少值的上拉電阻才最合適?較低的電阻RC時間常數也比較低,但會通過上拉電阻增加從VDD流向地的電流(只要SCL或SDA爲邏輯低電平)。

官方I2C規範(第9頁)規定,在達到VDD的70%之前,電壓不被視爲“邏輯高”。 RC時間常數告訴我們電壓達到最終電壓的約63%需要多長時間。 因此,爲簡單起見,我們假設R×C告訴我們信號從接地電壓附近上升到邏輯高電壓需要多長時間。

如何計算電容呢? 比較可行的方法是查找總線上每個器件的引腳電容進行粗略估計,然後再添加每英寸PCB走線3pF和每英尺同軸電纜30pF。

假設我們有50pF的總線電容,按照I2C“標準模式”規範規定 - 最大上升時間爲1000ns。

也就是說上拉電阻可以定爲20kΩ,這個值的功耗也比較低,速度如何呢?假設你希望時鐘高的時間至少是上升時間的三倍。

如果167 kHz不夠快,您可以降低電阻(以增加功耗爲代價),直到達到所需的時鐘速度。 (實際上,“標準模式”將時鐘速度限制爲100 kHz,但可以根據系統需要調整這些規格。)

當然,這只是粗略的計算,具體的應用中要根據掛在總線上的器件的數量以及電路設計來進行估算,還可以配合示波器上實際的測量進行調整,以滿足系統的綜合要求。

典型的數據傳輸

下面的時序圖爲一個典型的I2C傳輸時序。

可以看到以下幾點:

  • 對應於時鍾邏輯高電平部分的虛線提醒我們邏輯高電平(對於SCL和SDA)都是“隱性”狀態 - 換句話說,信號通過上拉電阻自然浮動到邏輯高電平。 “主導”狀態是邏輯低,因爲只有當設備實際將其驅動爲低時,信號纔會變低。

  • 每一次的傳輸都是以“起始位”開始,該起始位定義爲在SCL爲邏輯高電平的時候SDA的下降沿。

  • 傳輸以“停止位”結束 - 定義爲當SCL爲邏輯高電平的時候SDA的上升沿。 I2C傳輸必須以停止位結束,但在生成停止位之前可能會出現多個起始位。

  • 數據在時鐘爲高時有效,在時鐘爲低時改變狀態; 數字通信系統通常都是邊沿驅動的,因此實際上數據在時鐘的上升沿被讀取,在時鐘的下降沿時進行更新。

  • 信息一次一個字節地交換,從最高有效位開始,每個字節後跟一個ACK或NACK。

  • 你可能期望ACK由邏輯高指示,NACK由邏輯低指示,但事實並非如此。 ACK爲邏輯低,NACK爲邏輯高。 這是必要的,因爲高是隱性狀態 - 如果“從設備”不工作,信號自然浮動到NACK,同樣只有當設備正在運行並準備繼續進行傳輸時,纔會發送ACK。

以下爲I2C數據傳輸的順序:

  1. 主機生成一個起始位以啓動傳輸。

  2. 主設備發送與其想要通信的從設備相對應的7位地址。

  3. 第一個單字節段中的最後一位是讀/寫指示符。如果想要從“從設備”讀取數據,則“主設備”將該位設置爲邏輯高電平; 如果要將數據寫入“從設備”,則將其設置爲邏輯低電平。

  4. 下一個字節是第一個數據字節,它來自主設備或從設備,具體取決於讀/寫位的狀態。像往常一樣,我們有8位數據,從最重要的位開始。

  5. 數據字節之後是ACK或NACK,如果這是讀數據傳輸則由“主設備”生成,如果是寫數據傳輸,則由“從設備”生成。 ACK和NACK可能意味着不同的東西,具體取決於通信設備的固件以及底層的硬件設計。例如,主設備可以使用NACK來表示“這是最後一個數據字節”,或者如果“從設備”知道要發送多少數據,它可以使用ACK來確認數據是否已成功接收。

  6. 傳輸以“主設備”生成的停止位終止。

傳輸多少字節?

每次傳輸都是以同樣的方式開始:起始位、地址、讀/寫、ACK/NACK。 之後,任何數量的字節都可以從“主設備”發送到“從設備”或從“從設備”發送到”主設備“,每個字節後跟ACK或NACK。 NACK可以用來表示“停止發送數據!”。例如,“主設備”可能希望從“從設備”(例如溫度傳感器)接收連續的數據流,每個字節後面都會有ACK,如果“主設備”需要處理其它事情,它可以用NACK告知”從設備“並在它準備就緒時再開始新的傳輸。

由於篇幅限制,在此我們不做更詳細的介紹,有興趣的朋友可以閱讀Wikipedia中關於I2C的介紹以及該詞條下面的參考文章。對該總線的使用以及技術細節有一定程度的瞭解會幫助我們在實際的設計中更加有效地完成數據的傳輸設計以及有可能的問題定位。

一個應用舉例 - 下面是我們用小腳丫FPGA做的計算器,我們通過FPGA邏輯實現了I2C的主控制功能,來操作掛在I2C總線上的觸摸按鍵控制器、掛在SPI總線上的LCD顯示屏。

小腳丫FPGA做成的計算器

計算器的功能框圖,3顆觸摸控制器掛在I2C總線上

 

轉載 - -電路設計技能公=公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章