I2C 協議

1.I2C協議
  
   2條雙向串行線,一條數據線SDA,一條時鐘線SCL。
   SDA傳輸數據是大端傳輸,每次傳輸8bit,即一字節。
   支持多主控(multimastering),任何時間點只能有一個主控。
   總線上每個設備都有自己的一個addr,共7個bit,廣播地址全0.
   系統中可能有多個同種芯片,爲此addr分爲固定部分和可編程部份,細節視芯片而定,看datasheet。

1.1 I2C位傳輸

   數據傳輸:SCL爲高電平時,SDA線若保持穩定,那麼SDA上是在傳輸數據bit;
             若SDA發生跳變,則用來表示一個會話的開始或結束(後面講)
   數據改變:SCL爲低電平時,SDA線才能改變傳輸的bit



1.2 I2C開始和結束信號
   
   開始信號:SCL爲高電平時,SDA由高電平向低電平跳變,開始傳送數據。
   結束信號:SCL爲高電平時,SDA由低電平向高電平跳變,結束傳送數據。

  

1.3 I2C應答信號
   
   Master每發送完8bit數據後等待Slave的ACK。
   即在第9個clock,若從IC發ACK,SDA會被拉低。
   若沒有ACK,SDA會被置高,這會引起Master發生RESTART或STOP流程,如下所示:



1.4 I2C寫流程

寫寄存器的標準流程爲:
1.    Master發起START
2.    Master發送I2C addr(7bit)和w操作0(1bit),等待ACK
3.    Slave發送ACK
4.    Master發送reg addr(8bit),等待ACK
5.    Slave發送ACK
6.    Master發送data(8bit),即要寫入寄存器中的數據,等待ACK
7.    Slave發送ACK
8.    第6步和第7步可以重複多次,即順序寫多個寄存器
9.    Master發起STOP

寫一個寄存器




寫多個寄存器

1.5 I2C讀流程

讀寄存器的標準流程爲:
1.    Master發送I2C addr(7bit)和w操作1(1bit),等待ACK
2.    Slave發送ACK
3.    Master發送reg addr(8bit),等待ACK
4.    Slave發送ACK
5.    Master發起START
6.    Master發送I2C addr(7bit)和r操作1(1bit),等待ACK
7.    Slave發送ACK
8.    Slave發送data(8bit),即寄存器裏的值
9.    Master發送ACK
10.    第8步和第9步可以重複多次,即順序讀多個寄存器

讀一個寄存器


讀多個寄存器



2. PowerPC的I2C實現

Mpc8560的CCSR中控制I2C的寄存器共有6個。




2.1 I2CADR 地址寄存器

CPU也可以是I2C的Slave,CPU的I2C地址有 I2CADR指定

 

2.2 I2CFDR 頻率設置寄存器

The serial bit clock frequency of SCL is equal to the CCB clock divided by the divider.
用來設置I2C總線頻率



2.3 I2CCR 控制寄存器



MEN: Module Enable.    置1時,I2C模塊使能
MIEN:Module Interrupt Enable. 置1時,I2C中斷使能。
MSTA:Master/slave mode. 1 Master mode,0 Slave mode.
        當1->0時,CPU發起STOP信號
        當0->1時,CPU發起START信號
MTX:Transmit/receive mode select.0 Receive mode,1 Transmit mode
TXAK:Transfer acknowledge. 置1時,CPU在9th clock發送ACK拉低SDA
RSTA:Repeat START. 置1時,CPU發送REPEAT START
BCST:置1,CPU接收廣播信息(信息的slave addr爲7個0)

2.4 I2CSR 狀態寄存器




MCF:0  Byte transfer is in process
     1  Byte transfer is completed

MAAS:當CPU作爲Slave時,若I2CDR與會話中Slaveaddr匹配,此bit被置1

MBB:0 I2C bus idle  
     1 I2C bus busy

MAL:若置1,表示仲裁失敗
BCSTM:若置1,表示接收到廣播信息

SRW:When MAAS is set, SRW indicates the value of the R/W command bit of the calling address, which is sent from the master.
   0 Slave receive, master writing to slave
   1 Slave transmit, master reading from slave

MIF:Module interrupt. The MIF bit is set when an interrupt is pending, causing a processor interrupt request(provided I2CCR[MIEN] is set)

RXAK:若置1,表示收到了ACK

2.5 I2CDR 數據寄存器



這個寄存器儲存CPU將要傳輸的數據。


