www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TWI/I2C Master Receiver Mode


Autor: Tobias B. (roxxity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Bevor ich jetzt groß ausschweife: Wie genau kommt der Slave in den 
Status "Last-Data-Byte"?

Ich kann mit dem Master nämlich immer nur 2 Bytes auslesen, obwohl ich 
immer ACK mitsende.

Ich habe das Manual mehr als einmal gelesen und ich werd leider nicht 
draus schlau...
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);    // (RE)START senden
timeout = 0;
while (!(TWCR & (1<<TWINT))  && (timeout<4000) ) {timeout++;};  // Warten bis START gesendet wurde
if ((TWSR & 0xF8) == TW_REP_START)        // Fortsetzen wenn START erfolgreich
{
  TWDR = 0b00100000+1;        // Slave-Adresse+READ setzen
  TWCR = (1<<TWINT)|(1<<TWEN);      // Übertragung starten
  timeout = 0;
  while ( !(TWCR & (1<<TWINT)) && (timeout<4000) ) {timeout++;};      // Warten
  if ((TWSR & 0xF8) == TW_MR_SLA_ACK)    // Slave antwortet Acknowledged
  {
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);    //Hä

    timeout = 0;
    while ( !(TWCR & (1<<TWINT)) && (timeout<4000) )
    {timeout++;};      // Warten
          
    PORTD = TWDR;
    
    ...
  }
}

Den Part in der letzten Klammer kann ich nur zwei Mal wiederholen, 
danach kommt 0xFF

Grüße, Tobias

Autor: Sascha Weber (sascha-w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

was ist denn der Slave ??

Sascha

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Bevor ich jetzt groß ausschweife: Wie genau kommt der Slave in den
>Status "Last-Data-Byte"?

Indem das TWI als Slave Transmitter arbeitet, und man TWEA nicht setzt.

Aber dein Code da oben scheint ein Master Reciver zu sein?
Du musst nach jedem kommen von TWINT einen neuen Befehl
in TWCR schreiben.
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);    //Hä
Passt, das TWI holt ein Byte und schickt ACK zum Slave.
Und wie geht es weiter?

Was passiert eigentlich wenn dein Timeout abgelaufen ist,
das TWI aber noch nicht fertig ist?

Was ist dein Slave? Code?
I2c Sniffer zur Hand? Gibt hier im Forum sehr brauchbare.
Uart für die Debug ausgaben?

