Forum: Mikrocontroller und Digitale Elektronik TWI bricht zusammen - falsche Bearbeitung oder Timingproblem!?


von J.W. (Gast)


Lesenswert?

Hallo an alle!

Ich betreibe 3 (später sollen es 7 werden) Atmega32 (16 Mhz) in einem 
TWI-Multimaster-System mit 400kHz und einer Leitungslänge von etwa 
30cm... und bin verzweifelt: Nach einer kleinen Initialisierung sollen 
sich die Controller mit einer Art Ping-Funktion gegenseitig 
kontrollieren: Alle 200ms wird eine Anfrage geschickt und 200ms später 
kontrolliert, ob eine Antwort gekommen ist (1 kontrolliert 2, 2 
kontrolliert 3 und 3 kontrolliert 1). Ich benutze dazu den 
MasterTransiever- und den SlaveReceiver-Modus. Neben diesen "Pings" 
führen die Controller noch unterschiedliche Hauptfunktionen aus, die 
alle 4ms (Controller 3), 40 (Controller 1) oder 100ms (Controller 2) 
ausgefrufen werden.

Die Initialisierung des Systems, bestehend aus 2 Nachrichten (2 mal 3 
Byte) pro Controller, klappt (meistens) noch gut, aber danach bricht das 
TWI komplett zusammen. Außer ich plaziere in einer der main-Schleifen 
ein Delay von mindestens 20μs. Leider kann ich nicht vernünftig 
Debuggen, da sobald ich mein LCD ansteuere ja eine Verzögerung entsteht 
und alles funktioniert (JTAG wäre jetzt sicherlich hilfreich). Ich 
behandle den TWI Interrupt-basiert, hier ist der Code des Interrupts:
1
// 2 Wire bus interrupt service routine
2
interrupt [TWI] void twi_isr(void) {
3
4
  switch((TWSR&0xF8)) {
5
    
6
    // START has been transmitted
7
    case 0x08:
8
    // Repeated START has been transmitted
9
    case 0x10:
10
      // Set TWI busy flag
11
      twi_flag_busy=1;
12
      // Write slave address and W to data field
13
      TWDR=(twi_message_t[twi_message_index][0x00]<<1)&0xFE;
14
      // Send address
15
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
16
    break;
17
    
18
    // Arbitration lost
19
    case 0x38:
20
      // Set TWI transmit flag
21
        twi_flag_t=1;
22
      // Abort this try 
23
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE  
24
    break;
25
    
26
    // SLA+W has been tramsmitted and ACK received
27
    case 0x18:
28
      // Reset message part
29
      twi_message_part=0x01;
30
      // Write data to data field
31
      TWDR=twi_message_t[twi_message_index][twi_message_part];
32
      // Send data
33
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
34
    break;
35
    
36
    // Data byte has been tramsmitted and ACK received
37
    case 0x28:      
38
      // Continue to send message if necessary
39
      if((twi_message_part<TWI_MESSAGE_SIZE-0x01)&&(twi_message_t[twi_message_index][0x00]<0x20)) {
40
        twi_message_part++;
41
        // Write data to data field
42
        TWDR=twi_message_t[twi_message_index][twi_message_part];
43
        // Send data
44
        TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
45
      }
46
      // Message was sent
47
      else {
48
        // Delete message from TWI buffer
49
        twi_message_t[twi_message_index][1]=0xFF;
50
        // Reset TWI busy flag
51
        twi_flag_busy=0;
52
        // Set TWI transmit flag
53
        twi_flag_t=1;
54
        // Send STOP
55
        TWCR=0xD5; // TWINT, TWEA, TWSTO, TWEN, TWIE 
56
      }    
57
    break;
58
    
59
    // Own SLA+W has been received and ACK has been returned
60
    case 0x60:
61
    // Arbitration lost in SLA+R/W as Master, own SLA+W has been received and ACK has been returned
62
    case 0x68:
63
    // General call address has been received and ACK has been returned
64
    case 0x70:
65
    // Arbitration lost in SLA+R/W as Master, general call address has been received and ACK has been returned
66
    case 0x78:
67
      // Set TWI busy flag
68
      twi_flag_busy=1;
69
      // Reset message part
70
      twi_message_part=0x00;
71
      // Reset TWINT
72
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
73
    break;
74
    
75
    // Previously addressed with own SLA+W, data has been received and ACK has been returned
76
    case 0x80:
77
    // Previously addressed with general call, data has been received and ACK has been returned
78
    case 0x90:
79
      // Set TWI busy flag
80
      twi_flag_busy=1;
81
      // Save data in message
82
      twi_message_temp_r[twi_message_part]=TWDR;
83
      if(twi_message_part<TWI_MESSAGE_SIZE-2)
84
        twi_message_part++;
85
      // Reset TWINT
86
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
87
    break;
88
    
89
    // A STOP condition or repeated START has been received while still addressed as slave
90
    case 0xA0:
91
      twi_message_part=0x00;
92
      if(twi_attach_r(twi_message_temp_r)) {
93
        // Set TWI receive flag
94
        twi_flag_r=1;
95
      }
96
      else
97
        PORTC.7=0;
98
      // Reset TWI busy flag
99
      twi_flag_busy=0;
100
      // Set TWI transmit flag
101
      twi_flag_t=1;
102
      // Reset TWINT
103
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
104
    break;
105
    
106
    // Bus error due to an illegal START or STOP
107
    //case 0x00:
108
      PORTC.7=0;
109
      // Reset TWINT
110
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
111
    break;
112
  
113
  }
114
}

