mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TWI-Busfehler


Autor: Sören (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

für die Kommunikation mit einem DA-Wandler MCP4725 über TWI habe ich mir 
für den ATMEGA168 folgende Funktion geschrieben (bzw. weitestgehend das 
Beispiel aus dem Datenblatt verwendet):
// ###twi_send()###
// Sendet eine Nachricht über TWI
//  -> 1 Byte SLA-W + 2 Bytes Nachrichten
// @Parameter: SLA+W, Datenarray, Länge des Datenarrays
// @Return: 0: alles i.O.
//      1: Übertragung der Start-Condiotion nicht bestätigt
//      2: Senden von SLA+W nicht durch ACK bestätigt
//      3: Senden von Daten nicht durch ACK bestätigt

int twi_send(unsigned char sla, unsigned char dataArray[], int dataArrayLength){
  // START senden
  TWCR = (1<<TWINT)|            // TWINT-Flag löschen
       (1<<TWEN)|            // enable TWI
       (1<<TWSTA);            // Start-Condition übertragen
  
  while(!(TWCR & (1<<TWINT)));      // Warten solange TWINT-Flag = 0
  
  if((TWSR & 0xF8) != START)        // Prescaler-Bits im Statusregister maskiert, Übertragung...
    return 1;              // ...der Start-Condition nicht bestätigt --> ERROR

  // SLA+W senden
  TWDR = sla;                // SLA+W in Datenregister laden
  
  TWCR = (1<<TWINT)|            // TWINT-Flag löschen
       (1<<TWEN);            // enable TWI
  
  while(!(TWCR & (1<<TWINT)));      // Warten solange TWINT-Flag = 0

  lcd_home();
  lcd_dualtoascii(TWSR);
  lcd_string(", ");

  if((TWSR & 0xF8) != SLA_ACK){      // Prescaler-Bits im Statusregister maskiert, Übertragung...
    ERROR();                               // ...des SLA+W-Condition nicht bestätigt --> ERROR

  }

// .........

}

Wenn ich mir nach dem Versuch das SLA+W zu senden das Statusregister 
TWSR ansehe, steht dieses auf 0x00... Was laut Datenblatt einen 
Busfehler infolge illegaler Start- oder Stopbedingung kennzeichnet, also 
das Senden einer solchen zu einem nicht zulässigen Zeitpunkt. Hier also 
vermutlich während das SLA+W gesendet werden soll.

Woran könnte das liegen? Der ATMEGA selber sendet ja nichts falsches, 
ist also evtl der DAC schuld? Können Hardwarefehler in Frage kommen (ich 
finde keine..)

Vielen Dank schonmal,

Sören

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Können Hardwarefehler in Frage kommen (ich finde keine..)

Nie :-)

SDA an SDA, SCL an SCL, 1,5k Pull ups nach VCC, das hast du sicherlich 
schon hundert mal überprüft...

Auch wenn deine Software nach Datenblatt eigentlich richtig sein sollte, 
probier mal die von Peter Fleury. Die funktioniert nachgewiesenermaßen.

Oliver

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder diese Funktionen gehen auch:
//--------------------------------------------------------
// Intialize the I2C-Bus Interface 
// as Master with SCL 100kHz, non interrupt driven
//--------------------------------------------------------

#define F_SCL 100000UL

void TWI_init(void)
{
  //--------------------------------------------------------
  // SCL = F_CPU/(16+2*TWBR*4^TWSR)
  // TWSR=0 => TWBR = F_CPU/2/F_SCL-8
  //--------------------------------------------------------
  TWBR = (u08)(F_CPU/2/F_SCL-7.5);
  TWSR = 0x00;                     // TWI-clock prescaler = (TWSR+1) = 1
  TWCR = (1<<TWEA)|(1<<TWEN);      // no interrupt mode
}


u08 TWI_read(u08 TWI_adr, u08 *val, u08 count)
//------------------------------------------------
// Read n=count bytes from I2C-Bus in polled mode
// needs about 200us for reading addr + one byte
//------------------------------------------------
{
  u08 i=0, rc=0;
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);     // send START condition
  while (!(TWCR & (1<<TWINT)));               // wait for response
  if ((TWSR & 0xF8) == TW_START)              // if START was successful
  {
    TWDR = (TWI_adr | 0x01);                  // put slave address+READ to TWDR
    TWCR = (1<<TWINT)|(1<<TWEN);              // and start transmission
    while (!(TWCR & (1<<TWINT)));             // wait for response
    if ((TWSR & 0xF8) == TW_MR_SLA_ACK)       // if acknowledge ok
    {
      while (--count>0)                       // while more than one byte to read
      {
        TWCR=(1<<TWINT)|(1<<TWEA)|(1<<TWEN);  // then start transfer with acknowledge
        while (!(TWCR & (1<<TWINT)));         // wait for response
        val[i++]=TWDR;                        // read databyte from TWDR
      }
      TWCR=(1<<TWINT)|(1<<TWEN);              // start last byte transfer without acknowledge
      while (!(TWCR & (1<<TWINT)));           // wait for response
      val[i]=TWDR;                            // read databyte from TWDR
    }
    else
    {
      //printl_I("Error: I2C[R] Addr");
      rc = 0x10;
    }
  }
  else
  {
    //printl_I("Error: I2C[R] Start");
    rc = 0x20;
  }
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);      // transmit STOP condition
  _delay_us(10);                                // wait until STOP is transmitted
  return rc;
}

u08 TWI_write(u08 TWI_adr, u08 *val, u08 count)
//------------------------------------------------
// write n=count bytes to I2C-Bus in polled mode
// needs about 200us for writing Addr + one byte
//------------------------------------------------
{
  u08 rc=0;
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   // send START condition
  while (!(TWCR & (1<<TWINT)));             // wait for response
  if ((TWSR & 0xF8) == TW_START)            // if START was successful
  {
    TWDR = (TWI_adr & 0xFE);                // put slave address+WRITE to TWDR
    TWCR = (1<<TWINT)|(1<<TWEN);            // and start transmission
    for (u08 i=0; i<count; i++)
    {
      while (!(TWCR & (1<<TWINT)));         // wait for response
      if ((TWSR & 0xC8) == TW_MT_ACK)       // if acknowledge ok
      {
        TWDR = val[i];                      // put databyte  to TWDR
        TWCR = (1<<TWINT)|(1<<TWEN);        // and start transmission
      }
      else
      {
        //printl_I("Error: I2C[W] Data");
        rc=0x10;
      }
    }
  }
  else
  {
    //printl_I("Error: I2C[W] Start");
    rc=0x20;
  }
  while (!(TWCR & (1<<TWINT)));             // wait for response
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);   // transmit STOP condition
  _delay_us(10);                             // wait until STOP is transmitted
  return rc;
}



Autor: Sören (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke schonmal, ich werds mal ausprobieren!

Achja: Die Pins für SDA und SCL habe ich als Ausgänge, Pullups 
ausgeschaltet, ist das so korrekt?

Und: wer erzeugt mir denn den Busfehler den das Statusregister anzeigt? 
Im Datenblatt klingt es so, als würde der µC verbotenerweise versuchen, 
diese Startbedingung zu senden, während er eigentlich das SLA+W 
übertragen soll..

Viele Grüße, Sören

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.