Autor: Tobias B. (roxxity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay ich war etwas in Eile vorhin, sorry.

Also, der Code oben ist noch lange nicht fertig und der Timeout kann 
auch einfach ignoriert werden, da er im Normalfall ja eh nicht greift. 
Der Code oben ist wie schon vermutet vom Master (Receiver).

Hier der Code vom Slave
  for (;;) {
    while (!(TWCR & (1<<TWINT)));        // Warten bis START gesendet wurde
    PORTD = TW_STATUS;
    switch (TW_STATUS) //TWI-Statusregister prüfen und nötige Aktion bestimmen 
    {
    case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert  
      PORTD=0b01010101;
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
      break;
    case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen
       PORTD=TWDR; //Empfangene Daten auslesen      
       TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
      break;
    case TW_ST_SLA_ACK: //?!?
     
      TWDR = 0b01010101;
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
      break;
    case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert
      TWDR = 0b00001111;
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
    break;
    case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert 
    case TW_SR_DATA_NACK: //0x88 
    case TW_ST_LAST_DATA: //0xC8  Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
        TWCR=(1<<TWEN)|(1<<TWINT)|(1<<TWEA);
      break;
    case TW_SR_STOP: // 0xA0 STOP empfangen
        TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
      break;
    default:   
        TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
        TWCR = 0; //Übertragung beenden, warten bis zur nächsten Adressierung
        TWCR = (1<<TWEN)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
    break;
    } 
  }

Bitte nicht falsch verstehen: In den Codes herrscht das Chaos, weil ich 
schon viel rumprobiert habe und ich immer max. 2 Bits übertragen kann.
Ich weis, dass in einigen Fällen NACK gesendet werden sollte, aber das 
war nur ein Test nachdems so auch nicht ging.

Spätestens beim zweiten meint der Slave (warum auch immer) jedenfalls es 
wäre das Last Data Bit. Und ich glaube hier liegt auch der Hund begraben 
:(

Grüße, Tobias

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eins Vorweg:
Du scheinst sehr viel mit #define zu arbeiten. Zu Viel. Und dein
Code ist unvollständig. (Was/wie/wo ist TW_STATUS?)
Und schreib z.b.:
case 0x80: //addressed with ownSLA+W; data received; ACK send
Dann weiß man gleich was gemeint ist :-)

>Also, der Code oben ist noch lange nicht fertig und der Timeout kann
>auch einfach ignoriert werden, da er im Normalfall ja eh nicht greift.
Sicher? bei 8Mhz sind das gerade mal geschätzte 15 ms (wenn sich der gcc 
total dämlich anstellt, also eher unter 10).

Mangels vollständigem Code halte ich mich jetzt mal an die Hex angaben 
in deinem switch Code....
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert
case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen
Hmm... ich denke du möchtest eine Slave Tansmitter bauen oder?
Wozu dann der Code für einen Slave Receiver?

case TW_ST_SLA_ACK: //?!?
Ja, ich schliese mich dem "?!?" an. (Lies: ich bin Total bescheuert dir 
zu antworten)
Sollte das 0xA8 sein Passt der Code, aber du Sendest das ACK nicht 
sondern erwartest das der Master eins sendet...

case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert
Gut Das passt auch.
Der Slafe müsste also unendlich daten (0b00001111) senden,
sofern der Master alles Richtig macht.

case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert 
case TW_SR_DATA_NACK: //0x88 
case TW_ST_LAST_DATA: //0xC8  Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
Also in Datasheet steht zu 0x88 vier mal untereinander "Read data byte".
Fehlt bei dir irgendwie, aber das ist ja eh Slave reciver...
Sonst passt das.

case TW_SR_STOP: // 0xA0 STOP empfangen
Ist auch ok.

default:
Könnte man noch ein STO im ersten TWCR einbauen um
das TWI wieder auf die Füße zu hohlen.

Soweit sogut. Der Slave transmitter scheint korrekt zu sein.
Der Slave springt nur dann in den "last data byte mode" wenn
TWEA nicht gesetzt war. D.h.: Der Slave müsste entwerder
bei 0xA8 oder 0xB8 mist bauen. Kann ich nicht ausschließen, da
ich nicht weiss was TW_ST_SLA_ACK sein soll.


Den Master kann ich mangels vollständige Code nicht überprüfen.

Vermutlich geht das aber alles so schnell das du den eingentlichen
Fehler gar nicht siehst.

Entferne alles unnötige aus deinem Code (timeout, Slave reciver) und 
Poste ihn komplett!
Die wenigsten hier machen sich die mühe unvollständige Code zu lesen
oder gar zu Antworten.

Zum weiteren Debuggen:
1. Besorge dir einen I2C Sniffer
   Wirst du auch in Zukunft brauchen
2. Nutze die Uarts für Status ausgaben
0. Bau diese [Zensiert] Timeout aus und versuche
die Geschwindigkeit zu reduzieren (delay).

>Okay ich war etwas in Eile vorhin, sorry.
Wenn ich mir hier 1/2 Stunde Zeit nehme solltest du dir mindestens 2 
nehmen.

Autor: Tobias B. (roxxity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Code für den Slave ist eigentlich geklaut, der "?!?" Comment ist 
übernommen ;)
Das ist doch wenn der Slave das erste Mal schreiben soll, und da sendet 
er tatsächlich ein ACK, bevor er die Daten schickt. Aber im Weiteren 
hast du recht, da warte ich auf ein ACK/NACK.

Leider weis ich nicht woran es genau lag, da nach etwas Ausmisten des 
Codes alles plötzlich so funktioniert, wie es soll.

Danke für deine Mühe!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.