Forum: Compiler & IDEs AVR GCC TWI zwischen 2 Controllern geht nur einmal


von Martin N. (martin02)


Lesenswert?

Hallo zusammen,

zwei ATmega32 sollen per I2C/TWI kommunizieren. Der Master soll sich 
drei Byte vom Slave "holen". Baudrate ist ca. 100kHz, pullups 2,2k, 
Leitung ca. 20cm.

Beim ersten Durchlauf geht es, beim zweiten bleibt der Master an der 
markierten Stelle hängen. SDA ist dabei LOW.

Ich habe schon einiges probiert. Hier die wichtigsten Ausschnitte aus 
den Codes der beiden Controller:

Danke für eure Unterstützung!
Grüße
Martin
1
//Master:
2
  //Initialisierung:
3
    TWBR = 255;//56;                // I²C Bitrate ca. 100kHz
4
    TWCR = (1<<TWEN)|(1<<TWEA);     // I²C ein mit Interrupt
5
    TWSR = 0;                       // kein Prescaler
6
    TWAR = 0;
7
    
8
  //Dies hier wird aufgerufen, um was vom Slave zu holen:  
9
    
10
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWEA);    // START
11
    while(!(TWCR&(1<<TWINT)));              
12
    
13
    TWDR = 0x03;                                    // SLA+R laden
14
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);          // SLA+R senden
15
    while(!(TWCR&(1<<TWINT)));                   //HIER HÄNGTS!
16
17
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);          // Bus freimachen
18
    while(!(TWCR&(1<<TWINT)));   
19
    a = TWDR;                                       // Byte auswerten
20
21
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);          // Bus freimachen 
22
    while(!(TWCR&(1<<TWINT)));
23
    b = TWDR;                                       // Byte auswerten
24
    
25
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);          // Bus freimachen
26
    while(!(TWCR&(1<<TWINT)));
27
    c = TWDR;                                       // Byte auswerten
28
    
29
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWEA);    // STOP
30
31
//Slave:
32
  //Initialisierung:
33
    TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWEA);      // I²C ein mit Interrupt
34
    TWSR = 0;
35
    TWAR = 0x02;                               // Slaveadresse 1
36
    sei();
37
    
38
  //Interrupt:
39
  ISR(SIG_2WIRE_SERIAL)
40
  {
41
    static uint8_t count = 0;
42
    if(TWSR==0xA8)                   // Slave Transmit angesprochen 
43
    {
44
      count = 0;
45
      TWDR = temp[count];            // erstes Byte senden
46
    }
47
    if(TWSR==0xB8)                   // ACK für Byte erhalten
48
    {
49
      count++;
50
      TWDR = temp[count];            // weitere Bytes senden
51
    }
52
    TWCR |= (1<<TWINT);              // TWI freigeben
53
  }

von (prx) A. K. (prx)


Lesenswert?

Falsches Forum, denn es geht um I2C, nicht um GCC.

Der Slave muss seiner TWI state machine mit TWEA signalisieren ob es das 
letzte Byte ist, oder ob weitere folgen sollten/können. Andernfalls 
landest du bei einem bus error.

In deiner ISR fehlt das immer erforderliche Prozedere für einen bus 
error (state 00). Auf diesen läuft dein Slave beim unerwarteten STOP und 
schmollt.

von Martin N. (martin02)


Lesenswert?

Danke für die Antwort. Welches Forum passt besser? µC&Elektronik?

TWEA stelle ich doch einmal an und lasse es an. Also wird generell mit 
ACK gearbeitet. Wie soll ich damit was signalisieren?

Wie meinst du das, dass der Slave auf Error läuft? Wenn er gefragt wird, 
schickt er Daten und wenn ein Stop kommt, dann ist der Bus halt wieder 
frei und es werden keine Daten angefordert, oder? Kannst du mir evtl. 
ausführlicher erklären, was du meinst?

von (prx) A. K. (prx)


Lesenswert?

Martin N/a schrieb:

> TWEA stelle ich doch einmal an und lasse es an. Also wird generell mit
> ACK gearbeitet. Wie soll ich damit was signalisieren?

Falschrum gedacht. Wenn der Slave ein Transmitter ist, dann kommt das 
ACK vom Master. TWEA beeinflusst also nicht das ACK, wohl aber die State 
Machine vom TWI. Und wenn du der sagst, dann noch ein Byte folgt 
(TWEA=1), der Master aber statt dessen eine STOP Condition bringt, dann 
ist das TWI vom Slave beleidigt und schmollt.

Korrekt ist es nur, wenn du mit dem letzten Byte TWEA auf 0 setzt. Was 
nicht zwingend ist, aber andernfalls musst du eben mit dem Bus Error am 
Ende vom Transfer leben.

> wenn ein Stop kommt, dann ist der Bus halt wiedern frei

Falsch gedacht. Der Slave erwartet eine weitere Datenanfrage, kriegt 
statt dessen ein STOP und die State Machine läuft auf State=00 aka "bus 
error".

Und wie man damit umgeht steht unter "Miscellaneous States" im 
Datasheet: STO setzen. Solltest du auch dann handhaben können, wenn TWEA 
korrekt ist, weils immer mal passieren kann und du sonst nicht raus 
kommst.

von Martin N. (martin02)


Lesenswert?

Danke, mit deiner Hilfe hat es geklappt! Die Fehlerabfrage habe ich mal 
als erstes eingebaut (du hast ja Recht...). Dadurch wurde das Aufhängen 
vermieden.

TWEA wird jetzt beim letzten Byte nicht gesetzt. Wenn dieses Byte dann 
gesendet ist (last byte transmittet : 0xC8), setze ich TWEA wieder. So 
gibt es auch keinen Error mehr.

Vielen Dank und schönen Abend.
Martin

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.