和仿真【2.8】)
5.7 I2C5.7.1 I2C規(guī)范介紹I2CInter-Integrated Circuit是一種只使用兩根信號線的多主機、多從機總線。兩根線分別為SDA串行數據和SCL串行時鐘雖然有名為時鐘的SCL線但本質上并不能稱為同步串行總線因為SCL還參與了許多協議內容。I2C總線使用線與邏輯充分利用了SDA、SCL這兩根線實現了許多較為復雜的協議內容包括·多從機7位或10位編址從機尋址和應答。·時鐘同步?!ざ嘀鳈C和沖突仲裁?!ぶС种鲝囊惑w。·不同速率從機混合使用。·數據應答?!V播等等。下面將介紹I2C規(guī)范中常用的一些內容。對于完整的規(guī)范讀者應參閱規(guī)范文檔。1.I2C電氣連接圖5-32是I2C總線的典型連接。所有主從機的SDA和SCL均為漏極開路輸出。所有SDA連接在一起、SCL連接在一起并由RP電阻上拉構成線與。任何一個主機或從機下拉將使得總線變低所有主、從機均釋放總線時才會由電阻上拉到高。VCC由主機和從機的工作電壓決定常見為3.3V、3.0V、2.5V或5VRP的取值與VCC和總線速度有關VCC越低或速度越快RP越小RP也可替換為1mA至3mA的電流源。RS可用于消除主從機之間的些許時序差異導致的毛刺。圖5-32 I2C總線的電氣連接I2C總線的數據率即SCL頻率在規(guī)范中定義的有標準速率100kHz、快速400kHz和高速3.4MHz三種。2.I2C位定義SCL和SDA在空閑時均為高電平所有主從機均釋放總線。數據位傳輸時要求在SCL為高電平期間SDA保持穩(wěn)定即SDA只能在SCL為低電平時跳變如圖5-33所示。SCL為高時的SDA跳變則被專門定義為一次傳輸的起始和停止稱為起始位和停止位如圖5-34和圖5-35所示。圖5-33 I2C位傳輸圖5-34 I2C起始位圖5-35 I2C停止位注意圖5-33圖5-35中上跳沿為曲線段而下降沿為直線段。曲線段代表了釋放總線由外部電阻上拉到高的過程。因而一次I2C傳輸過程的波形將如圖5-36所示。其中還以快速模式400kHz為例標注了一些重要的時序要求。圖5-36 I2C傳輸波形和時序以400kHz速率為例除正常的起始位之外還可以有重復起始位。在一次傳輸結束時不發(fā)送停止位而發(fā)送起始位緊接著進行下一次傳輸稱為重復起始位。重復起始位用于直接發(fā)起下一次傳輸而不讓總線回到空閑狀態(tài)這樣主機可以一直掌握總線控制權避免進入空閑狀態(tài)后被其他主機搶奪控制權。圖5-37所示是重復起始位。圖5-37 重復起始位3.I2C字節(jié)傳輸和尋址I2C的數據傳輸以字節(jié)為單位并且MSB在先每個字節(jié)后附一位應答位因此傳輸中的位以9位為一組一次完整傳輸的位數必然是9的整數倍。應答位的意義在規(guī)范中并沒有嚴格定義可以是接收方對字節(jié)數據的確認也可以是接收方表達欲結束傳輸之意圖甚至還可以是發(fā)送方發(fā)送的附加信息這都取決于從機的功能定義。應答位的“確認”、“應答”之含義一般以低電平表達記為“ACK”“不確認”、“無應答”則以高電平表達記為“NAK”。在7位從機地址尋址的模式下每次I2C傳輸的第一個字節(jié)用作從機尋址。這個字節(jié)的高7位為從機地址而最低位則指示本次傳輸中后續(xù)數據的方向是主機向從機發(fā)送數據稱為寫操作理解為主機視角還是從機向主機發(fā)送數據稱為讀操作寫操作以低電平表示讀操作以高電平表示??偩€上的從機均會至少監(jiān)聽每次傳輸的第一字節(jié)如果其中的高7位與某個從機預先分配的地址一致則該從機會在第一字節(jié)后的應答位給出ACK低電平并配合主機完成后續(xù)數據傳輸如果沒有從機地址吻合則總線上不會有應答主機應忽略此次操作可立即發(fā)送停止位或走完預先的傳輸流程當然后續(xù)也得不到任何有效數據或應答。7位一共可以表達128個地址但其中有十余個地址在規(guī)范中定義為特殊用途如廣播、高速模式主機碼、10位尋址擴展等并不能作為從機地址。圖5-38所示是一次包含一字節(jié)數據寫從主機到從機操作的傳輸從機應答了尋址和數據。其中從機的7位地址為0b10011010x4d傳輸的數據為0xa5。有時也常常將一個從機的讀寫分開表述為兩個8位地址即讀地址和寫地址那么這個從機的讀地址和寫地址就分別為0b100110110x9b和0b100110100x9a。注意在第一個應答前主機釋放SDA上升而后從機拉低SDA應答而產生了一個小毛刺是正?,F象。圖5-38 向從機0x4d寫一字節(jié)數據0xa5的示例圖5-38中“S”表示起始位Start“P”表示停止位“stoP”。圖5-39所示則是向從機寫入一個字節(jié)后立即重復起始條件然后向同一個從機讀取一字節(jié)的例子。在這個例子中主機從從機讀取到的字節(jié)數據為0xf5但最后主機給出NAK即表達“即將結束傳輸不必準備下一個數據”之意。圖5-39 重復起始條件的示例波形圖5-39中“sA”表示來自從機的ACK“mNA”表示來自主機的NAK“rS”表示重復起始位repeat Start。圖5-39所示的I2C總線波形也常簡化為圖5-40所示的圖形其中灰色部分為主機操縱SDA白色部分為從機操縱SDA。圖5-40 簡化的I2C總線操作4.從機內部地址數據字節(jié)是否有進一步的意義一般不是I2C規(guī)范的范疇這取決于從機的功能。例如有些從機是存儲設備或內部有大量寄存器構成一個地址空間則往往將寫操作中的前一個或數個數據字節(jié)用作內部地址尋址。例如一個256字節(jié)存儲器會使用寫操作中的第一個數據字節(jié)作為內部地址當它接收到這個表達內部地址的字節(jié)時會將內部操作指針指向這個內部地址以便以后的寫或讀操作在這個地址上進行。圖5-41演示了向一個從機地址為0x52的存儲器的內部地址0x39處寫入數據0x7a的操作。圖5-41 帶有內部地址的從機的寫數據操作而圖5-42則演示了從該存儲器內部地址0x76處讀取數據的操作。因設定內部地址需要用I2C寫傳輸而讀取數據需要用I2C讀傳輸因而整個操作用一個重復起始位拆分成兩次I2C傳輸且不會丟失總線控制權。讀出的數據為0xcf。圖5-42 帶有內部地址的從機的讀操作大多數帶有內部地址的從機在每次寫進數據后或在讀出數據并收到主機ACK時會將內部操作指針自增1以便主機向連續(xù)地址上寫入或讀取多個數據。圖5-43演示了向上述存儲器的內部地址0x39~0x3b分別寫入0xf2、0xf3、0xf4的操作。圖5-43 帶有內部地址的從機的連續(xù)寫數據操作圖5-44則演示了從上述存儲器的內部地址0x39~0x3b讀出數據的操作。讀出的數據為0xf2、0xf3和0xf4。圖5-44 帶有內部地址的從機的連續(xù)讀數據操作5.時鐘同步和仲裁這里簡單介紹時鐘同步機制和多主機的仲裁機制。當多個主機同時操作從機時如果兩者SCL步調不一致根據線與邏輯只要有一個將SCL拉低SCL線便為低因而先下拉SCL的主機將導致SCL下跳而后釋放SCL的主機才會使SCL上跳。如圖5-45所示在T0時刻主機1拉低SCLSCL即刻下跳同時運作的主機2在T1時刻監(jiān)測到SCL為低與自身意圖不一致立即開始其低電平周期與主機1同步下降沿。在T2時刻主機1意圖釋放SCL但主機2仍然拉低SCL此時主機1監(jiān)測到SCL電平與自身意圖不一致便進入等待直到主機2釋放SCL才繼續(xù)自己的高電平周期與主機2同步上升沿。最終SCL的低電平時間由低電平最長的主機決定而高電平時間由高電平最短的主機決定。從機也可在SCL為低時下拉住SCL線使得主機釋放SCL時SCL不上跳迫使主機進入等待。如圖5-46所示T1時刻從機可能因內部邏輯忙而跟不上主機的節(jié)奏于是拉低SCL到T2時刻主機意圖釋放SCL但從機仍然拉低SCL迫使主機進入等待直到T3時刻從機準備好繼續(xù)傳輸過程而釋放SCL。圖5-45 I2C主機間的時鐘同步圖5-46 I2C從機迫使主機等待主機只能在總線空閑的時候發(fā)起傳輸因而前述的重復起始位可以避免總線回到空閑狀態(tài)從而避免后面可能與別的主機搶奪控制權失敗。在SCL線為高電平期間主機們也會監(jiān)測SDA電平是否與自身意圖一致監(jiān)測到與自身意圖不一致的主機喪失控制權剩下的主機們繼續(xù)直到最終剩余一個主機或者剩下的主機都對同一個外設做一模一樣的操作并完成傳輸。這個過程稱為仲裁。容易想到訪問小地址值從機的主機會贏得仲裁。輸掉仲裁的主機可以繼續(xù)控制SCL直到當前字節(jié)完成。主從一體機在作為主機輸掉仲裁時有可能檢測到贏得仲裁的主機欲訪問的就是自身的從機角色此時它應立即切換到從機角色發(fā)送應答并配合贏得仲裁的主機完成傳輸。5.7.2 通用I2C主機設計這里我們定義一個命令FIFO驅動的I2C主機向FIFO中寫入命令來控制I2C主機工作這些命令包括·產生起始位/重復起始位?!ぎa生停止位?!懽止?jié)并寫ACK?!懽止?jié)并讀ACK讀ACK也等同于發(fā)送NAK。·讀字節(jié)并寫ACK?!ぷx字節(jié)并讀ACK讀ACK也等同于發(fā)送NAK。上層邏輯只需將所需的I2C操作轉換為上述6種命令的序列寫入FIFO即可控制I2C完成工作。從I2C總線讀到的數據8位數據和1位應答位將被I2C主機寫入到一個數據FIFO因寫出字節(jié)時可能更需要讀入應答位所以I2C主機并不區(qū)分讀寫的數據而是會記錄總線上的每次字節(jié)傳輸及其應答位以供上層邏輯根據上層協議選擇分析。我們定義命令FIFO中的命令格式如表5-7所示每個命令均為10位。從表中可以看到發(fā)送數據0xff與讀入數據并沒有區(qū)別因為對于I2C總線來說都是釋放SDA。I2C協議和時序相對復雜因此這里并不能像前兩節(jié)介紹的UART或SPI主機那樣依賴簡單的計數來產生時序。為降低模塊復雜度可將位時序生成和字節(jié)處理均獨立成模塊分別取名為位引擎Bit Engine模塊和字節(jié)引擎Byte Engine模塊。表5-7 I2C主機的控制命令對于位時序生成參見圖5-47可將起始位、停止位和數據位的各個時序要求總結為圖中所示的9個時間段。圖5-47 I2C主機BitEngine的時序分段這9個時間段如下?!て鹗嘉幌嚓PSSU起始位建立時間SH起始位保持時間SDH起始位后的SDA保持時間?!祿幌嚓PDSU數據建立時間SCLH數據位中SCL的高電平時間DH數據保持時間?!ねV刮幌嚓PPDSU停止位前的數據保持時間PSU停止位建立時間PH停止位保持時間。定義好這9個時間段的長度即可保證I2C總線時序。在位引擎中使用一個9狀態(tài)的狀態(tài)機來完成時序的生成狀態(tài)機的狀態(tài)轉換如圖5-48所示。狀態(tài)轉換依賴一個計數器t_cnt用于計每一個狀態(tài)所需的時間這些時間以參數形式在模塊中給出。根據前述的I2C時序SDH時間和DH時間、PSDU時間和DSU時間可合用同一個參數。圖5-48 BitEngine的狀態(tài)機位引擎模塊的參數和端口定義如表5-8所示。表5-8 BitEngine模塊的參數和端口說明根據上述說明BitEngine模塊描述為代碼5-7注意這個位引擎并未實現多主機的時鐘同步和仲裁。對于幾個用來設定時序的參數應遵循以下限制·TDSU應不小于其他6個參數?!DSU最大為1023/CLK_FREQ因t_cnt為10位。總線空閑的時間為TSSUTPH總線時鐘頻率為1TDSUTSCLHTDH。代碼5-7 I2C主機的BitEngine模塊對于字節(jié)引擎功能定義為從FIFO讀取命令并控制位引擎工作也使用一個狀態(tài)機來控制其工作流程。狀態(tài)轉換如圖5-49所示。圖5-49 ByteEngine的狀態(tài)機其中的狀態(tài)輸出·fifo_rd讀取命令FIFO因RDFIFO狀態(tài)只會持續(xù)一個周期fifo_rd為單周期。·bit_go控制BitEngine開始產生一個I2C位?!ic_bit根據data記錄的命令FIFO中的命令向BitEngine給出位類型連接至BitEngine的iic_bit輸入端口。其中的事件·9b_end輸出事件表示一次9位傳輸結束用于指示將收到的數據寫到數據FIFO?!atacmd[80]內部事件將命令FIFO讀到的命令中的內容賦給datadata將用作移位寄存器參與構造iic_bit?!ata1內部事件將data左移一位。字節(jié)引擎模塊的端口定義如表5-9所示。表5-9 ByteEngine模塊的端口說明IicByteEngine的描述如代碼5-8所示。代碼5-8 I2C主機的ByteEngine模塊最后將BitEngine和ByteEngine模塊實例化到一個完整的IicMaster模塊中并使用一個簡單的移位寄存器模塊記錄總線上的數據。表5-10是其參數和端口定義。表5-10 IicMaster模塊的端口說明代碼5-9是完整的IicMaster代碼。其中將I2C總線信號定義到了一個名為IicBus的接口中因無論主從機SCL和SDA的形態(tài)均一樣所以并不需要使用modport關鍵字定義角色IicBus中將SCL和SDA的讀、寫和三態(tài)控制分開定義應在整個工程的頂層模塊中使用它們實例化三態(tài)門實現模擬漏極開路輸入。代碼5-9 完整的IicMaster模塊5.7.3 通用I2C從機設計這里我們定義一個I2C從機IicSlave模塊的功能如下·7位從機地址參數化設定?!た膳渲脙炔康刂肺粚捇驘o內部地址?!ぬ峁┮粋€存儲器讀寫口如配置為有內部地址則可直接連接存儲器如配置為無內部地址則由其寫信號指示從I2C總線獲取的數據更新到了寫數據口上。與前述的UART接收器、SPI從機類似通過將SCL和SDA的跳沿轉換為使能信號來控制模塊的工作。但I2C協議較復雜還需要使用狀態(tài)機根據上述功能定義和I2C協議可總結出狀態(tài)機的轉換圖如圖5-50所示。當然這個狀態(tài)機的工作還需要兩個位計數數據位計數bit_cnt和內部地址位計數ia_bit_cnt來配合因較為復雜在圖中并未畫出它們的驅動事件應對照圖5-51和后文代碼來理解。圖5-50 IicSlave模塊中的狀態(tài)機數據位計數、內部地址計數以及狀態(tài)變化的波形如圖5-51所示。圖中以IADDR_WIDTH8為例。圖5-51 IicSlave模塊的工作波形IicSlave模塊的參數和端口定義如表5-11所示。表5-11 IicSlave模塊的參數和端口說明IicSlave模塊的描述如代碼5-10所示。注意其中的狀態(tài)機部分的狀態(tài)驅動和狀態(tài)轉移兩段為節(jié)約篇幅將state、bitcnt和ia_bitcnt都寫在了同一個過程里與前述的帶有輔助計數器的狀態(tài)機稍有不同讀者應著重理解。代碼5-10 IicSlave模塊