AnsweredAssumed Answered

Problem with I2C master receive

Question asked by Andrew Goodings on Dec 12, 2014
Latest reply on Dec 21, 2014 by igorpadykov

I wonder if anyone can help with me with an issue I have. I am in the process of writing a I2C driver for our custom hardware using an i.MX287

 

We plan to use PIO mode and interrupts to handle the transmit / receive packets but for the moment we am not using interrupts - simply polling the appropriate flags between the various stages of the transaction.

 

I am following the guidelines from the reference manual in the PIO mode section to read a byte from an EEPROM using master mode.

 

Here is my code :-

 

CRESULT I2C_Wait_DMAREQ( void )

{

  U32 timeout = *pSysCntRunVal;

  U32 status;

  CRESULT result = EE_FAILURE;

 

  while ( *pSysCntRunVal < (timeout + 1000) )

{

   status = HW_I2C0_REGS->DEBUG0;

      if ( ( status & (1UL << 31 ) ) == ( 1UL << 31) )

   {

    result = FOUND_OK;

       break;

   }

  }

  return result;

}

 

void I2C_Clear_DMAREQ( void )

{

  HW_I2C0_REGS->DEBUG0_CLR = ( 1UL << 31 );

}

 

CRESULT I2C_Wait_COMPLETE( void )

{

  U32 timeout = *pSysCntRunVal;

  U32 status;

  CRESULT result = EE_FAILURE;

  while ( *pSysCntRunVal < (timeout + 1000) )

{

  status = HW_I2C0_REGS->CTRL1;

    if ( ( status & ( 1 << 6 ) ) == ( 1 << 6 ) )

  {

    result = FOUND_OK;

        break;

}

}

I2C_Clear_COMPLETE();

  return result;

}

 

void I2C_Clear_COMPLETE( void )

{

  HW_I2C0_REGS->CTRL1_CLR = ( 1 << 6 );

}

 

CRESULT EE_ReadByte( U16 address, U8 *data )

{

   U32 address_low = address & 0xff;

   U32 address_high = (address & 0xff00) >> 8;

   U32 temp = EE_I2C_ADDRESS | ( address_high << 8 ) | ( address_low << 16 );

 

  HW_I2C0_REGS->CTRL1= 0x08000000;

  HW_I2C0_REGS->QUEUECTRL= 0x00000000;

 

    // prepare for transaction – master write mode with start bit and 3 bytes to transfer (i2c address + 16 bit EEPROM address followed by stop

  HW_I2C0_REGS->CTRL0 = 0x001b0003;

 

    // run

  HW_I2C0_REGS->CTRL0_SET = ( 1 << 29 );

 

  I2C_Wait_DMAREQ();

 

    // write i2c address + EEPROM address

HW_I2C0_REGS->DATA = temp;

 

  I2C_Clear_DMAREQ();

 

  I2C_Wait_COMPLETE();

 

    // prepare for transaction - master write mode with start bit and i2c address

  HW_I2C0_REGS->CTRL0 = 0x000b0001;

 

   // run

  HW_I2C0_REGS->CTRL0_SET = ( 1 << 29 );

 

  I2C_Wait_DMAREQ();

 

    // read i2c address

  HW_I2C0_REGS->DATA = EE_I2C_ADDRESS + 1;

 

  I2C_Clear_DMAREQ();

 

I2C_Wait_COMPLETE();

 

   // prepare for transaction - master read mode with one byte to transfer (i2c address) then stop

  HW_I2C0_REGS->CTRL0 = 0x20120001;

 

  I2C_Wait_DMAREQ();

 

  *data = (U8)HW_I2C0_REGS->DATA;

 

  I2C_Clear_DMAREQ();

}

 

The start of this transaction seems to work OK. I am seeing the first 3 bytes being written (I2C address and internal EEPROM address followed by a stop). Then the read address is being written OK. Then it gets as far as the line highlighted in bold in the code which attempts to initiate the I2C read – the DMAREQ bit doesn’t seem to assert after this. On a scope I can see that no clocks are being generated to receive the data and the SDA line remains low. The bus busy bit in the status register suggests the bus is still busy. I am unsure what is preventing the read from starting.

 

Before using the above code I reset the I2C block and set it up (for 100Kbps).

 

Any help anyone can give would be greatly appreciated. We have spent many days searching forums and looking at Linux drivers for possible clues with no luck.

Outcomes