i2c 相關知識總結(轉)

一. 技術性能:
    工作速率有100K和400K兩種;
    支持多機通訊;
    支持多主控模塊,但同一時刻只允許有一個主控;      
    由數據線SDA和時鐘SCL構成的串行總線;
    每個電路和模塊都有唯一的地址;                    
    每個器件可以使用獨立電源

二. 基本工作原理:
    以啓動信號START來掌管總線,以停止信號STOP來釋放總線;
    每次通訊以START開始,以STOP結束;
    啓動信號START後緊接着發送一個地址字節,其中7位爲被控器件的地址碼,一位爲讀/寫控制位R/W,R. /W位爲0表示由主控向被控器件寫數據,R/W爲1表示由主控向被控器件讀數據;
    當被控器件檢測到收到的地址與自己的地址相同時,在第9個時鐘期間反饋應答信號;
    每個數據字節在傳送時都是高位(MSB)在前;

寫通訊過程:
    1. 主控在檢測到總線空閒的狀況下,首先發送一個START信號掌管總線;
    2. 發送一個地址字節(包括7位地址碼和一位R/W);
    3. 當被控器件檢測到主控發送的地址與自己的地址相同時發送一個應答信號(ACK);
    4. 主控收到ACK後開始發送第一個數據字節;
    5. 被控器收到數據字節後發送一個ACK表示繼續傳送數據,發送NACK表示傳送數據結束;
    6. 主控發送完全部數據後,發送一個停止位STOP,結束整個通訊並且釋放總線;

讀通訊過程:
    1. 主控在檢測到總線空閒的狀況下,首先發送一個START信號掌管總線;
    2. 發送一個地址字節(包括7位地址碼和一位R/W);
    3. 當被控器件檢測到主控發送的地址與自己的地址相同時發送一個應答信號(ACK);
    4. 主控收到ACK後釋放數據總線,開始接收第一個數據字節;
    5. 主控收到數據後發送ACK表示繼續傳送數據,發送NACK表示傳送數據結束;
    6. 主控發送完全部數據後,發送一個停止位STOP,結束整個通訊並且釋放總線;

四. 總線信號時序分析
    1. 總線空閒狀態
    SDA和SCL兩條信號線都處於高電平,即總線上所有的器件都釋放總線,兩條信號線各自的上拉電阻把電平拉高;
    2. 啓動信號START
    時鐘信號SCL保持高電平,數據信號SDA的電平被拉低(即負跳變)。啓動信號必須是跳變信號,而且在建立該信號前必修保證總線處於空閒狀態;
    3. 停止信號STOP
    時鐘信號SCL保持高電平,數據線被釋放,使得SDA返回高電平(即正跳變),停止信號也必須是跳變信號。
    4. 數據傳送
    SCL線呈現高電平期間,SDA線上的電平必須保持穩定,低電平表示0(此時的線電壓爲地電壓),高電平表示1(此時的電壓由元器件的VDD決定)。只有在SCL線爲低電平期間,SDA上的電平允許變化。
    5. 應答信號ACK
    I2C總線的數據都是以字節(8位)的方式傳送的,發送器件每發送一個字節之後,在時鐘的第9個脈衝期間釋放數據總線,由接收器發送一個ACK(把數據總線的電平拉低)來表示數據成功接收。
    6. 無應答信號NACK
    在時鐘的第9個脈衝期間發送器釋放數據總線,接收器不拉低數據總線表示一個NACK,NACK有兩種用途:
    a. 一般表示接收器未成功接收數據字節;
    b. 當接收器是主控器時,它收到最後一個字節後,應發送一個NACK信號,以通知被控發送器結束數據發送,並釋放總線,以便主控接收器發送一個停止信號STOP。

五. 尋址約定
    地址的分配方法有兩種:
    1. 含CPU的智能器件,地址由軟件初始化時定義,但不能與其它的器件有衝突;
    2. 不含CPU的非智能器件,由廠家在器件內部固化,不可改變。

    高7位爲地址碼,其分爲兩部分:
    1. 高4位屬於固定地址不可改變,由廠家固化的統一地址;

    2. 低三位爲引腳設定地址,可以由外部引腳來設定(並非所有器件都可以設定);



主控器向被控器發送的信息種類有:啓動信號、停止信號、7位地址碼、讀/寫控制位、10位地址碼、數據字節、重啓動信號、應答信號、時鐘脈衝。
 
  被控器向主控器發送的信息種類有:應答信號、數據字節、時鐘低電平。
 
  下面對I2C總線通信過程中出現的幾種信號狀態和時序進行分析。
 
  ①總線空閒狀態。
 
  I2C總線總線的SDA和SCL兩條信號線同時處於高電平時,規定爲總線的空閒狀態。此時各個器件的輸出級場效應管均處在截止狀態,即釋放總線,由兩條信號線各自的上拉電阻把電平拉高。
 
  ②啓動信號。
 
  在時鐘線SCL保持高電平期間,數據線SDA上的電平被拉低(即負跳變),定義爲I2C總線總線的啓動信號,它標誌着一次數據傳輸的開始。

  啓動信號是一種電平跳變時序信號,而不是一個電平信號。啓動信號是由主控器主動建立的,在建立該信號之前I2C總線必須處於空閒狀態,如圖1所示。

  圖1  I2C總線上的啓動信號和停止信號

  ③停止信號。
 
  在時鐘線SCL保持高電平期間,數據線SDA被釋放,使得SDA返回高電平(即正跳變),稱爲I2C總線的停止信號,它標誌着一次數據傳輸的終止。
 
  停止信號也是一種電平跳變時序信號,而不是一個電平信號,停止信號也是由主控器主動建立的,建立該信號之後,I2C總線將返回空閒狀態。
 
  ④數據位傳送。   
 
  在I2C總線上傳送的每一位數據都有一個時鐘脈衝相對應(或同步控制),即在SCL串行時鐘的配合下,在SDA上逐位地串行傳送每一位數據。
 
  進行數據傳送時,在SCL呈現高電平期間,SDA上的電平必須保持穩定,低電平爲數據0,高電平爲數據1。
 
  只有在SCL爲低電平期間,才允許SDA上的電平改變狀態。邏輯0的電平爲低電壓,而邏輯1的電平取決於器件本身的正電源電壓VDD(當使用獨立電源時),如圖2所示。

  圖2  I2C總線上的數據位傳送

  ⑤應答信號。
 
  I2C總線上的所有數據都是以8位字節傳送的,發送器每發送一個字節,就在時鐘脈衝9期間釋放數據線,由接收器反饋一個應答信號。
 
  應答信號爲低電平時,規定爲有效應答位(ACK簡稱應答位),表示接收器已經成功地接收了該字節;應答信號爲高電平時,規定爲非應答位(NACK),一般表示接收器接收該字節沒有成功。
 
  對於反饋有效應答位ACK的要求是,接收器在第9個時鐘脈衝之前的低電平期間將SDA線拉低,並且確保在該時鐘的高電平期間爲穩定的低電平。

  如果接收器是主控器,則在它收到最後一個字節後,發送一個NACK信號,以通知被控發送器結束數據發送,並釋放SDA線,以便主控接收器發送一個停止信號P,如圖3所示。

  圖3 I2C總線上的應答時序

  ⑥插入等待時間。
  
  如果被控器需要延遲下一個數據字節開始傳送的時間,則可以通過把時鐘線SCL電平拉低並且保持,使主控器進入等待狀態。
  
  一旦被控器釋放時鐘線,數據傳輸就得以繼續下去,這樣就使得被控器得到足夠時間轉移已經收到的數據字節,或者準備好即將發送的數據字節。
  
  帶有CPU的被控器在對收到的地址字節做出應答之後,需要一定的時間去執行中斷服務子程序,來分析或比較地址碼,其間就把SCL線鉗位在低電平上,直到處理妥當後才釋放SCL線,進而使主控器繼續後續數據字節的發送,如圖4所示。

  圖4 I2C總線上的插入等待時間

  ⑦重啓動信號。
 
  在主控器控制總線期間完成了一次數據通信(發送或接收)之後,如果想繼續佔用總線再進行一次數據通信(發送或接收),而又不釋放總線,就需要利用重啓動Sr信號時序。
 
  重啓動信號Sr既作爲前一次數據傳輸的結束,又作爲後一次數據傳輸的開始。利用重啓動信號的優點是,在前後兩次通信之間主控器不需要釋放總線,這樣就不會丟失總線的控制權,即不讓其他主器件節點搶佔總線。

  ⑧時鐘同步。
 
  如果在某一I2C總線系統中存在兩個主器件節點,分別記爲主器件1和主器件2,其時鐘輸出端分別爲CLK1和CL【0,它們都有控制總線的能力。
 
  假設在某一期間兩者相繼向SCL線發出了波形不同的時鐘脈衝序列CLK1和CLK2(時鐘脈衝的高、低電平寬度都是依靠各自內部專用計數器定時產生的),在總線控制權還沒有裁定之前這種現象是可能出現的。
 
  鑑於I2C總線的“線與”特性,使得時鐘線SCL上得到的時鐘信號波形,既不像主器件1所期望的CLK1,也不像主器件2所期望的CLK2,而是兩者進行邏輯與的結果。
 
  CLKI和CLK2的合成波形作爲共同的同步時鐘信號,一旦總線控制權裁定給某一主器件,則總線時鐘信號將會只由該主器件產生,如圖5所示。

  圖5 I2C總線上的時鐘同步

  ⑨總線衝突和總線仲裁。
  
  假如在某I2C總線系統中存在兩個主器件節點,分別記爲主器件1和主器件2,其數據輸出端分別爲DATA1和DATA2,它們都有控制總線的能力,這就存在着發生總線衝突(即寫衝突)的可能性。
  
  假設在某一瞬間兩者相繼向總線發出了啓動信號,鑑於:I2C總線的“線與”特性,使得在數據線SDA上得到的信號波形是DATA1和DATA2兩者相與的結果,該結果略微超前送出低電平的主器件1,其DATA1的下降沿被當做SDA的下降沿。
  
  在總線被啓動後,主器件1企圖發送數據“101……”,主器件2企圖發送數據“100101……”。
  
  兩個主器件在每次發出一個數據位的同時都要對自己輸出端的信號電平進行抽檢,只要抽檢的結果與它們自己預期的電平相符,就會繼續佔用總線,總線控制權也就得不到裁定結果。
  
  主器件1的第3位期望發送“1”,也就是在第3個時鐘週期內送出高電平。
  
  在該時鐘週期的高電平期間,主器件1進行例行抽檢時,結果檢測到一個不相匹配的電平“0”,這時主器件1只好決定放棄總線控制杈;因此,主器件2就成了總線的惟一主宰者,總線控制權也就最終得出了裁定結果,從而實現了總線仲裁的功能。
  
  從以上總線仲裁的完成過程可以得出:仲裁過程主器件1和主器件2都不會丟失數據;各個主器件沒有優先級別之分,總線控制權是隨機裁定的,即使是搶先發送啓動信號的主器件1最終也並沒有得到控制杈。
  
  系統實際上遵循的是“低電平優先”的仲裁原則,將總線判給在數據線上先發送低電平的主器件,而其他發送高電平的主器件將失去總線控制權,如圖6所示。

  圖6 I2C總線上的總線仲裁

  ⑩總線封鎖狀態。
  
  在特殊情況下,如果需要禁止所有發生在I2C總線上的通信活動,封鎖或關閉總線是一種可行途徑,只要掛接於該總線上的任意一個器件將時鐘線SCL鎖定在低電平上即可。

