TWI Repeated Start (unwanted)

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

Quote:
A special case occurs when a new Start condition is issued between a Start and Stop condition. This is referred to as a Repeated Start condition, and is used when the Master wishes to initiate a new transfer without relinquishing control of the bus.
Is this the only way a repeated start status code can be generated?
I am using an ATmega88 TWI Master Receive to read three remote I2C ports. After reading the first port, the other two report status Repeated Start when a Start is sent. The status returned when reading each port is 0x58, which I think means the Master has sent the required NACK.
Here is the code I am using for I2C Stop:
TWI_Stop:					; It seems that a delay is needed before
							;   this is called.  It works OK with
;	ldi TEMP, 0x22			;** this test code inserted.

;	mov HEX, TEMP			;**

;	rcall SendHex			;**goes thru here

	clr TEMP				;**I know, not needed

	ldi TEMP, (1<<TWINT|1<<TWSTO|1<<TWEN)	;
	
	sts TWCR, TEMP			;

	ret						;

The code commented out is to use the USART to help troubleshoot. The funny thing is that with that code in place, I no longer get the Repeated Start status.
Any ideas about what I'm doing wrong?

John

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

if you issue an i2c_start() without an intervening i2c_stop() then the state machine will call it an i2c_restart()

Your i2c_stop() looks perfectly ok to me.

You commonly do:

i2c_start()
i2c_write(slave_w)
i2c_write(data) ...
i2c_start()                  THIS IS RESTART
i2c_write(slave_r)
data = i2c_read(1) ...       ACK
data = i2c_read(0)           NAK
i2c_stop()

Of course that last i2c_stop() could be another i2c_restart() ...

The only important thing is that the last i2c_read() must be a NAK. You should always check the correct status after any i2c_start(), i2c_write() etc.

David.

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

Won't the status codes for start and repeated start differ? Or shall we use the same start function for restart too?

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

Yes,   the TWI state machine will tell you whether it was a Start or a Restart.

You still use the same TWSTA command to send the Start/Restart.

 

You can try all these things for yourself.   God gave you TWSR for this very purpose!

 

David.

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

Thanks to god, I was checking the status code of a start that I had called between a START condition and a STOP condition i.e, repeated start which is supposed to be 0x10 for ATmega16. To my surprise,the status code was 0x08( which corresponds to a normal start condition). Can you help me out here? 

 

           

 void TWI_repeated_start()
            {
            TWCR=(1<<TWINT);//*__* clear the two-wire interrupt by setting TWINT flag *__* 
            TWCR=(1<<TWEN)|(1<<TWSTA)|(0<<TWSTO);//Send the START bit and enable TWI functionality   
            while (!(TWCR & (1<<TWINT)));//Wait for the Interrupt to be set, to confirm START has been transmitted
            //LCDWriteStringXY(0,1,"RS");
            while((TWSR&(0xF8))!=0x10);// Check if repeated start has been transmitted 
            }
   
 void TWI_master_address_write(unsigned char add)
            {
            int flag=0;
            TWDR=add;    //Write the 8-bit data with the first 7-bits holding the slave address and the 8th bit holding the R/W value.              
            TWCR=(1<<TWINT)|(1<<TWEN);//Clear the interrupt flag to start the Slave address transmission
            while(!(TWCR & (1<<TWINT)));//Wait for the Interrupt to be set, to confirm the address bit has been transmitted to the slave and ACK/NACK is received
            //LCDWriteFloatXY(0,1,add,0,10);
            while(flag==0)
            {
                switch(TWSR&(0xF8))        //Mask the prescaler bits and read the status bits alone
                {
                case 0x18: LCDClear();
                           LCDWriteStringXY(12,0,"Ack");
                           flag=1;            //If ACK is received,terminate the loop as the aim of the function is achieved
                           break;
                           
                case 0x20: LCDClear();
                           LCDWriteString("Nack"); 
                           TWI_repeated_start();
                           TWI_master_address_write(add);
                           flag=2;            //If NACK is received,set the flag to 2 and break out of the loop.
                           break;                
                            
                default:   flag=0;            //If neither is received,wait until at least one is received
                           break;                
                }
            }
            
            }

void main()
{
DDRB=0xFF;
DDRD=0xFF;
LCDInit(LS_NONE);
_delay_ms(50);
LCDClear();
LCDWriteStringXY(0,0,"I2C Master");
unsigned char x=1;
TWI_master_init();
while(x<200)
{
TWI_start();
TWI_master_address_write(add);//Write the slave address
TWI_master_data_write(0b01111110,x);
TWI_stop();
x++;
}
}
          

The communication stalls as the slave could not recognise its own address due to the failure of execution of the repeated start condition. But when I check for the status against 0x08 the code is working like a charm. 

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

Just go and download Fleury I2C library,  and look at the "twimaster.c"

 

Then take a pencil and paper and hand-trace your code.

Spot the difference(s)?

 

0x7E (8-bit) or 0x3F (7-bit) is an unusual I2C address.

Most Slave devices are happy to have Stop,Start or Restart

Some devices require Restart.   You must check the data sheet of your Slave.

 

David.

 

 

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

I use another ATmega16 as a slave whose address can be set by the user by configuring TWAR register! So, I shouldn't have a problem as long as I don't set the address to 0000 000 right? 

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

Read a proven library first.

Check your logic for your code.

 

Then test your code on real hardware  I2C slaves.  e.g. AT24Cxx

When you are happy with real Slaves,  test your 'software Slave'

 

Quite honestly,  software Slave on a AVR TWI requires careful coding.

An I2C Master is easy to write (and test) on any MCU.

 

David.

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

Thanks David.

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

I tried studying Fleury's twimaster.c! I think there is a loophole in that. 

unsigned char i2c_start(unsigned char address)
{
    uint8_t   twst;

	// send START condition
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

	// send device address
	TWDR = address;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wail until transmission completed and ACK/NACK has been received
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

	return 0;

}/* i2c_start */

unsigned char i2c_rep_start(unsigned char address)
{
    return i2c_start( address );

}/* i2c_rep_start */

Consider the problem I faced. When I call repeated start,the status code in the TWSR is 0x08 instead of 0x10! The function,

unsigned char i2c_start(unsigned char address)

will return 1 if twst is either 0x08 or 0x10,which is fine! BUT,the function would not be returning a 1 because it had rightly matched the status code with start/rep_start Consider, i2c_repeated_start generating a status code of 0x08(my scenario) for which the function i2c_start would be returning 0 not because twst is 0x10 but it is 0x08. Isn't that wrong? 
 

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

What is the problem?

 

if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

 

Both of these values are good.

 

Since you are the Master,   you know whether the Slave was already on the bus.

 

The important lesson is to see the API of the Fleury primitive functions.

And to use the return values.

 

David.

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

Ok.