I2C-ATMEGA328p als Master und 24LC256 als Slave

Also versuche ich, eine Verbindung zwischen ATMEGA328p als Master und dem 24LC256-EEPROM-Chip mithilfe des I2C-Protokolls herzustellen.

  • Die Uhr ist auf 100 kHz eingestellt
  • SDA- und SCK-Leitungen werden mit 4,7-K-Ohm-Widerständen auf Vcc hochgezogen.
  • Startbedingung funktioniert gut, ich bekomme auch ein ACK zurück,
  • ACK erhalten, wenn die richtige Adresse gesendet wird,
  • Versagt, wenn MSB der Adresse im Chip gesendet wird!

Code:

#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;
}

Vermutlich stimmt etwas mit dem Code nicht, oder wie ich die Adresse sende! Die Bits A2, A1, A0 von 24LC256 sind auf Masse gesetzt, daher ist die Geräteadresse 0x50 << 1.

Aktualisieren:

Die Geräteadresse wird jetzt korrekt gesendet. Wenn ich jetzt das MSB der Adresse auf den Chip sende, auf den ich Daten schreiben möchte, schlägt es fehl!

HW-Setup

Antworten (1)

Der Wert, den Sie in der Funktion einstellen send_address(), ist ein Bit daneben. Die Chipadresse 0x50ist eine 7-Bit-Zahl, die beim Senden auf dem I2C-Bus um 1 Bit nach oben verschoben werden muss (das niedrigste Bit ist das Lese-/Schreib-Flag). Sie sollten also send_address(0xa0)(das ist 0x50<<1) in Ihrem Code verwenden oder die send_address()Funktion shift inside ausführen.

Mit "wenn ich die Adresse + / W sende, bekomme ich weder ACK noch NACK" meinen Sie, dass Ihr Code in einer while (!(TWCR &(1<<TWINT)));Schleife hängt send_address()? Wenn ja, dann handelt es sich um ein anderes Problem, das nichts mit der oben genannten Adresse zu tun hat.

Danke! der Code hängt nicht in send_address(). Ich habe die Adresse als 7bit gesendet, 1010000, das obere Nibble 1010 ist fest, jetzt verstehe ich es! Es funktioniert jetzt soweit, dh ich bekomme ein ACK zurück :)