I2C總線是由Philips公司開發的兩線式串行總線,用於連接微控制器和外圍設備。

      I2C總線支持多主控模式,任何能夠進行發送和接收的設備都可以成爲主設備。主控能夠控制數據的傳輸和時鐘頻率,在任意的時刻只能有一個主控。
      組成I2C總線的兩個信號爲數據線SDA和時鐘線SCL。爲避免總信號線的混亂,要求各設備連接到總線的輸出端必須是開漏輸出或集電極開路輸出的結構。根據這種結構的“線與”邏輯,I2C總線上任意器件輸出低電平都會使相應總線上的信號線變低。
      總線空閒時,上拉電阻使SDA和SCL線都保持高電平。
      數據線 SDA 的電平狀態必須在時鐘線 SCL 處於高電平期間保持穩定不變。SDA 的電平狀態只有在 SCL 處於低電平期間才允許改變。但是在 I2C總線的起始和結束時例外。
      當SCL穩定在高電平時,SDA由高到低的變化將產生一個開始位,而由低到高的變化則產生一個停止位。開始位和停止位都是由I2C主設備產生的。如果從設備採用7位地址,則主設備在發起傳輸前,需先發送一字節的地址信息,前7位爲設備地址,最後1位爲讀寫標誌。之後每次傳輸的數據也是一個字節,從MSB位(Most Significant Bit 最高有效位,對應有LSB: Least Significant Bit 最低有效位)開始傳輸。每個字節傳完後,在SCL的第9個上升沿到來之前,接受方應該發出一個ACK位。
      應答位的時鐘脈衝仍由主機產生,而應答位的數據狀態則遵循“誰接收誰產生”的原則,即總是由接收器產生應答位。主機向從機發送數據時,應答位由從機產生;主機從從機接收數據時,應答位由主機產生。I2C總線標準規定:應答位爲 0 表示接收器應答(ACK) ,常常簡記爲 A;爲 1 則表示非應答(NACK) ,常常簡記爲NA。發送器發送完 LSB 之後,應當釋放 SDA 線(拉高 SDA,輸出晶體管截止) ,以等待接收器產生應答位。
      在切換數據的傳輸方向時,可以不必先產生停止條件再開始下次傳輸,而是直接再一次產生開始條件。I2C 總線在已經處於忙的狀態下,再一次直接產生起始條件的情況被稱爲重複起始條件。例如:訪問某一具有 I2C總線接口的 E2PROM 存儲器時,主機先向存儲器輸入存儲單元的地址信息(發送數據) ,然後再讀取其中的存儲內容(接收數據)。
      帶有 I2C 總線的器件除了有從機地址(Slave Address)外,還可能有子地址。從機地址是指該器件在 I2C 總線上被主機尋址的地址, 而子地址是指該器件內部不同部件或存儲單元的編址。 與從機地址一樣,子地址實際上也是像普通數據那樣進行傳輸的,傳輸格式仍然是與數據相統一的,區分傳輸的到底是地址還是數據要靠收發雙方具體的邏輯約定。子地址的長度必須由整數個字節組成,可能是單字節(8 位子地址) ,也可能是雙字節(16 位子地址) ,還可能是 3 字節以上,這要看具體器件的規定。

         

          I2C體系結構分3個部分:I2C核心、I2C總線驅動、I2C設備驅動。

      I2C核心提供了I2C總線驅動和設備驅動的註冊、註銷方法,I2C通信方法上層的、與具體適配器無關的代碼以及探測設備、檢測設備地址的上層代碼等。

      I2C總線驅動是對I2C硬件體系結構中適配器端的實現,適配器可由CPU控制,甚至可以直接集成在CPU內部。包含了i2c_adapter、i2c_algorithm和控制I2C適配器產生通信信號的函數。通過I2C總線驅動的代碼,我們可以控制I2C適配器以主控方式產生開始位、停止位讀寫週期,以及以從設備方式被讀寫,產生ACK等。

          I2C設備驅動是對I2C硬件體系結構中設備端的實現,設備一般掛接在受CPU控制的I2C適配器上,通過I2C適配器與CPU交換數據。包含了i2c_driver和i2c_client。

      所有的I2C設備都在sysfs文件系統中顯示,存於/sys/bus/i2c/目錄下,以適配器地址和芯片地址的形式列出。

      i2c_adapter對應於物理上的一個適配器,而i2c_algorithm對應一套通信方法。一個I2C適配器需要i2c_algorithm提供的通信函數來控制適配器上產生特定的訪問週期。缺少i2c_algorithm的i2c_adapter什麼也做不了,因此i2c_adapter中包含其使用的i2c_algorithm的指針。

      i2c_driver對應一套驅動方法,是純粹的用於輔助作用的數據結構,它不對應於任何的物理實體。i2c_client對應於真實的物理設備,每個I2C設備都需要一個i2c_client來描述。i2c_client一般被包含在I2C字符設備的私有信息結構體中。

      i2c_driver於i2c_client發生關聯的時刻在i2c_driver的attach_adapter()函數被運行時。attach_adapter()會探測物理設備,當確定一個client存在時,把該client使用的i2c_client數據結構的adapter指針指向對應的i2c_adapter,driver指針指向該i2c_driver,並會調用i2c_adapter的client_register()函數。相反的過程會發生在i2c_driver的detach_client()函數被調用的時候。

      
      i2c_transfer()函數用於進行I2C適配器和I2C設備之間的一組消息交互,i2c_master_send()函數和i2c_master_recv()函數內部會調用i2c_transfer()函數分別完成一條寫消息和一條讀消息。i2c_transfer()函數本身並不具備驅動適配器物理硬件完成消息交互的能力,它只是尋找到i2c_adapter對應的i2c_algorithm,並使用i2c_algorithm的master_xfer函數真正驅動硬件流程。

      I2C總線驅動模塊加載函數需完成兩個工作:

      1.初始化I2C適配器所使用的硬件資源,如申請I/O地址、中斷號等。

      2.通過i2c_add_adapter()添加i2c_adapter的數據結構,當然這個i2c_adapter數據結構的成員已經被xxx適配器的相應函數指針所初始化。

      I2C總線驅動模塊的卸載函數要完成的工作與加載函數相反。

      I2C總線通信方法:我們要爲特定的I2C適配器實現其通信方法,主要實現i2c_algorithm的master_xfer()函數和functionality()函數。functionality()函數用於返回algorithm所支持的通信協議,如I2C_FUNC_I2C、I2C_FUNC_10BIT_ADDR、I2C_FUNC_SMBUS_READ_BYTE、I2C_FUNC_SMBUS_WRITE_BYTE等。master_xfer()函數在I2C適配器上完成傳遞給它的i2c_msg數組中的每個I2C消息。

      master_xfer()函數處理I2C消息數組,對於數組中的每個消息,判斷消息類型,若爲讀消息,則賦從設備地址爲(msg->addr<<1)| 1 ,否則爲msg->addr<<1(賦地址爲setaddr)。對每個消息產生一個開始位,緊接着傳送從設備地址,然後開始數據的發送或接收,對最後的消息還需產生一個停止位。

       I2C設備驅動(i2c_driver和i2c_client)。

       I2C設備驅動要使用i2c_driver和i2c_client數據結構並填充其中的成員函數。i2c_client一般被包含在設備的私有信息結構體yyy_data中,而i2c_driver則適合被定義成全局變量並初始化。

       I2C設備驅動的模塊加載函數中會做:

       (1)通過register_chrdev()函數將I2C設備註冊爲一個字符設備。

       (2)通過I2C核心的i2c_add_driver()函數添加i2c_driver。

       模板卸載函數中則相反。

       yyy_init()->i2c_add_driver()->yyy_attach_adapter()->i2c_probe()->yyy_detect()->i2c_client初始化->i2c_attach_client()->yyy_init_client

       yyy_exit()->i2c_del_driver()->yyy_detach_client()->i2c_detach_client()

       作爲一種字符類設備,Linux I2C設備驅動的文件操作接口與普通的設備驅動是完全一致的。I2C設備的寫操作經歷瞭如下幾個步驟:

       (1)從用戶空間到字符設備驅動寫函數接口,寫函數構造I2C消息數組。

       (2)寫函數把構造的I2C消息數組傳遞給I2C核心的傳輸函數i2c_transfer()。

       (3)I2C核心的傳輸函數i2c_transfer()找到對應適配器algorithm的通信方法函數master_xfer()去最終完成I2C消息的處理。

       read()/write()(用戶空間)->yyy_read()/yyy_write()(I2C設備驅動文件操作接口)->i2c_transfer()(I2C核心)->master_xfer()(I2C總線驅動)

       i2c-dev.c文件完全可以被看做一個I2C設備驅動,不過,它實現的一個i2c_client是虛擬、臨時的,隨着設備文件的打開而產生,並隨設備文件的關閉而撤銷,並沒有被添加到i2c_adapter的clients鏈表中。i2c-dev.c針對每個I2C適配器生成一個主設備號爲89的設備文件,實現了i2c_driver的成員函數以及文件操作接口,所以,i2c-dev.c的主體式“i2c_driver成員函數+字符設備驅動”。

      i2c-dev.c中提供i2cdev_read()、i2cdev_write()函數來對應用戶空間要使用的read()和write()文件操作接口,這兩個函數分別調用I2C核心的i2c_master_recv()和i2c_master_send()函數來構造一條I2C消息並引發適配器algorithm通信函數的調用,完成消息的傳輸。i2cdev_read()和i2cdev_write()函數不具備太強的通用性,滅有太大的使用價值,只能適用於非RepStart模式的情況。對於兩條以上消息組成的讀寫,在用戶空間需要組織i2c_msg消息數組並調用I2C_RDWR IOCTL命令。    



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