Forum: Mikrocontroller und Digitale Elektronik Mega16, I2C Problem mit TWINT


von Felix T. (felix)


Lesenswert?

Hallo Leute

Ich habe einen DS1307 (I2C RTC, Batteriegepuffert) und 7 TLC59116 (I2C 
LED Controller) zusammen an einen Mega16 angeschlossen, inklusive den 
4,7k Pullups an SDA und SCL.
Im Moment bin ich vom Programm her soweit, dass ich aus dem DS1307 die 
Uhrzeit auslesen kann und auch eine andere reinschreiben kann. Die 
TLC59116 bleiben bis jetzt noch außen vor und werden erst später in den 
Code mit integriert.
Ich nutze als I2C-Code-Basis die Bibliotheken von Peter Fleury. Jetzt 
habe ich aber das Problem, dass ab und zu der Controller in folgender 
Routine hängen bleibt
1
unsigned char i2c_write( unsigned char data_byte )
2
{  
3
    uint8_t   twst;
4
    
5
  // send data to the previously addressed device
6
  TWDR = data_byte;
7
  TWCR = (1<<TWINT) | (1<<TWEN);
8
9
  // wait until transmission completed
10
  while(!(TWCR & (1<<TWINT)));
11
12
  // check value of TWI Status Register. Mask prescaler bits
13
  twst = TW_STATUS & 0xF8;
14
  if( twst != TW_MT_DATA_ACK) return 1;
15
  return 0;
16
17
}/* i2c_write */

Das weiß ich zum Glück dank JTAG so genau :-) Hängen bleibt er genau 
hier in dieser Zeile:
1
while(!(TWCR & (1<<TWINT)));

Wie gesagt oft funktionierts aber manchmal eben nicht. Ist euch sowas 
bekannt?
Ich hatte mir schon überlegt, die while-Schleife um eine zweite 
Abbruch-Bedingung zu erweitern:
1
// wait until transmission completed or timeout
2
   i2c_timeout_flag = 0;
3
   while( !(!(TWCR & (1<<TWINT)) || i2c_timeout_flag>3) );

Die Variable i2c_timeout_flag sollte dann in einer Timerschleife 
hochgezählt werden. Im Simulator funktionierts, zumindest die logisch 
Verknüpfung
1
 ( !(!(TWCR & (1<<TWINT)) || i2c_timeout_flag>3) )
 Aber in real spinnt der Controller dann an einer anderen Stelle, beim 
I2C-Stop-Kommando bleibt er hängen:
1
void i2c_stop(void)
2
{
3
    /* send stop condition */
4
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
5
        
6
        // wait until stop condition is executed and bus released
7
        while(TWCR & (1<<TWSTO));       
8
9
}

Im Moment bin ich echt etwas ratlos :( Habt ihr eine Idee?
Die Signale auf SDA und SCL hab ich mir mit dem Oszi angesehen und sehen 
normal aus. Auch ist der Takt sauber bei 100kHz.
Danke schon mal für eure Hilfe.

von Wolfgang H. (Firma: AknF) (wolfgang_horn)


Lesenswert?

Hi, Felix,

bevor ich mich durch Deinen Code quäle, mit meinem vergleiche und mit 
Datenblatt - ein I2C-Sniffer ist Dir da äußerst hilfreich. Schaltung und 
Firmware entweder in diesem Forum irgendwo, oder im Archiv von 
AVRfreaks.

Begründung:
1. Die Anzahl der Fallen in der I2C-Programmierung ist zu hoch für die 
Fehlersuchmethode "Try and Error".
2. Selbst die Anzeige im digitalen Speicheroszilloskop ist bitweise sehr 
mühsam zu lesen.
3. Wer Fehler selber finden kann, der ist mächtiger als einer, der sich 
auf den Rat anderer verlassen muss.
4. Ein I2C-Sniffer kostet ein Pollin-Board plus LCD plus AtTiny2313. Je 
höher Dein Stundensatz für das Debuggen, desto schneller hat es sich 
rentiert.

Ciao
Wolfgang Horn

von Manfred S. (Firma: Manfred) (xfred343)


Lesenswert?

es scheint so, als würde der Takt nicht passen,
hast du wirklich sicher 100 khZ eingestellt?

Welche Werte haben denn TWBR, die 3 lower Bits von TWSR, wie hoch ist 
die Takfrequenz vom Atmega? Der DS1307 verträgt max. 100 kHz!!

manchmal läuft das Programm auch zu schnell, versuche zwischen Interrupt 
löschen und abfragen mit while(TWCR & (1<<TWSTO));
ein paar uSec Wartezeit einzufügen (NOPs)

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.