Mein Sende Buffer (twi_message_t) ist 5 Felder groß und jeder Eintrag 
besteht auf 4 Byte (Zieladresse und 3 Datenbyte). Allerdings werden auch 
noch Port-Expander (PCF8574), so dass in machen Fällen (Adresse < 0x20) 
nach dem ersten Datenbyte abgebrochen werden kann. Ein Feld im Buffer 
gilt als leer, wenn das erste Datenbyte einen Wert von 0xFF hat. Der 
Empfangsbuffer ist genauso aufgebaut und wird mit 
twi_attach_r(twi_message_temp_r) befüllt.

Eine Übertragung wird mit einer Funktion initiert, die in der 
main-Schleife bei gesetztem twi_flag_t aufgerufen wird und versucht ein 
START zu senden:
1
// Send messages in TWI buffer
2
void twi_transmit(void) {
3
  
4
  // Local variables
5
  unsigned char index;
6
  
7
  if(!twi_flag_busy) {
8
    for(index=0x00;index<TWI_BUFFER_SIZE;index++) {
9
      if(twi_message_t[index][1]!=0xFF) {
10
        // Set index to message index in buffer
11
        twi_message_index=index;
12
        // Send START
13
        TWCR=0xE5; // TWINT, TWEA, TWSTA, TWEN, TWIE
14
        break;
15
      } 
16
    }
17
  }
18
  // Reset TWI transmit flag
19
  twi_flag_t=0;  
20
21
}

Und noch die Initialisierung des TWI:
1
// 2 Wire Bus initialization
2
// Generate Acknowledge Pulse: On
3
// 2 Wire Bus Slave Address: TWI_ADDRESS
4
// General Call Recognition: On
5
// Bit Rate: 400,000 kHz
6
TWSR=0x00;
7
TWBR=0x0C;
8
TWAR=(TWI_ADDRESS<<1)|0x01;
9
TWCR=0x45;

Entschuldigung für den langen Post! Arbeitet meine Interrupt-Rountine 
richtig? Habe ich einen "Fall" vergessen (Kollision)? Achja: Habe das 
ganze auch schon bei 1000ms Ping-Takt versucht, aber es geht auch nicht, 
nach der ersten oder zweiten Anfrage/Bestätigung geht auf dem TWI nix 
mehr, die Controller laufen aber noch. Ich versuche jetzt seit 3 Tagen 
dahinter zu kommen und finde einfach nichts. Bin für jede Anregung 
außerst dankbar!

J.W.

von Peter D. (peda)


Lesenswert?

Wenn Du willst, daß man sich den Code auch ansieht, mußt Du ihn als 
Anhang senden, sonst scrollt man sich ja tot (wichtige Regeln Punkt 5)!

Ich kann bestätigen, daß Multimaster-I2C mit AVRs ne haarige Sache ist.
Ich hatte keine Zeit mehr, den Hänger zu finden und hab dann nen Timeout 
aufgesetzt.

Ich mache Multimaster-I2C nie wieder!


Peter

von J. W. (arx)


Angehängte Dateien:

Lesenswert?

Oh, entschuldigung. Da habe ich gar nicht dran gedacht. Ich habe den 
Code mal in eine txt-Datei geschmissen und an diese Nachricht angehängt. 
Aber ob man sich nun im Browser oder in nem Editor tot scrollt... nun 
ja, wie auch immer.

Hätte nicht gedacht, dass das so problematisch wird mit dem Multimaster, 
da im Datenblatt was von Multimaster-fähig steht. Aber vielleicht 
könntet Ihr trotzdem nochmal grob drüberschauen, ob ich nicht 
irgendeinen grundlegenden Zustand des TWI vergessen habe. Die NACKs habe 
ich z.B. komplett ausgeklammert, da ich die eigentlich gar nicht 
erzeuge(n will). Könnt das ein Problem sein?!

Danke schon mal für die Beachtung und den Hinweis!

Janis

von Peter D. (peda)


Lesenswert?

Janis Wojtusch wrote:
> Oh, entschuldigung. Da habe ich gar nicht dran gedacht. Ich habe den
> Code mal in eine txt-Datei geschmissen

Warum das denn?

Quelltexte postet man als C-Datei, dann werden sie auch richtig 
formatiert im Forum angezeigt.


Peter

von Peter D. (peda)


Lesenswert?

Janis Wojtusch wrote:
> Die NACKs habe
> ich z.B. komplett ausgeklammert, da ich die eigentlich gar nicht
> erzeuge(n will). Könnt das ein Problem sein?!

Könnte sein.

Die NACK/ACK sind für den I2C-Bus lebenswichtig. Sie müssen immer 
korrekt erzeugt und ausgewertet werden.


Peter

von J. W. (arx)


Lesenswert?

Ok, ich schau mir das nochmal an. Danke erstmal!

von Klaus W. (Firma: privat) (texmex)


Lesenswert?

Peter Dannegger schrieb:
> Janis Wojtusch wrote:
>> Die NACKs habe
>> ich z.B. komplett ausgeklammert, da ich die eigentlich gar nicht
>> erzeuge(n will). Könnt das ein Problem sein?!
>
> Könnte sein.
>
> Die NACK/ACK sind für den I2C-Bus lebenswichtig. Sie müssen immer
> korrekt erzeugt und ausgewertet werden.

Müssen sie das wirklich solange sich Master und Slave trotzdem einig 
sind?

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.