I2C-ATMEGA328p como maestro y 24LC256 como esclavo

Así que estoy tratando de establecer una conexión entre ATMEGA328p como maestro y el chip EEPROM 24LC256 usando el protocolo I2C.

  • El reloj está ajustado a 100 KHz
  • Las líneas SDA y SCK se elevan a Vcc usando resistencias de 4.7K Ohm,
  • La condición de inicio funciona bien, también recibo un ACK a cambio,
  • ACK recibido cuando se envía la dirección correcta,
  • ¡Falla cuando se envía el MSB de la dirección en el chip!

Código:

#define FOSC         16000000UL
#define START        0x08
#define MT_SLA_ACK   0x18
#define MT_SLA_NACK  0x18
#define DEV_ADDR     0x50


typedef enum result_t{FAIL, SUCCESS}result;

void Debug_LED_ON()
{
   PORTD|=1<<PD4; //Turn on LED on PIN4 of PORTD
}

void set_clock(int freq_in_khz)
{
   TWCR = 1<<TWEN;     //Enable TWI module
   TWSR |=(1<<TWPS0); //Prescaler set to 4
   TWBR  = FOSC/freq_in_khz;
   TWBR -= 16;
   TWBR /= 8;  //2*Prescaler_value

}

void send_start()
{
   TWCR= ( (1<<TWINT) | (1<<TWEN) | (1<<TWSTA) ); //send START
   while( !(TWCR & (1<<TWINT)) ) ;                //wait for TWINT flag SET
}

void send_stop()
{
   TWCR= ( (1<<TWINT) | (1<<TWEN) | (1<<TWSTO) ); //send STOP
   //while( !(TWCR & (1<<TWINT)) ) ;                //wait for TWINT flag SET
}

result check_start_status()
{
   if ((TWSR & 0xF8) == START )
     return SUCCESS;
   else
     return FAIL;
}

void send_address(char addr_w)
{

   TWDR=addr_w; //7bit  address + W bit (write bit)
   TWCR = (1<<TWINT) | (1<<TWEN); //Clear TWINT bit to start transmission of address
   while (!(TWCR &(1<<TWINT)));  //wait for TWINT flag SET

}
result check_MT_slave_ack()
{
   if ((TWSR & 0xF8) == MT_SLA_ACK )
     return SUCCESS;
   else
     return FAIL;
}
result check_MT_slave_nack()
{
   if ((TWSR & 0xF8) == MT_SLA_NACK )
     return SUCCESS;
   else
     return FAIL;
}

void  transmit_data(char data)
{
   TWDR=data;
   TWCR = (1<<TWINT) | (1<<TWEN); //Clear TWINT bit to start transmission of Data on the bus
   while (!(TWCR &(1<<TWINT)));  //wait for TWINT flag SET

}

int main (void)
{
   DDRC=0xff;
   PORTC=0x30;   //Enable internal pullups on PORTC PINS  SDA(PC4) , SCL(PC5)
   DDRD=0xFF;   //Port D as output


   set_clock(100); //setting clock 100KHz
   send_start();

   if(check_start_status()==FAIL)
     Debug_LED_ON();


   send_address(DEV_ADDR << 1); 

   if(check_MT_slave_ack()==FAIL)
    Debug_LED_ON();

   transmit_data(0x00);  

   if(check_MT_slave_ack()==FAIL) //fails here!
    Debug_LED_ON();     

   return 0;
}

¡Supongo que algo anda mal con el código o con la forma en que envío la dirección! Los bits A2,A1,A0 de 24LC256 se establecen en tierra, por lo tanto, la dirección del dispositivo es 0x50 << 1.

Actualizar:

La dirección del dispositivo se envía correctamente ahora, ahora cuando envío el MSB de la dirección en el chip donde quiero escribir datos, ¡falla!

Configuración de hardware

Respuestas (1)

El valor que está configurando en send_address()la función está un poco apagado. La dirección del chip 0x50es un número de 7 bits, que debe cambiarse 1 bit hacia arriba cuando se envía en el bus I2C (el bit más bajo es el indicador de lectura/escritura). Por lo tanto, debe usar send_address(0xa0)(es decir 0x50<<1) en su código, o hacer la send_address()función shift inside.

Por "cuando envío la dirección +/W, no obtengo ni ACK ni NACK", ¿quiere decir que su código se cuelga en while (!(TWCR &(1<<TWINT)));bucle dentro send_address()? Si es así, entonces es un problema diferente que no está relacionado con la dirección mencionada anteriormente.

¡Gracias! el código no cuelga en send_address(). Estaba enviando la dirección como 7 bits, 1010000, el nibble superior 1010 está arreglado, ¡ahora lo entiendo! Funciona hasta ahora, es decir, recibo un ACK a cambio :)