problema AVR TWI (I2C)

3

Estoy utilizando EEPROM ATmega32A y 24c16A para probar un código I2C. Para cada transición de estado, el controlador responde cambiando el registro de estado TWSR . Después de que se transmite la condición de inicio, EEPROM responde y luego, para la dirección del dispositivo y las instrucciones de escritura (SLA + R / W), el registro de estado se actualiza correctamente. Pero cuando transmito los siguientes 8 bits, en lugar de ACK (byte de datos enviado ACK), el estado cambia a inicio repetido. El código se da a continuación. Nunca pude encontrar la posible solución para que funcione.

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
}

En lugar de 0x28, 0x10 se actualiza en el registro de estado al llamar a la función twi_write_data(data) .

    
pregunta gzix

2 respuestas

3

El problema está en

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

Según las hojas de datos de Atmel, las banderas que configuró en TWCR "deben ser borradas por el software cuando [lo que está intentando enviar] se haya transmitido".

Así que no "o" TWCR con tus banderas pero escribe todas las banderas en el registro a sus valores apropiados, como

TWCR = (1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    
respondido por el JimmyB
2

Otro pequeño error:

while(!(TWCR & (1<<TWSTO)));  // Wait till stop condition is transmitted

TWSTO se borra cuando se ha transmitido una condición de parada. Debe cambiarse a:

while(TWCR & (1<<TWSTO));  // Wait till stop condition is transmitted

Esta es la razón por la que envías un inicio repetido en lugar de una parada y un inicio.

    
respondido por el diego freschi

Lea otras preguntas en las etiquetas