3. PPC-Linux中I2C的實現

 
  內核代碼(linux-2.6.24)中,通過I2C總線存取寄存器的函數都在文件drivers/i2c/busses/i2c-mpc.c中
  最重要的函數是mpc_xfer.
  
  1. static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
  2. {
  3.     struct i2c_msg *pmsg;
  4.     int i;
  5.     int ret = 0;
  6.     unsigned long orig_jiffies = jiffies;
  7.     struct mpc_i2c *i2c = i2c_get_adapdata(adap);

  8.     mpc_i2c_start(i2c);    // 設置I2CCR[MEN], 使能I2C module 

  9.     /* Allow bus up to 1s to become not busy */
  10.     //一直讀I2CSR[MBB],等待I2C總線空閒下來
  11.     while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
  12.         if (signal_pending(current)) {
  13.             pr_debug("I2C: Interrupted\n");
  14.             writeccr(i2c, 0);
  15.             return -EINTR;
  16.         }
  17.         if (time_after(jiffies, orig_jiffies + HZ)) {
  18.             pr_debug("I2C: timeout\n");
  19.             if (readb(i2c->base + MPC_I2C_SR) ==
  20.                 (CSR_MCF | CSR_MBB | CSR_RXAK))
  21.                 mpc_i2c_fixup(i2c);
  22.             return -EIO;
  23.         }
  24.         schedule();
  25.     }

  26.     for (= 0; ret >= 0 && i < num; i++) {
  27.         pmsg = &msgs[i];
  28.         pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages\n",
  29.              pmsg->flags & I2C_M_RD ? "read" : "write",
  30.              pmsg->len, pmsg->addr, i + 1, num);
  31.         //根據消息裏的flag進行讀操作或寫操作
  32.         if (pmsg->flags & I2C_M_RD) 
  33.             ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  34.         else
  35.             ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
  36.     }
  37.     mpc_i2c_stop(i2c);    //保證爲I2CCSR[MSTA]爲0,保證能觸發STOP
  38.     return (ret < 0) ? ret : num;
  39. }


  1. static int mpc_write(struct mpc_i2c *i2c, int target,
  2.              const u8 * data, int length, int restart)
  3. {
  4.     int i;
  5.     unsigned timeout = i2c->adap.timeout;
  6.     u32 flags = restart ? CCR_RSTA : 0;

  7.     /* Start with MEN */    //以防萬一,保證I2C模塊使能起來
  8.     if (!restart)
  9.         writeccr(i2c, CCR_MEN);
  10.     /* Start as master */       //寫了I2CCR[CCR_MSTA],觸發CPU發起START信號
  11.     writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
  12.     /* Write target byte */     //CPU發送一個字節,slave I2C addr和0 (寫操作bit) 
  13.     writeb((target << 1), i2c->base + MPC_I2C_DR);

  14.     if (i2c_wait(i2c, timeout, 1) < 0)    //等待slave 發ACK
  15.         return -1;

  16.     for (= 0; i < length; i++) {
  17.         /* Write data byte */
  18.         writeb(data[i], i2c->base + MPC_I2C_DR); //CPU接着發數據,包括reg addr和data

  19.         if (i2c_wait(i2c, timeout, 1) < 0)       //等待slave 發ACK
  20.             return -1;
  21.     }

  22.     return 0;
  23. }


  1. static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
  2. {
  3.     unsigned long orig_jiffies = jiffies;
  4.     u32 x;
  5.     int result = 0;

  6.     if (i2c->irq == 0)
  7.     {    //循環讀I2CSR,直到I2CSR[MIF]置1
  8.         while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
  9.             schedule();
  10.             if (time_after(jiffies, orig_jiffies + timeout)) {
  11.                 pr_debug("I2C: timeout\n");
  12.                 writeccr(i2c, 0);
  13.                 result = -EIO;
  14.                 break;
  15.             }
  16.         }
  17.         x = readb(i2c->base + MPC_I2C_SR);
  18.         writeb(0, i2c->base + MPC_I2C_SR);
  19.     } else {
  20.         /* Interrupt mode */
  21.         result = wait_event_interruptible_timeout(i2c->queue,
  22.             (i2c->interrupt & CSR_MIF), timeout * HZ);

  23.         if (unlikely(result < 0)) {
  24.             pr_debug("I2C: wait interrupted\n");
  25.             writeccr(i2c, 0);
  26.         } else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
  27.             pr_debug("I2C: wait timeout\n");
  28.             writeccr(i2c, 0);
  29.             result = -ETIMEDOUT;
  30.         }

  31.         x = i2c->interrupt;
  32.         i2c->interrupt = 0;
  33.     }

  34.     if (result < 0)
  35.         return result;

  36.     if (!(& CSR_MCF)) {
  37.         pr_debug("I2C: unfinished\n");
  38.         return -EIO;
  39.     }

  40.     if (& CSR_MAL) {    //仲裁失敗
  41.         pr_debug("I2C: MAL\n");
  42.         return -EIO;
  43.     }

  44.     if (writing && (& CSR_RXAK)) {//寫後沒收到ACK
  45.         pr_debug("I2C: No RXAK\n");
  46.         /* generate stop */
  47.         writeccr(i2c, CCR_MEN);
  48.         return -EIO;
  49.     }
  50.     return 0;
  51. }

  1. static int mpc_read(struct mpc_i2c *i2c, int target,
  2.             u8 * data, int length, int restart)
  3. {
  4.     unsigned timeout = i2c->adap.timeout;
  5.     int i;
  6.     u32 flags = restart ? CCR_RSTA : 0;

  7.     /* Start with MEN */    //以防萬一,保證I2C模塊使能
  8.     if (!restart)
  9.         writeccr(i2c, CCR_MEN);
  10.     /* Switch to read - restart */
  11.     //注意這裏,再次把CCR_MSTA置1,再觸發 START 
  12.     writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);


  13.     /* Write target address byte - this time with the read flag set */ 
  14.     //CPU發送slave I2C addr和讀操作1
  15.     writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
      
     //等待Slave發ACK
  1.     if (i2c_wait(i2c, timeout, 1) < 0)
  2.         return -1;

  3.     if (length) {
  4.         if (length == 1)
  5.             writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
  6.         else //爲什麼不置 TXAK
  7.             writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
  8.         /* Dummy read */
  9.         readb(i2c->base + MPC_I2C_DR);
  10.     }

  11.     for (= 0; i < length; i++) {
  12.         if (i2c_wait(i2c, timeout, 0) < 0)
  13.             return -1;

  14.         /* Generate txack on next to last byte */
  15.         //注意這裏TXAK置1,表示CPU每收到1byte數據後,會發送ACK
  16.         if (== length - 2) 
  17.             writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);

  18.         /* Generate stop on last byte */
  19.         //注意這裏CCR_MSTA [1->0] CPU會觸發STOP
  20.         if (== length - 1)    
  21.             writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);

  22.         data[i] = readb(i2c->base + MPC_I2C_DR);
  23.     }

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