TWI APIF Errata/Workaround

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The errata for the XMEGA256A3 contains an issue whose summary is, "Clearing TWI Stop Interrupt Flag may lock the bus". The datasheet then goes on to specify a workaround, but I'm a bit confused by the code which appears there. Has anyone successfully used this workaround to alleviate the described issue? Is it correct as written?

Problem fix/Workaround
Check if the bus state is IDLE. If this is the case, it is safe to clear APIF. If the bus state is not IDLE, wait for the SCL pin to be low before clearing APIF.

/* Only clear the interrupt flag if within a "safe zone". */
while ( /* Bus not IDLE: */
((COMMS_TWI.MASTER.STATUS & TWI_MASTER_BUSSTATE_gm) !=
TWI_MASTER_BUSSTATE_IDLE_gc)) &&
/* SCL not held by slave: */
!(COMMS_TWI.SLAVE.STATUS & TWI_SLAVE_CLKHOLD_bm))
{
  /* Ensure that the SCL line is low */
  if ( !(COMMS_PORT.IN & PIN1_bm) )
    if ( !(COMMS_PORT.IN & PIN1_bm) )
      break;
}

/* Check for an pending address match interrupt */
if ( !(COMMS_TWI.SLAVE.STATUS & TWI_SLAVE_CLKHOLD_bm) )
{
  /* Safely clear interrupt flag */
  COMMS_TWI.SLAVE.STATUS |= (uint8_t)TWI_SLAVE_APIF_bm;
}

Imagine if we're the slave device. Basically, what we're told is that we shouldn't clear APIF unless the bus is idle. However, from all the documentation, it looks like CLKHOLD will be set as long as APIF is set. When CLKHOLD is set, the clock line is forced low by the slave. Doesn't this inherently mean that the bus is idle, because the slave started stretching the clock the moment this interrupt took place?

The errata workaround checks "!(COMMS_TWI.SLAVE.STATUS & TWI_SLAVE_CLKHOLD_bm))" in two different locations. Per my reading, this is checking that the clock isn't currently held, but since we haven't yet cleared APIF, it has to be held, right? In which case how can this code do anything meaningful? If we haven't yet cleared APIF, CLKHOLD is always set. Or is the whole point of this that CLKHOLD hasn't yet been set because we're trying to clear it too quickly?

Does anyone have any insight on this? Thanks in advance.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

At least from what I can tell, this code doesn't work, and/or it's not clear where exactly in the TWI flow it would be placed.

Incidentally it's not the only place where something happening very fast can trip up the TWI module. Based on my observations... If the XMEGA is acting as a TWI/I2C slave and the master has just finished a read operaton, the master will respond with a NACK indicating end of read. The slave cannot stretch the clock at this point, so the master is free to proceed. If the master is fast and sends a stop bit and the start bit for the next transaction before the XMEGA application code can write to the CMD bits in the SLAVE.CTRLB register in response to the NACK, the next transaction will be lost (i.e. the XMEGA won't see it at all). Pretty unpleasant.