www.mikrocontroller.net

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


Autor: J.W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
// 2 Wire bus interrupt service routine
interrupt [TWI] void twi_isr(void) {

  switch((TWSR&0xF8)) {
    
    // START has been transmitted
    case 0x08:
    // Repeated START has been transmitted
    case 0x10:
      // Set TWI busy flag
      twi_flag_busy=1;
      // Write slave address and W to data field
      TWDR=(twi_message_t[twi_message_index][0x00]<<1)&0xFE;
      // Send address
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
    
    // Arbitration lost
    case 0x38:
      // Set TWI transmit flag
        twi_flag_t=1;
      // Abort this try 
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE  
    break;
    
    // SLA+W has been tramsmitted and ACK received
    case 0x18:
      // Reset message part
      twi_message_part=0x01;
      // Write data to data field
      TWDR=twi_message_t[twi_message_index][twi_message_part];
      // Send data
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
    
    // Data byte has been tramsmitted and ACK received
    case 0x28:      
      // Continue to send message if necessary
      if((twi_message_part<TWI_MESSAGE_SIZE-0x01)&&(twi_message_t[twi_message_index][0x00]<0x20)) {
        twi_message_part++;
        // Write data to data field
        TWDR=twi_message_t[twi_message_index][twi_message_part];
        // Send data
        TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
      }
      // Message was sent
      else {
        // Delete message from TWI buffer
        twi_message_t[twi_message_index][1]=0xFF;
        // Reset TWI busy flag
        twi_flag_busy=0;
        // Set TWI transmit flag
        twi_flag_t=1;
        // Send STOP
        TWCR=0xD5; // TWINT, TWEA, TWSTO, TWEN, TWIE 
      }    
    break;
    
    // Own SLA+W has been received and ACK has been returned
    case 0x60:
    // Arbitration lost in SLA+R/W as Master, own SLA+W has been received and ACK has been returned
    case 0x68:
    // General call address has been received and ACK has been returned
    case 0x70:
    // Arbitration lost in SLA+R/W as Master, general call address has been received and ACK has been returned
    case 0x78:
      // Set TWI busy flag
      twi_flag_busy=1;
      // Reset message part
      twi_message_part=0x00;
      // Reset TWINT
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
    
    // Previously addressed with own SLA+W, data has been received and ACK has been returned
    case 0x80:
    // Previously addressed with general call, data has been received and ACK has been returned
    case 0x90:
      // Set TWI busy flag
      twi_flag_busy=1;
      // Save data in message
      twi_message_temp_r[twi_message_part]=TWDR;
      if(twi_message_part<TWI_MESSAGE_SIZE-2)
        twi_message_part++;
      // Reset TWINT
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
    
    // A STOP condition or repeated START has been received while still addressed as slave
    case 0xA0:
      twi_message_part=0x00;
      if(twi_attach_r(twi_message_temp_r)) {
        // Set TWI receive flag
        twi_flag_r=1;
      }
      else
        PORTC.7=0;
      // Reset TWI busy flag
      twi_flag_busy=0;
      // Set TWI transmit flag
      twi_flag_t=1;
      // Reset TWINT
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
    
    // Bus error due to an illegal START or STOP
    //case 0x00:
      PORTC.7=0;
      // Reset TWINT
      TWCR=0xC5; // TWINT, TWEA, TWEN, TWIE
    break;
  
  }
}

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:
// Send messages in TWI buffer
void twi_transmit(void) {
  
  // Local variables
  unsigned char index;
  
  if(!twi_flag_busy) {
    for(index=0x00;index<TWI_BUFFER_SIZE;index++) {
      if(twi_message_t[index][1]!=0xFF) {
        // Set index to message index in buffer
        twi_message_index=index;
        // Send START
        TWCR=0xE5; // TWINT, TWEA, TWSTA, TWEN, TWIE
        break;
      } 
    }
  }
  // Reset TWI transmit flag
  twi_flag_t=0;  

}

Und noch die Initialisierung des TWI:
// 2 Wire Bus initialization
// Generate Acknowledge Pulse: On
// 2 Wire Bus Slave Address: TWI_ADDRESS
// General Call Recognition: On
// Bit Rate: 400,000 kHz
TWSR=0x00;
TWBR=0x0C;
TWAR=(TWI_ADDRESS<<1)|0x01;
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: J. W. (arx)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: J. W. (arx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ich schau mir das nochmal an. Danke erstmal!

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht 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?

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.