This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129ENCPDT: I2C interface seems to need a delay before sending data.

Part Number: TM4C129ENCPDT

Hi,

when sending data via i2c bus it seems that a short delay between the individual communications is needed.

For example the i2c interface is busy with sending data. Immediately after the i2c interface has finished the transfer

(the last byte has been sent and the interface is idle) a new communication is started. Now a short delay is necessary

before the i2c interface is addressed. Otherwise the i2c interface get stuck and stops working. A soft reset of the interface doesn't help.

The interface then needs to be hard resetted. The delay time is about 2 milliseconds.

Here's is what i'm doing when sending data to the slave.

[...]

  /// Wait for the master to become ready.
  drv_i2c2_wait_busy();

  /// Master is from now on busy.
  bo_busy = true;

  /// Insert delay time. Otherwise the master get stuck.
  drv_i2c2_delay(COM_DELAY_LOOPS);

  /// Set working variables.
  ui8_len     = ui8_len;
  pu8_data    = pu8_data;
  ui32_action = I2C_MASTER_CMD_SINGLE_SEND;
  ui8_mode    = SINGLE_SEND;

  /// If there is only one argument use the single send command.
  if(ui8_len > 1)
  {
    /// Set action.
    ui32_action = I2C_MASTER_CMD_BURST_SEND_START;
    ui8_mode    = BURST_SEND;
  }

  /// Enable interupts.
  ROM_IntEnable(INT_I2C2);
  ROM_I2CMasterIntEnableEx(I2C2_BASE, I2C_MASTER_INT_DATA);

  /// Tell the master the slaves address and that we want to write data.
  ROM_I2CMasterSlaveAddrSet(I2C2_BASE, u8_addr, false);

  /// Hand over the first byte.
  ROM_I2CMasterDataPut(I2C2_BASE, *(pu8_data++));

  /// Start sending data.
  ROM_I2CMasterControl(I2C2_BASE, ui32_action);

  /// Wait until the master has finished sending the data.
  /// NOTE: Sending data is done in the isr.
  drv_i2c2_wait_busy();

  /// Return
  return (I2C_ERR_NONE);
}

The sending of the data is done in the interrupt service routine. A flag signals if the master is busy or idle. When starting a transmission. The flag is set at the beginning of a new transmission and is cleared after the last byte has been transmitted/received.

The the microcontroller runs on 120 MHz. The i2c interface runs in fast mode at 400 kHz and there are one master and three slaves on the bus.

Any ideas what could cause the described behavior?

Regards

Marco

 

  • Hello Marco,

    One tricky point on your code is that you call drv_i2c2_wait_busy(), which per your description, simply waits for a flag to be set (and this flag is told to being set inside an ISR). Basically, if that's true, you are not really using the interrupt to let your MCU do something else while the data is being transferred to the bus, but rather looping in a wait state - and for that reason, code will be simpler to manage and debug if you just wait inline for the bus to be free.

    This is a piece of tested code, just as an inspiration - I honestly don't even remember the details that lead into the additional error verification found in it...

    	while (!goodtransfer)
    	{
    		while(I2CMasterBusy(AT24_I2C_BASE));
    		I2CMasterSlaveAddrSet(AT24_I2C_BASE, AT24_EEPROM_ADD, I2C_WRITE);
    		while(I2CMasterBusy(AT24_I2C_BASE));
    		I2CMasterDataPut(AT24_I2C_BASE, pageaddress);
    		I2CMasterControl(AT24_I2C_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    		if (!(I2CMasterErr(AT24_I2C_BASE) & I2C_MASTER_ERR_ADDR_ACK))
    			goodtransfer = true;
    	}
    

    This particular interfacing hardware uses many more bytes, this is the section for the first one only.

    Regards

    Bruno

  • Hi Marco,
    In addition to Bruno's comments, please take a look at this I2C app note which includes some I2C high speed code example. 

  • Hello Bruno,

    yes you are right. The communication is done in the interrupt service routine, but the interrupt is indeed not used to let the MCU do something else while data is transferred.

    The piece of code you posted is indeed interesting. Waiting inline for the bus to be free is an interesting idea. In the first version of my i2c driver, i have handled the I2C communication in a similar way to yours. But it failed due to a special characteristic of the I2C interface. According to the silicon errata of the MCU, it takes "approximately 60% of the I2C clock period for the BUSY status bit to be set" after a transaction command is issued. So if a transaction is started immediately behind another transaction, the busy bit is possibly not yet set, though the I2C bus is already busy. So i decided to introduce my own busy bit that is handled in the interrupt service routine.

    Regards

    Marco