i2c issue on i.mx51

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i2c issue on i.mx51

1,248 Views
bottleneck
Contributor II

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

Labels (1)
0 Kudos
4 Replies

848 Views
jimmychan
NXP TechSupport
NXP TechSupport

I think you may take the i.MX53 OBDS for reference. There is a I2C code.

On-Board Diagnostic Suit for the i.MX53 Quick Start Board

0 Kudos

848 Views
bottleneck
Contributor II

Could atleast help me what are the necessary mux and pad configurations to be enabled for SGTL5000 to respond.

0 Kudos

848 Views
jimmychan
NXP TechSupport
NXP TechSupport

According to the schematic of i.MX51EVK, the ctrl_data and ctrl_clk of SGTL5000 is connect to the I2C2_SDA and I2C2_SCL. And these two I2C2 pins are the KEY_COL4 and KEY_COL5. So, please check the IOMUX and PAD setting for these two pins are proper.

For the IOMUX example, you can take the Linux BSP for reference.

This is the iomux-mx51.h:

linux-2.6-imx.git - Freescale i.MX Linux Tree

The iomux-mx51.h defined all the pin mux and pad setting. You can find below settings for I2C2 in this file.

#define MX51_I2C_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_ODE | \ PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP | \ PAD_CTL_HYS)

#define _MX51_PAD_KEY_COL4__I2C2_SCL IOMUX_PAD(0x65c, 0x26c, 0x13, 0x09b8, 1, 0)

#define _MX51_PAD_KEY_COL5__I2C2_SDA IOMUX_PAD(0x660, 0x270, 0x13, 0x09bc, 1, 0)

#define MX51_PAD_KEY_COL4__I2C2_SCL (_MX51_PAD_KEY_COL4__I2C2_SCL | MUX_PAD_CTRL(MX51_I2C_PAD_CTRL))

#define MX51_PAD_KEY_COL5__I2C2_SDA (_MX51_PAD_KEY_COL5__I2C2_SDA | MUX_PAD_CTRL(MX51_I2C_PAD_CTRL))

let take the _MX51_PAD_KEY_COL4__I2C2_SCL for example:

(0x65C is the PAD setting offset address,

0x26C is the IOMUX setting offset address,

0x13 is SION=1, ALT3

0x09b8 is the offset address of daisy chain input select

1 is the "input select" for KEY_COL4 for Mode:ALT3.)

For more details, please read the "IOMUXC" in  i.MX51 Reference Manual.

Then for i.MX51EVK, the specific pin mux will be defined in board-mx51_babbage.c "mx51babbage_pads[]":

linux-2.6-imx.git - Freescale i.MX Linux Tree

0 Kudos

847 Views
bottleneck
Contributor II

Thanks for the reply. could you identify what actual mux and pad configurations are required. Since I am working for QNX driver and trying to understand what configurations is missed. In the link shared I found the following function,

io_cfg_i2c(base);

and its implementation in hardware.c

But what actual configuration is been missed in the above shared snippet. Looking for suggestions.

Thanks

0 Kudos