Search This Blog

Nov 22, 2010

Chapter 5 MX53 OBDS I2C Module

Chapter 5 MX53 OBDS I2C Module
-- Mark Ding
5. iMX53 I2C setting.
  This chapter talking about OBDS I2C module in detail. We can customize the code base on customer’s hardware board.



5.1 I2C IOMUX setting.
In “src/mx53/hardware.c”, function void io_cfg_i2c(u32 module_base),
        /* I2C1 mux'd out on CSI0_DAT8 and CSI0_DAT9 pads */
       /* I2C1_SDA ALT5 on CSI0_DAT8 IOMUX setup */
       writel(0x10 | ALT5, IOMUXC_SW_MUX_CTL_PAD_CSI0_DAT8);
       /* I2C1_SDA is involved in the Daisy Chain */
       writel(0x0, IOMUXC_I2C1_IPP_SDA_IN_SELECT_INPUT);
       writel(0x1EC, IOMUXC_SW_PAD_CTL_PAD_CSI0_DAT8);

       /* I2C1_SCL ALT5 on CSI0_DAT8 IOMUX setup */
       writel(0x10 | ALT5, IOMUXC_SW_MUX_CTL_PAD_CSI0_DAT9);
       /* I2C1_SCL is involved in the Daisy Chain */
       writel(0x0, IOMUXC_I2C1_IPP_SCL_IN_SELECT_INPUT);
       writel(0x1EC, IOMUXC_SW_PAD_CTL_PAD_CSI0_DAT9);




5.2 I2C module files.
 “src/drivers/i2c/imx_i2c.c” ----  i2c driver code.
 “src/include/imx_i2c.h”   ---- i2c pre-definition




5.3 I2C module funcions
  • OBDS I2C transfer function is  int i2c_xfer(u32 base, struct imx_i2c_request *rq, int dir).  structure imx_i2c_request controls I2C device transfer information.

struct imx_i2c_request
{
   u32 dev_addr;      // the I2C DEVICE address
   u32 reg_addr;      // the actual REGISTER address
   u32 reg_addr_sz;   // number of bytes for the address of I2C device register
   u8 * buffer;     // buffer to hold the data
   u32 buffer_sz;     // the number of bytes for read/write
};

  • Example for I2C transfer:

   struct imx_i2c_request rq;
   rq.dev_addr = 0x18; //TLV
   rq.reg_addr = buf[0];
   rq.reg_addr_sz = 1;
   rq.buffer_sz = 1;
   rq.buffer = data;
   ret = i2c_xfer(I2C1_BASE_ADDR, &rq, 1);
   if(ret !=0)
   {
       printf("i2c transfer error ret=%d\n",ret);
   }
   printf1("i2c rx complete.\n");

5.4 I2C MX53 register setting
  Detail information please refer iMX53RM.pdf “Chapter 31 Inter IC Module (I2C)”
  • All I2C regisiter 


  • I2C Control Register (I2CR)


  • I2C Status Register (I2SR)


5.5 I2C communication
  • We look into int i2c_xfer(u32 base, struct imx_i2c_request *rq, int dir).

