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){
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 or any configuration is missed.
I have not implemented mux and pad configurations of i.mx51 in the RM, since those
configurations are taken care in BSP, should I re-initialize it again.
Thanks