AnsweredAssumed Answered

i2c issue on i.mx51

Question asked by Eshvar Esh on Jun 7, 2015
Latest reply on Jun 16, 2015 by jimmychan

Hi

Please check the following code snippet to read and write on i2c, i2c read gives wrong data. I am trying to reads the chip id of SGTL5000's chip id on i.mx51 EVK board it should return 0xA000 but the code returns 0xff. Looking for quick solutions,

 

void mx6q_i2c_reset(void){

    // Reset I2C registers

    out16(dev_r->regbase + I2C_AR, 0);

    out16(dev_r->regbase + I2C_IFDR, 0);

    out16(dev_r->regbase + I2C_I2CR, 0);

    out16(dev_r->regbase + I2C_I2SR, 0);

}

 

void i2c_init(void){

    // I2C clock rate

    out16(dev_r->regbase + I2C_IFDR, dev_r->div);

}

 

static int wait_op_done(int is_tx)

{

    int i = 0;

    volatile unsigned char stats;

    i = WAIT_RXAK_LOOPS;

 

     while ((((stats = in16(dev_r->regbase + I2C_I2SR)) & I2C_I2SR_ICF) == 0 )&& --i > 0){

    //while ((((stats = in16(dev_r->regbase + I2C_I2SR)) & I2C_I2SR_IIF) == 0 ||

      //     (stats & I2C_I2SR_ICF) == 0)) {

         if (stats & I2C_I2SR_IAL) {

            printf("Arbitration lost\n");

                  return -1;

        }

    }

 

    if (i <= 0) {

        printf("wait op done timeout unexpected\n");

        return -1;

    }

    if (is_tx) {

        if (stats & I2C_I2SR_IAL) {

            printf("Arbitration lost\n");

            return -1;

        }

        if (stats & I2C_I2SR_RXAK) {

            printf("No ack received\n");

            return -1;

        }

    }

 

    return 0;

}

 

static inline int wait_till_busy()

{

    int i = I2C_WAIT_CNT;

 

    while (((in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IBB) == 0) && (--i > 0)) {

        if (in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IAL) {

            printf("arbitration lost!\n");

           return -1;

        }

    }

 

    if (i <= 0) {

        printf(" timeout unexpected\n");

        return -1;

    }

 

    return 0;

}

static uint16_t tx_byte(uint16_t *data){

 

    out16(dev_r->regbase + I2C_I2SR, 0);

    printf("tx byte data 0x%x\n",*data);

    out16(dev_r->regbase + I2C_I2DR, *data);

 

    if (wait_op_done(1) != 0)

        return -1;

    return 0;

}

 

static uint16_t rx_byte(uint16_t *data)

{

    unsigned short i2cr;

 

    if (wait_op_done(0) != 0)

       return -1;

    out16(dev_r->regbase + I2C_I2SR, 0);

    i2cr = in16(dev_r->regbase + I2C_I2CR);

    out16(dev_r->regbase + I2C_I2CR, (i2cr & ~( I2C_I2CR_MSTA | I2C_I2CR_MTX)));

    *data = in16(dev_r->regbase + I2C_I2DR);

    printf("rx byte data 0x%x\n",*data); //when data is read from SGTL5000 chip id register gives wrong data.

 

    return 0;

}

 

static uint16_t i2c_transaction(uint16_t reg, uint16_t * val, int dir){

 

    volatile int i,i2cr=0;

    uint16_t data;

    int ret = 0;

 

    i2cr |= I2C_I2CR_IEN;

    out16(dev_r->regbase + I2C_I2CR,i2cr);

    for (i = 0; i < 100; i++) ;

 

    /* Check if bus is free */

    if ((in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IBB) != 0) {

            printf(" Bus is not free\n");

            return -1;

    }

    /* Set Device address to I2C Address Register*/

    data = ((dev_r->slave << 1) | I2C_WRITE) & 0xFF;

    out16(dev_r->regbase + I2C_AR , data);

 

    /* Start I2C Transaction */

    i2cr |= I2C_I2CR_MSTA | I2C_I2CR_MTX;

 

    out16(dev_r->regbase + I2C_I2CR, i2cr);

 

    /*Write Device Address to Data Register*/

     if (tx_byte(&data) != 0) {

        printf("Failed to transmit slave address\n");

        return -1;

    }

 

    // make sure bus is busy after the START signal

   if (wait_till_busy() != 0) {

        printf("Bus is not busy\n");

        return -1;

    }

    // send I2C device register address

    data = reg & 0xFF;

 

    if (tx_byte(&data) != 0) {

        printf(" Failed to transmit device register address\n");

        return -1;

    }

 

    if (dir == I2C_WRITE) {

            data = *val & 0xFFFF;

            if((ret = tx_byte(&data)) != 0) {

                printf(" Failed to transmit data while write\n");

            }

 

            out16(dev_r->regbase + I2C_I2CR, (I2C_I2CR_IEN | I2C_I2CR_MTX));

    }

    else {

        // do repeat-start

        i2cr = in16(dev_r->regbase + I2C_I2CR);

        out16(dev_r->regbase + I2C_I2CR, (i2cr | I2C_I2CR_RSTA));

 

        // send slave address again, but indicate read operation

        data = ((dev_r->slave << 1) | I2C_READ) & 0xFF;

 

        if (tx_byte(&data) != 0) {

            printf(" Failed to transmit slave address in read\n");

            return -1;

        }

 

        // change to receive mode

        i2cr = in16(dev_r->regbase + I2C_I2CR);

 

        // read only one byte, make sure don't send ack

        //i2cr |= I2C_I2CR_TXAK;

        i2cr &= ~(I2C_I2CR_MTX);

        out16(dev_r->regbase + I2C_I2CR, i2cr);

 

        // dummy read

        in16(dev_r->regbase + I2C_I2DR);

 

        // now reading

        if (rx_byte(&data) != 0) {

            printf(" Failed to receive data\n");

            return -1;

        }

        *val = data;

        printf("data from i2c 0x%x\n",*val);

 

    }

 

    return ret;

}

 

/**** from read file operations sending the reg address to be read ***/

 

dev_r->reg = 0x0000;

 

/**** from write  file operations sending the reg address to be read ***/

dev_r->reg = 0x0000;

    dev_r->val = 0x0010;

 

Other initializations like slave address and setting up frequency divider value

dev->div     = 0x16;

dev->slave      = 0x0A;

 

Please provide suggestions where logics are going wrong.

 

Thanks

Outcomes