Forum: Mikrocontroller und Digitale Elektronik TWI XMega256A3B Slave


von Honda (Gast)


Lesenswert?

Moin,
Ich versuche aktuell eine Kommunikation zwischen einem AtMega32 (Master) 
und einem AtxMega256A3B (Slave) über I²C herzustellen. Für den AtMega32 
nutze ich die Bibliothek von Peter Fleurry. Diese scheint soweit auch 
korrekt implementiert zu sein, die Kommunikation mit einem PCF8574 
funktioniert einwandfrei.

Ich habe es bereits hinbekommen, dass der Master Daten an den Slave 
sendet. Allerdings scheitere ich daran, dass der Master Daten vom Slave 
liest.

Ich initialisiere I2C auf dem XMega:

>TWIE.SLAVE.ADDR = I2C_ADDRESS;
>TWIE.SLAVE.CTRLA = 0b11111000;
>TWIE.SLAVE.CTRLB = 0b00000000;

>PORTA.DIR |= I2C_INT_PIN;

Beim Setzen des Interrupt-Pins wird gleichzeitig ein Interrupt-Impuls 
gesendet. Ein Interrupt beim Mega32 setzt I2C_Interrupt auf 1, wodurch 
in der Hauptschleife die I2C Kommunikation vom Master (Atmega) gestartet 
wird:

>while (1)
>{
>  if (I2C_Interrupt)
>  {
>    lcd_string("Interrupt!");
>    I2C_Interrupt = 0;
>
>    // Try logged in devices
>
>    for (int i = 0; i < i2c_addresses_loggedin_amount; i++)
>        check_i2c_device(i, i2c_addresses_loggedin[i], 1);
>  }
>}

>uint8_t check_i2c_device(uint8_t i, uint8_t address, uint8_t loggedin)
>{
>  uint8_t x;
>  if (x = i2c_start_wait(address | I2C_READ)) // Address not reach -> log off
>  {
>    if (loggedin)
>      Remove_I2C_Address(i);
>    return 0;
>  }
>
>  if ((I2C_Int_PIN & I2C_Int_PIN_N) == I2C_Int_PIN_N) // Interrupt cleared
>  {
>    uint8_t answer = i2c_read(0);
>
>    if (address == Handsteuerung_Address)
>    {
>      if (answer == HS_LOGIN)
>        HS_Online = 1;
>      else if (answer == HS_LOGOFF)
>        Remove_I2C_Address_by_Address(Handsteuerung_Address);
>    }
>    return 1;
>  }
>  return 0;
>}

In i2c_addresses_loggedin stehen alle aktuell eingeloggten Geräte. Also 
alle I2C-Geräte, die dem Master bekannt sind, dass sie sich aktuell am 
Bus befinden. Die Funktion prüft nun, ob die Adresse erreichbar ist, 
wenn dem nicht so ist, wird das Gerät mit der Funktion 
Remove_I2C_Address aus der Eingeloggten-Liste gelöscht, da es 
offensichtlicherweise nicht mehr online ist.
Sollte das Gerät ein Ack senden, überprüft die Funktion, ob der 
Interrupt Pin wieder freigegeben ist. Dies geschieht, sobald das 
richtige Gerät angesprochen wurde. In diesem Fall wird ausgewertet, was 
der Slave zurückgegeben hat.

Der Code des xMegas nach dem Initialisieren:
>uint8_t reg = ~TWIE.SLAVE.STATUS;
>int am = 0;
>while(1)
>{
>  if (reg != TWIE.SLAVE.STATUS)
>  {// Print Slave-Status-Reg
>    reg = TWIE.SLAVE.STATUS;
>    char* buffer = (char*)malloc(sizeof(char) * 11);
>    sprintf(buffer, "0x%02x", reg);
>    Print_String(buffer, 180, 4 + am++ * 16, WHITE);
>  }
>  if (TWIE.SLAVE.STATUS & (1 << 6))
>  { // Apif set -> send ack, clear interrupt
>    TWIE.SLAVE.CTRLB = 0b00000011;
>    I2C_INT_PORT.OUT |= I2C_INT_PIN;
>  }
>  else if (TWIE.SLAVE.STATUS & (1 << 7))
>  { // Dif set -> set data, send ack
>    TWIE.SLAVE.DATA = 2;
>  }
>}

Um den Code zu schreiben, habe ich den Chart "Slave operation" auf Seite 
9 genommen: http://www.atmel.com/images/doc8054.pdf

So wie ich das verstehe, sendet der Master das Start-Signal und die 
Adresse inkl. Read-Bit. Beim Slave wird APIF gesetzt und mit 
TWIE.SLAVE.CTRLB = 0b00000011; sende ich das geforderte ACK. 
Anschließend schreibe ich mit TWIE.SLAVE.DATA = 2; die Daten ins "data 
register". Mit dem Setzen des Data-Registers wird die Clock wieder 
freigegeben und der Master kann das Byte empfangen. Nach dem Schemata 
müsste damit die Kommunikation beendet sein, da ich mit i2c_read(0) ein 
NACK nach dem Lesen eines Bytes zurückgeben lasse.

Stattdessen hält der Slave die Clock auf GND und blockiert somit weitere 
Kommunikation.
Der Slave registriert die folgenden Status-Werte vom 
TWIE.SLAVE.STATUS-Register:
0x00 = 0b0000 0000
0x63 = 0b0110 0011
0x03 = 0b0000 0011
0xa3 = 0b1010 0011

Wo liegt da mein Fehler?
Füge ich an der Stelle, wo ich die zu übertragenden Daten ins Register 
schreibe noch folgende Zeile hinzu:
  TWIE.SLAVE.CTRLB = 0b11;

Dann wird die Clock wieder freigegeben. Allerdings bricht 
i2c_start_wait() bei if( (TW_STATUS & 0xF8) != TW_MT_SLA_ACK) ab.
Der Slave gibt folgende Status-Werte aus:
0x00 = 0b0000 0000
0x63 = 0b0110 0011
0x03 = 0b0000 0011
0x02 = 0b0000 0010
0x03 = 0b0000 0011
0x02 = 0b0000 0010

Mein Master erkennt die Verbindung als gescheitert an und löscht das 
Gerät aus der Eingeloggten-Liste.

Ich habe das Gefühl, ich drehe mich hier ein wenig im Kreis und habe 
irgendwo einen entscheidenen Punkt übersehen... Wäre daher klasse, wenn 
mir da jemand mit Ahnung einen Tipp geben könnte, wo mein Fehler steckt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.