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


von Tobias B. (roxxity)


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...
1
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);    // (RE)START senden
2
timeout = 0;
3
while (!(TWCR & (1<<TWINT))  && (timeout<4000) ) {timeout++;};  // Warten bis START gesendet wurde
4
if ((TWSR & 0xF8) == TW_REP_START)        // Fortsetzen wenn START erfolgreich
5
{
6
  TWDR = 0b00100000+1;        // Slave-Adresse+READ setzen
7
  TWCR = (1<<TWINT)|(1<<TWEN);      // Übertragung starten
8
  timeout = 0;
9
  while ( !(TWCR & (1<<TWINT)) && (timeout<4000) ) {timeout++;};      // Warten
10
  if ((TWSR & 0xF8) == TW_MR_SLA_ACK)    // Slave antwortet Acknowledged
11
  {
12
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);    //Hä
13
14
    timeout = 0;
15
    while ( !(TWCR & (1<<TWINT)) && (timeout<4000) )
16
    {timeout++;};      // Warten
17
          
18
    PORTD = TWDR;
19
    
20
    ...
21
  }
22
}

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

Grüße, Tobias

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

was ist denn der Slave ??

Sascha

von Tim (Gast)


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.
1
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?

von Tobias B. (roxxity)


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
1
  for (;;) {
2
    while (!(TWCR & (1<<TWINT)));        // Warten bis START gesendet wurde
3
    PORTD = TW_STATUS;
4
    switch (TW_STATUS) //TWI-Statusregister prüfen und nötige Aktion bestimmen 
5
    {
6
    case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert  
7
      PORTD=0b01010101;
8
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
9
      break;
10
    case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen
11
       PORTD=TWDR; //Empfangene Daten auslesen      
12
       TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
13
      break;
14
    case TW_ST_SLA_ACK: //?!?
15
     
16
      TWDR = 0b01010101;
17
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
18
      break;
19
    case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert
20
      TWDR = 0b00001111;
21
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA);   // ACK senden;
22
    break;
23
    case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert 
24
    case TW_SR_DATA_NACK: //0x88 
25
    case TW_ST_LAST_DATA: //0xC8  Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
26
        TWCR=(1<<TWEN)|(1<<TWINT)|(1<<TWEA);
27
      break;
28
    case TW_SR_STOP: // 0xA0 STOP empfangen
29
        TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
30
      break;
31
    default:   
32
        TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
33
        TWCR = 0; //Übertragung beenden, warten bis zur nächsten Adressierung
34
        TWCR = (1<<TWEN)|(1<<TWEA); //Übertragung beenden, warten bis zur nächsten Adressierung
35
    break;
36
    } 
37
  }

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

von Tim (Gast)


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.:
1
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....
1
case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert
2
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?

1
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...

1
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.

1
case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert 
2
case TW_SR_DATA_NACK: //0x88 
3
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.

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

1
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.

von Tobias B. (roxxity)


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!

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.