Forum: Mikrocontroller und Digitale Elektronik TWI-Busfehler


von Sören (Gast)


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):
1
// ###twi_send()###
2
// Sendet eine Nachricht über TWI
3
//  -> 1 Byte SLA-W + 2 Bytes Nachrichten
4
// @Parameter: SLA+W, Datenarray, Länge des Datenarrays
5
// @Return: 0: alles i.O.
6
//      1: Übertragung der Start-Condiotion nicht bestätigt
7
//      2: Senden von SLA+W nicht durch ACK bestätigt
8
//      3: Senden von Daten nicht durch ACK bestätigt
9
10
int twi_send(unsigned char sla, unsigned char dataArray[], int dataArrayLength){
11
  // START senden
12
  TWCR = (1<<TWINT)|            // TWINT-Flag löschen
13
       (1<<TWEN)|            // enable TWI
14
       (1<<TWSTA);            // Start-Condition übertragen
15
  
16
  while(!(TWCR & (1<<TWINT)));      // Warten solange TWINT-Flag = 0
17
  
18
  if((TWSR & 0xF8) != START)        // Prescaler-Bits im Statusregister maskiert, Übertragung...
19
    return 1;              // ...der Start-Condition nicht bestätigt --> ERROR
20
21
  // SLA+W senden
22
  TWDR = sla;                // SLA+W in Datenregister laden
23
  
24
  TWCR = (1<<TWINT)|            // TWINT-Flag löschen
25
       (1<<TWEN);            // enable TWI
26
  
27
  while(!(TWCR & (1<<TWINT)));      // Warten solange TWINT-Flag = 0
28
29
  lcd_home();
30
  lcd_dualtoascii(TWSR);
31
  lcd_string(", ");
32
33
  if((TWSR & 0xF8) != SLA_ACK){      // Prescaler-Bits im Statusregister maskiert, Übertragung...
34
    ERROR();                               // ...des SLA+W-Condition nicht bestätigt --> ERROR
35
36
  }
37
38
// .........
39
40
}

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

von Oliver (Gast)


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

von Peter (Gast)


Lesenswert?

Oder diese Funktionen gehen auch:
1
//--------------------------------------------------------
2
// Intialize the I2C-Bus Interface 
3
// as Master with SCL 100kHz, non interrupt driven
4
//--------------------------------------------------------
5
6
#define F_SCL 100000UL
7
8
void TWI_init(void)
9
{
10
  //--------------------------------------------------------
11
  // SCL = F_CPU/(16+2*TWBR*4^TWSR)
12
  // TWSR=0 => TWBR = F_CPU/2/F_SCL-8
13
  //--------------------------------------------------------
14
  TWBR = (u08)(F_CPU/2/F_SCL-7.5);
15
  TWSR = 0x00;                     // TWI-clock prescaler = (TWSR+1) = 1
16
  TWCR = (1<<TWEA)|(1<<TWEN);      // no interrupt mode
17
}
18
19
20
u08 TWI_read(u08 TWI_adr, u08 *val, u08 count)
21
//------------------------------------------------
22
// Read n=count bytes from I2C-Bus in polled mode
23
// needs about 200us for reading addr + one byte
24
//------------------------------------------------
25
{
26
  u08 i=0, rc=0;
27
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);     // send START condition
28
  while (!(TWCR & (1<<TWINT)));               // wait for response
29
  if ((TWSR & 0xF8) == TW_START)              // if START was successful
30
  {
31
    TWDR = (TWI_adr | 0x01);                  // put slave address+READ to TWDR
32
    TWCR = (1<<TWINT)|(1<<TWEN);              // and start transmission
33
    while (!(TWCR & (1<<TWINT)));             // wait for response
34
    if ((TWSR & 0xF8) == TW_MR_SLA_ACK)       // if acknowledge ok
35
    {
36
      while (--count>0)                       // while more than one byte to read
37
      {
38
        TWCR=(1<<TWINT)|(1<<TWEA)|(1<<TWEN);  // then start transfer with acknowledge
39
        while (!(TWCR & (1<<TWINT)));         // wait for response
40
        val[i++]=TWDR;                        // read databyte from TWDR
41
      }
42
      TWCR=(1<<TWINT)|(1<<TWEN);              // start last byte transfer without acknowledge
43
      while (!(TWCR & (1<<TWINT)));           // wait for response
44
      val[i]=TWDR;                            // read databyte from TWDR
45
    }
46
    else
47
    {
48
      //printl_I("Error: I2C[R] Addr");
49
      rc = 0x10;
50
    }
51
  }
52
  else
53
  {
54
    //printl_I("Error: I2C[R] Start");
55
    rc = 0x20;
56
  }
57
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);      // transmit STOP condition
58
  _delay_us(10);                                // wait until STOP is transmitted
59
  return rc;
60
}
61
62
u08 TWI_write(u08 TWI_adr, u08 *val, u08 count)
63
//------------------------------------------------
64
// write n=count bytes to I2C-Bus in polled mode
65
// needs about 200us for writing Addr + one byte
66
//------------------------------------------------
67
{
68
  u08 rc=0;
69
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   // send START condition
70
  while (!(TWCR & (1<<TWINT)));             // wait for response
71
  if ((TWSR & 0xF8) == TW_START)            // if START was successful
72
  {
73
    TWDR = (TWI_adr & 0xFE);                // put slave address+WRITE to TWDR
74
    TWCR = (1<<TWINT)|(1<<TWEN);            // and start transmission
75
    for (u08 i=0; i<count; i++)
76
    {
77
      while (!(TWCR & (1<<TWINT)));         // wait for response
78
      if ((TWSR & 0xC8) == TW_MT_ACK)       // if acknowledge ok
79
      {
80
        TWDR = val[i];                      // put databyte  to TWDR
81
        TWCR = (1<<TWINT)|(1<<TWEN);        // and start transmission
82
      }
83
      else
84
      {
85
        //printl_I("Error: I2C[W] Data");
86
        rc=0x10;
87
      }
88
    }
89
  }
90
  else
91
  {
92
    //printl_I("Error: I2C[W] Start");
93
    rc=0x20;
94
  }
95
  while (!(TWCR & (1<<TWINT)));             // wait for response
96
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);   // transmit STOP condition
97
  _delay_us(10);                             // wait until STOP is transmitted
98
  return rc;
99
}

von Sören (Gast)


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

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.