Electronic – AVR TWI (I2C) problem

avri2c

I am using ATmega32A and 24c16A EEPROM for testing an I2C code. For every state transition, controller responds by changing the status register TWSR. After start condition is transmitted, EEPROM responds and then also for Device address and write instruction (SLA+R/W), status register updates fine. But when I transmit next 8 bits, instead of ACK (Data byte sent ACK), status changes to repeated start. The code is given below. I never could find the possible solution to make it work.

int main(void)
{
init();
twi_start();
twi_write_device_address();
twi_write_data(0x08); // Data-write Memory transmission 
twi_write_data('U');  // Data transmission
twi_stop();
}
void twi_start(void)
{
// Clear TWI interrupt flag, Put start condition on SDA, Enable TWI
TWCR|= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR & (1<<TWINT))); // Wait till start condition is transmitted
while((TWSR & 0xF8)!= 0x08); // Check for the acknowledgment (start transmitted)
} 

void twi_write_device_address()
{
TWDR=0b10101110; // Device address and write instruction
TWCR|=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
while((TWSR & 0xF8)!= 0x18);  // Check for the acknowledgment (SLA+W transmitted)   
}

void twi_write_data(unsigned char data)
{
TWDR=data; // put data in TWDR
TWCR|=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
while((TWSR & 0xF8) != 0x28); // Check for the acknowledgment (Data written)
}

void twi_stop()
{ 
// Clear TWI interrupt flag, Put stop condition on SDA, Enable TWI
TWCR|= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); 
while(!(TWCR & (1<<TWSTO)));  // Wait till stop condition is transmitted
}

Instead of 0x28, 0x10 is updated in the status register while calling twi_write_data(data) function.

Best Answer

The problem is at

TWCR |= (1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI

As per Atmel datasheets, the flags you set in TWCR "must be cleared by software when [what you're trying to send] has been transmitted."

So don't "or" TWCR with your flags but write all the flags in the register to their appropriate values, like

TWCR = (1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI