Forum: Mikrocontroller und Digitale Elektronik TWI Repeated Start Probleme


von Markus E. (opc)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe ein Problem mit der Repeated Start Condition am TWI.

Allgemein soll eine Schreiboperation vom Master auf den Slave und im 
Anschluss daran eine Leseoperation vom Master an den Slave stattfinden.

Das ganze funktioniert ohne Repeated Start (s. Anhang 
start_stop_start_stop.PNG und twi_start.txt), also nach dem Muster 
START_STOP_START_STOP wobei WRITE auf den Slave zwischen dem ersten 
START_STOP und READ zwischen dem zweiten START_STOP stattfindet.

Führe ich nach dem ersten START ein Repeated Start aus um direkt ohne 
Verlust der Busverbindung zwischen Master Transmit auf Master Receive 
Mode umzuschalten, erhalte ich als Quittung nach dem SLA_R auf den Slave 
ein NACK (s. Anhang start_repeatedStart_stop.PNG und 
twi_repeated_start.txt).
Der Stauts Code in TWSR ist entsprechend: 0x48 (SLA+R transmitted, NACK 
received).

Ich hoffe jemand hat möglicherweise Erfahrung mit dem TWI und Repeated 
Start und kann mir erklären warum der Slave nach dem Repeated Start 
nicht mehr mit ACK antwortet und ohne Repeated Start schon.

Danke für Hinweise!

LG
Markus

von Peter D. (peda)


Lesenswert?

Markus E. schrieb:
> Führe ich nach dem ersten START ein Repeated Start aus um direkt ohne
> Verlust der Busverbindung zwischen Master Transmit auf Master Receive
> Mode umzuschalten, erhalte ich als Quittung nach dem SLA_R auf den Slave
> ein NACK

Dazu müßte man den Slave-Code sehen, aber nicht als .txt, sondern als 
.c.

von Erklehr Behr (Gast)


Lesenswert?

Markus E. schrieb:
> ich habe ein Problem mit der Repeated Start Condition am TWI.

Wenn du deinem Compiler deine Sourcen als *.txt Datei gibst
dann wird das sowieso nichts.

Und deine Leser die du um Hilfe bittest haben grössere Mühe
überhaupt deine Sourcen zu betrachten.

von Markus E. (opc)


Angehängte Dateien:

Lesenswert?

Hier der Slave Code aus der Lib von Manfred Langemann, bei der ich noch 
die Repeated Start eingebaut habe.

von Erklehr Behr (Gast)


Lesenswert?

Markus E. schrieb:
> Ich hoffe jemand hat möglicherweise Erfahrung mit dem TWI und Repeated
> Start und kann mir erklären warum der Slave nach dem Repeated Start
> nicht mehr mit ACK antwortet und ohne Repeated Start schon.

Weil dein Slave (den du uns verheimlichst) womöglich einen
Protokoll-Verlauf verlangt der kein Repeated Start erfordert.

Dum musst schon dazusagen welcher Slave und was du genau machen
willst. Ein Datenblatt zum Slave wäre auch hilfreich.

Das hier ist jedenfalls zu allgemein:

Markus E. schrieb:
> Allgemein soll eine Schreiboperation vom Master auf den Slave und im
> Anschluss daran eine Leseoperation vom Master an den Slave stattfinden.

von Markus E. (opc)


Lesenswert?

Der Slave ist ein ATMega8 (wie der Master auch).
Den Slave Code habe ich angehängt. Den Ablauf der Ansteuerung habe ich 
in Post #1 erläutert und mehr ist es auch nicht. Nichts von wegen 
Protokoll etc.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Markus E. schrieb:
> Hier der Slave Code aus der Lib von Manfred Langemann, bei der ich noch
> die Repeated Start eingebaut habe.

Kein Wunder, daß das nicht geht. Main ist ja auskommentiert.
Poste den exakten und vollständigen Code, wie er auf dem Slave ist!
Mit nur ähnlichem Code kann Dir keiner helfen!

Am besten schreib ein Minimalprogramm, was nur auf dem Slave eine Taste 
einliest und eine LED setzt, quasi einen PCF8574 emuliert.
Alternativ kannst Du auch gleich einen PCF8574 als Slave nehmen, um den 
Mastercode zu prüfen.

: Bearbeitet durch User
von Markus E. (opc)


Angehängte Dateien:

Lesenswert?

Im Anhang seht ihr nun meine TWI-Lib sowie den Master und Slave 
main-Code.

Beide Devices (Master/Slave) sind ATMega8.

Diese Codes führen zu den Bildern im Anhang aus Post #1.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ne, so geht das nicht.
Als Slave kriegst Du nicht nur 60,A8, sondern auch viele andere States 
(80,88,A0,C0,C8).
Du must alle I2C-States behandeln, sonst hängt sich der Slave auf.
Schreib das besser als switch/case/default hin.

von Markus E. (opc)


Lesenswert?

Ok danke für die Info. Gibt es die Möglichkeit herauszufinden mit 
welchem Status Code es aktuell scheitert um nur diesen erstmal zu 
behandeln oder müssen wirklich alle behandelt werden? Ich weiß gar nicht 
was ich bei den meisten davon am Slave tun müsste...

Ich habe die Slave-main mal wie du meintest (außer der Behandlung 
aller...) umgeschrieben zu:
1
#include <avr/io.h>
2
#include "TWI_LIB.h"
3
#include "MAX7221CNG.h"
4
5
int main(void)
6
{
7
  DDRB |= (1<<PB0);
8
  PORTB &= ~(1<<PB0);
9
  
10
  twi_slave_init(11);       
11
  
12
  MAX7221_initialization();
13
  writeDataBCD(123);
14
  
15
  uint8_t data[4];  
16
    
17
    while (1) 
18
    {      
19
      if (TWCR & (1<<TWINT)) 
20
      {      
21
        writeDataBCD(TWSR & 0xF8);
22
        switch (TWSR & 0xF8) 
23
        {
24
          case TW_SR_SLA_ACK:
25
              twi_read_NACK();
26
              twi_stop_slave();
27
            break;
28
          
29
          case TW_ST_SLA_ACK: 
30
              twi_write_slave(100);
31
              twi_stop_slave();
32
          break;  
33
          
34
          default:
35
          break;          
36
        }        
37
      }    
38
    }
39
}

Wie man sieht habe ich mir den Status Code auf ein Display geschickt und 
anzeigen lassen. Der letzte übermittelte Status-Code ist 0x60, also Own 
"SLA+W has been received; ACK has been returned" vom Slave im Receiver 
Mode. Der Master empfängt ein 0x48 "SLA+R has been transmitted; NOT ACK 
has been received" was dem aktuellen Fehlverhalten entspricht.

EDIT:

Habe zum Test mal alle Codes des Slaves im Receiver und Transmitter Mode 
testweise mit aufgenommen. Die LED zu Testzwecken bleibt dunkel. Also 
wird kein anderer Status-Code als 0x60 am Slave mehr zur Verfügung 
gestellt.
1
 while (1) 
2
    {      
3
    
4
      if (TWCR & (1<<TWINT)) 
5
      {      
6
        writeDataBCD(TWSR & 0xF8);
7
        
8
        switch (TWSR & 0xF8) 
9
        {
10
          case TW_SR_SLA_ACK:              
11
              twi_read_NACK();
12
              twi_stop_slave();
13
              break;
14
          
15
          case TW_ST_SLA_ACK:               
16
              twi_write_slave(100);
17
              twi_stop_slave();
18
              break;
19
              
20
          case TW_ST_ARB_LOST_SLA_ACK: 
21
              PORTB |= (1<<PB0);
22
              break;      
23
          case TW_ST_DATA_ACK: 
24
              PORTB |= (1<<PB0);
25
              break;
26
          case TW_ST_DATA_NACK: 
27
              PORTB |= (1<<PB0);
28
              break;
29
          case TW_ST_LAST_DATA:
30
              PORTB |= (1<<PB0);
31
              break;
32
              
33
          case TW_SR_ARB_LOST_SLA_ACK:
34
              PORTB |= (1<<PB0);
35
              break;
36
          case TW_SR_GCALL_ACK:
37
              PORTB |= (1<<PB0);
38
              break;
39
          case TW_SR_ARB_LOST_GCALL_ACK:
40
              PORTB |= (1<<PB0);
41
              break;
42
          case TW_SR_DATA_ACK:
43
              PORTB |= (1<<PB0);
44
              break;
45
          case TW_SR_DATA_NACK:
46
              PORTB |= (1<<PB0);
47
              break;
48
          case TW_SR_STOP:
49
              PORTB |= (1<<PB0);
50
              break;
51
          case TW_NO_INFO:
52
              PORTB |= (1<<PB0);
53
              break;
54
          case TW_BUS_ERROR:
55
              PORTB |= (1<<PB0);
56
              break;
57
         
58
          default:
59
          break;          
60
        }        
61
      }    
62
    }

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Markus E. schrieb:
> Also
> wird kein anderer Status-Code als 0x60 am Slave mehr zur Verfügung
> gestellt.

Das Problem an Deinem Code ist, daß das TWSR nur nach der ersten Aktion 
ausgewertet wird. Ob dazwischen irgendwas schief läuft, kriegst Du daher 
nicht mit. Du müßtest nach allen Stellen wo auf TWINT gewartet wird, das 
TWSR auswerten.

von Markus E. (opc)


Lesenswert?

Ok, habe TWSR ausgelesen an den relevanten Stellen des Slave, also:

twi_read_NACK() --> TWSR = 0xA0 (A STOP condition or repeated START 
condition has been received while still addressed as Slave)

Ok soweit so gut, dann wollte ich gleiches bei twi_write_slave() 
ausführen, was mir schon gar keinen Status mehr ausgegeben hat.
1
void twi_write_slave(uint8_t data) 
2
{  
3
  TWDR = data;
4
  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
5
  while (!(TWCR & (1<<TWINT))); 
6
  writeDataBCD(TWSR & 0xF8);
7
}

Er betritt wohl die twi_write_slave(100) in der main des Slave gar nicht 
mehr weil kein Status-Code 0xA8 mehr vorliegt, was wiederum heißen 
müsste, dass der SLA+R des Master gar nicht erst am Slave verarbeitet 
wird.

: Bearbeitet durch User
von Markus E. (opc)


Lesenswert?

Nach etlicher Recherche konnte ich mein Problem noch immer nicht lösen. 
Ähnliche Librarys wie von Peter Fleury nutzen selbiges Prinzip für den 
TWI jeodch kein wirkliches Repeated Start, da diese dann ein Stop vorher 
setzen.
Vlt. möchte das mal jemand anders an 2 ATMegas testen? :)

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Schließ doch mal einen PCF8574 an. Damit kannst Du testen, ob der Master 
richtig arbeitet.
Ich hab schon ewig nichts mehr mit I2C gemacht.

Slave ist richtig aufwendig. Dazu braucht man eine Statemaschine im 
Interrupthandler. Immer nur den ersten State auszuwerten und sich dann 
blind weiter zu tasten, erscheint mir zu gewagt.

von Markus E. (opc)


Angehängte Dateien:

Lesenswert?

Ich hatte noch einen PCF8591 herumliegen und habe mal testweise ein 
Repeated Start abgesetzt und dieses ging normal ein und hat 
funktioniert.
Das Problem liegt also wie du schon sagst am Slave.

Na gut, dann trotzdem danke bis hierher, denn weiter weiß ich aktuell 
auch nicht.

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.