int i2c_xfer(u32 base, struct imx_i2c_request *rq, int dir)
{
   unsigned int reg;
   unsigned char i, data;
   unsigned short i2cr;
   int ret = 0;
   if (rq->buffer_sz == 0 || rq->buffer == NULL)
   {
       printf("Invalid register address size=%x, buffer size=%x, buffer=%x\n",
              rq->reg_addr_sz, rq->buffer_sz, (unsigned int)rq->buffer);
       return -1;
   }
   /* Check if bus is free, if not return error */
   if (is_bus_free(base) != 0)
   {
       return -1;
   }
   // reset and enable I2C
   writew(0, base + I2C_I2CR);
   writew(I2C_I2CR_IEN, base + I2C_I2CR);
   /* Need wait at least 2 cycles of per_clk*/
   hal_delay_us(5000);
   // 1.2 clear both IAL and IIF bits
   writew(0, base + I2C_I2SR);

   // 1.3 assert START signal and also indicate TX mode
   i2cr = I2C_I2CR_IEN;
   writew(i2cr, base + I2C_I2CR);
   i2cr = I2C_I2CR_IEN | I2C_I2CR_MTX;
   writew(i2cr, base + I2C_I2CR);
   i2cr = I2C_I2CR_IEN | I2C_I2CR_MSTA | I2C_I2CR_MTX;
   writew(i2cr, base + I2C_I2CR);

   // 1.4 make sure bus is busy after the START signal
   if (wait_till_busy(base) != 0)
   {
       printf1("1\n");
       return -1;
   }
   /* Set the Transmit bit */
   i2cr |= I2C_I2CR_MTX;
   writew(i2cr, base + I2C_I2CR);

   // Step 2: send slave address + read/write at the LSB
   data = (rq->dev_addr << 1) | I2C_WRITE;

   if ((ret = tx_byte(&data, base)) != 0)
   {
       printf1("START TX ERR %d %d\n", __LINE__, ret);
       if (ret == ERR_NO_ACK)
       {
           return ERR_NO_ACK_ON_START;
       }
       else
       {
           return ret;
       }
   }

   // Step 3: send I2C device register address
   if (rq->reg_addr_sz > 4)
   {
       printf("Warning register address size %d should less than 4\n",
              rq->reg_addr_sz);
       rq->reg_addr_sz = 4;
   }

   reg = rq->reg_addr;

   for (i = 0; i <  rq->reg_addr_sz; i++, reg>>=8)
   {
       data = reg & 0xFF;
       printf1("sending I2C=0x%x device register: data=0x%x, byte %d\n",
               base, data, i);
       if (tx_byte(&data, base) != 0)
       {
           return -1;
       }
   }
   // Step 4: read/write data
   if (dir == I2C_READ)
   {
       // do repeat-start
       i2cr = readw(base + I2C_I2CR);
       writew(i2cr | I2C_I2CR_RSTA, base + I2C_I2CR);

       // make sure bus is busy after the REPEATED START signal
       if (wait_till_busy(base) != 0)
       {
           return ERR_TX;
       }
       // send slave address again, but indicate read operation
       data = (rq->dev_addr << 1) | I2C_READ;

       if (tx_byte(&data, base) != 0)
       {
           return -1;
       }

       // change to receive mode
       i2cr = readw(base + I2C_I2CR);

       if (rq->buffer_sz == 1)
       {
           // if only one byte to read, make sure don't send ack
           i2cr |= I2C_I2CR_TXAK;
       }

       writew(i2cr & ~I2C_I2CR_MTX, base + I2C_I2CR);
       // dummy read
       readw(base + I2C_I2DR);
       // now reading ...
       if (rx_bytes(rq->buffer, base, rq->buffer_sz) != 0)
       {
           return -1;
       }
   }
   else
   {
       // I2C_WRITE
       for (i = 0; i < rq->buffer_sz; i++)
       {
           // send device register value
           data = rq->buffer[i];

           if ((ret = tx_byte(&data, base)) != 0)
           {
               break;
           }
       }
       // generate STOP by clearing MSTA bit
       imx_send_stop(base);
   }
   return ret;
}

  • I2C protocol


  • Arbitration lost
    • We might met this message in I2C communication, the message comes from read I2C status register.
        if (readw(base + I2C_I2SR) & I2C_I2SR_IAL)
        {
            printf("Error: arbitration lost!\n");
            return -1;
        }
    •     If several devices try to engage the bus at the same time, one becomes master. Hardware immediately switches devices that lose arbitration to slave receive mode. Data output to SDA stops, but SCL is still generated until the end of the byte during which arbitration is lost. An interrupt occurs at the falling edge of the ninth clock of this transfer if the arbitration is lost (I2SR[IAL] = 1), and the slave mode is selected (I2CR[MSTA] = 0). See the flow chart in Figure 35-13.
    •     If a device that is not a master tries to transmit or do a START, hardware inhibits the transmission, clears MSTA without signalling a STOP, generates an interrupt to the CPU, and sets I2SR[IAL] to indicate a failed attempt to engage the bus. When considering these cases, the slave service routine should first test I2SR[IAL], and the software should clear it if it is set. For Multi-master mode, when an I2C module is enabled when the bus is busy and asserts START, the I2SR[IAL] bit gets set only for SDA=0, SCL=0/1, SDA=1, and SCL=0, but not for SDA=1 and SCA=1, which is the same as bus idle state.
  • Caution:
    •    We have met one Arbitration lost due to iMX53 TO1 power up sequence hardware setting not correct.,The I2C module works abnormal at this case. We captured I2C waveform and found after 9th CLK, SCL has a very narrow low waveform and then SDA raise high. It generate arbitration lost error. With fine tune hardware power up sequence, the I2C module works OK.

Nov 1, 2010

二 存养善性(四)

公都子问曰,钧是人也,或为大人,或为小人,何也?
孟子曰,从其大体为大人,从其小体为小人。
曰,钧是人也,或从其大体,或从其小体。何也。
曰,耳目之官不思,而蔽于物。物交物,则引之而已矣。心之官则思,思则得之,不思则不得也。此天之所与我者,先立乎其大者,则其小者不能夺也。此为大人而已矣。(告子,上,一五)

语译
公都子问说,同样是人,有的人是大人,有的人是小人,什么原因呢?
孟子说,随着本心所具的善性行事就是大人,随着耳目之类的欲望行事就是小人。
公都子说,同样是人,有的人能照着本心行事,有得人却照着感官欲望行事,这又是什么原因?
孟子说,耳朵眼睛这类器官不会思考,因为会为外物所蒙蔽,(即如此,耳目也不过是一物而已)一与外在的声色等事物相接触,则被引诱而去。心这种器官职司思考,能够思考,就能得到仁义礼智等义理的实践,不思考,便不能得。这些器官都是上天赐给我们的,要先立定大体的心,那小体的耳目之欲,就不会夺去心志之官能,这样就可以成为大人了。

体会
大人,这个平时广泛使用的词语,里面的含义却没有体会。我们对孩子们自称大人,贫民对官员们称呼大人。 大人,是指大德之人。孟子心目中的大人是在善,信,美之上,而在圣,神之下,集信善美于一身,而又能光大之,因此可称为大德之人。 看到此,大人这个称呼实在是要努力去做才行。

发自我的 iPad