Missing TWI start bit after transaction

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

Is there an issue with the XMEGA chips potentially missing certain TWI/I2C signals on the bus if the microcontroller isn't clocked at or near its maximum rate? Should this be documented somewhere, e.g. in one of the notes or manuals?

Consider the case where an XMEGA is acting as a TWI/I2C slave on a high-speed bus, e.g. 400 KHz. Imagine if a bus master is reading data from the XMEGA as part of a transaction, and has just received the last byte of data it is interested in. Per the protocol, after it receives the last byte, it sends a NACK back to the XMEGA and can take further action on the bus immediately. That is, there's no slave clock stretching allowed at this point. Therefore, this is a perfectly valid sequence:

1) Master reads last byte from XMEGA.
2) Master sends NACK for last byte.
3) Master sends START for next transaction.
4) Master sends slave address for next transaction.

Based on testing, if the microcontroller application code is not able to finish servicing the interrupt generated for #2 (i.e. writing a new value to SLAVE.CTRLB) before #3 occurs, it seems that the START bit is lost because the hardware isn't in the correct state to see it. The microcontroller never acknowledges its slave address and so no further interrupt is generated.

Is this interpretation correct? If so, is there anything which can be done on the XMEGA other than increasing the clock rate so that it can service the interrupt more quickly? Obviously the master can wait between transactions, but this shouldn't be required per the protocol. If nothing else, it would be helpful if this were documented somewhere.

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

I tested TWI bus at 1 MHz using polling technique and I do not had any issues. It seems that for higher frequencies than this the SDA line cannot handle the data even if the clock looks fine.

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

1) Master reads last byte from XMEGA.
2) Master sends NACK for last byte.
2a) Master sends a STOP condition to end transfer.
3) Master sends START for next transaction.
4) Master sends slave address for next transaction.

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

Yes, sorry, I omitted step 2a in my original description. The issue is the same, though. If you clock the XMEGA at say, 2 or 4 MHz and therefore are not able to process the interrupt for the final byte read before the stop and subsequent start are transmitted, you completely lose the next transaction.

I imagine this is not a problem if you clock the XMEGA at 32 MHz, since at this speed, the interrupt handling is probably able to complete in time. Similarly, if the master is not aggressive in sending back-to-back commands, one won't see this issue.

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

The I2C protocol allows a slave device to hold the clock signal low when it's not ready, slowing the bus.

From the XMEGA A document, section 19.6 TWI Slave Operation:

Quote:
When an interrupt flag is set, the SCL line is forced low. This will give the slave time to respond
or handle any data, and will in most cases require software interaction.

That should (in theory) resolve any speed problems on the slave side. You pay for it by holding the I2C bus and slowing other devices that may be attached to it.

Disclaimer: I have never actually used an XMEGA as an I2C slave so I do not know how well it works in reality.

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

Is the slave really allowed to hold the clock line low even when the protocol does not expect a response from the slave? That is, the "NACK" and subsequent "STOP" from the master do not require a slave response, so I'm not clear on whether the slave is allowed to hold the clock line at this point or not.

It's possible that the implementation of the master in question may not be expecting the clock to be held here and so may not get along well with the XMEGA in this particular situation.

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

Although not commonly used, it is part of the I2C protocol definition.
Read chapter 3.9 about clock stretching here.

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

The XMEGA has to use clock stretching when operating as a slave at slower speeds (e.g. 2 or 4 MHz) and interfacing with a 400 KHz bus; it's pretty much unavoidable, which is why Atmel recommends 32 MHz in this situation. The question was specifically if the slave is allowed to stretch the bus at an arbitrary time other than when receiving a byte of data, i.e. is clock stretching allowed when just a single bit with no expected response is sent to the slave?

The protocol says, "... Slaves can then hold the SCL line LOW after reception and acknowledgment of a byte to force the master into a wait state until the slave is ready for the next byte transfer in a type of handshake procedure". It says nothing about being able to stretch the clock between the time when a NACK is generated, when a STOP is generated, and when the next START is generated, which can happen back-to-back in three bit cycles.

This is the situation where I'm seeing the XMEGA completely fail to catch the start of the next transaction. I don't have a scope connected to the SCL line so I don't know if it's not stretching, or if it's stretching but this is being ignored since the master is not expecting stretching at this unusual time. If the master waits, say, 50us to start the next transaction, all is well.

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

To comment further on this...

The slave is not allowed to stretch the clock in this situation. When completing a "master read", the master is allowed to send a NACK, a stop bit, a start bit, and a new slave address in rapid succession without acknowledgement and without any possibility of clock stretching from the slave.

Using Atmel's TWI slave driver from the ASF (with the XMEGA as the slave), if the ISR code does not process the NACK before the master sends the slave address for the next transaction, communication breaks down. Because the interrupt flag is already set from the NACK, no second interrupt is generated in response to the slave address, so when the ASF handler does finally get around to processing the NACK, it does this and exits, and the slave address transmission is basically lost. The master waits forever for the slave to acknowledge its address but the microcontroller does not do so.

I’m not clear on whether this is a hardware limitation, i.e. the ISR needs to write “transmission complete” to the hardware in response to the previous NACK before being able to process the next slave address? Or is this actually a deficiency in Atmel’s ASF driver, in that the address is recognized by the hardware and the appropriate bits are set in the status register when this occurs, but the driver doesn’t consider this case? It only checks one condition at a time (i.e. it only processes the NACK for the write and then returns) without considering additional possibilities, and of course, since the interrupt flag was already set, it won’t be set again.

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

m having problem with atmega8 as master.when it sends start bit ,TWINT gets set but status is coming invalid...

what wud be the reason..m also posting code for atmega8 as master

 

#include<avr/io.h>                   
#define F_CPU 12000000
#include<util/delay.h>

// for master dddddddddddddddd
void ERROR ()
{
 while(1)
  {
    PORTB=0b00000101;
    
  }
}
int TWIGetStatus()
{
    int status;
    status=TWSR&0xF8; //mask lower three bits
    return status;
}

void main ()
{
   //for successful download
   DDRB=0x0F;
   PORTB=0x0F;
   _delay_ms(2000);
   PORTB=0x00;
   _delay_ms(2000);
   
       TWBR=0XFF;                            //lowest possible scl frequency i.e.22.81khz or 43us
    TWSR=0X00;                            //precscalar set to 1
    
    TWCR=0XA4;                            //start bit with clearing TWINT and enabling TWEN

//    while(!(TWCR&0x80));                //checking if TWINT is set
//    while (!(TWCR & (1<<TWINT)));
while(!(TWCR&0x80)==0x00);        //checking if TWINT is set

 

//    while(TWSR!=0x08);                    //checking if  status code is correct

    
if (TWIGetStatus() != 0x08) //checks for start bit
     ERROR();
    
    
    
    TWDR=0x08;                            //loading slave address and master rite
    TWCR=0x84;                            //enabling TWI and clear TWINT
while(!(TWCR&0x80)==0x00);        //checking if TWINT is set
    while(TWSR!=0x18);                    //checking if  status code is correct
    
    
    
    TWDR=0x01;                            //sending data byte
    TWCR=0x84;                            //enabling TWI and clearing TWINT
    while(!(TWCR&0x80)==0x00);        //checking if TWINT is set
    while(TWSR!=0x28);                    //checking if  status code is correct
    
    
    TWCR=0x94;                            //sending stop bit with clearing TWINT and setting enable
    
    //for successful write operation
    
 
    
     PORTB=0x00;
    _delay_ms(5000);
    
     PORTB=0xFF;
    _delay_ms(3000);

}