Forum: Mikrocontroller und Digitale Elektronik I2C rätsehaftes Verhalten


von Attila C. (attila)


Lesenswert?

Hallo!

Dies hier funktioniert:
1
while (1)
2
  {
3
    upper=I2Creceive(0x04);
4
    lower=I2Creceive(0x05);
5
    temp=(float)(upper+(lower/256.0));
6
    dtostrf(temp, 2, 2, test);
7
    string(test);
8
    cursorhome();
9
  }
Dies hier funktinert nicht:
1
  while (1) 
2
  {      
3
    if (loss==1)
4
    {
5
      network();
6
      httpTerm();
7
      httpInit();    
8
    }
9
    if(loss==0)
10
    {
11
      upper=I2Creceive(0x04);
12
      lower=I2Creceive(0x05);
13
      temp=(float)(upper+(lower/256.0));
14
      dtostrf(temp, 2, 2, test);
15
      string(test);
16
      cursorhome();      
17
      httpStream(temp);
18
    }
19
  }
Es funtioniert allerdings reibungsfrei wenn ich bei der I2C Routine die 
"repeated start"  Prüfung (Und nur die!) auskommentiere.

Vielleicht sagt dieses merkwürdige Verhalten jemandem von euch was?

: Bearbeitet durch Moderator
von Eric B. (beric)


Lesenswert?

Mein Glaskugel fängt bei Zeile 42 in der I2Creceive-Funktion zu weinen 
an.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Attila C. schrieb:
> Dies hier funktioniert:
Mit welchem Compiler auf welchem Zielsystem?

> Dies hier funktinert nicht:
Und was "funktioniert" da nicht?
Was erwartest du und was erhältst du stattdessen?

Das hier ist übrigens hübsch gefährlich, wenn sich "loss" zwischendurch 
ändern kann:
1
    if (loss==1)
2
    {
3
      network();
4
      httpTerm();
5
      httpInit();    
6
    }
7
    if(loss==0)
8
    {
9
      :
Ich würde da auf jeden Fall so schreiben:
1
    if (loss==1)
2
    {
3
      network();
4
      httpTerm();
5
      httpInit();    
6
    }
7
    else if (loss==0)
8
    {
9
      :
Und falls "loss" nur 1 oder 0 sein kann, dann so
1
    if (loss==1)
2
    {
3
      network();
4
      httpTerm();
5
      httpInit();    
6
    }
7
    else
8
    {
9
      :



BTW:
Sieh dir mal an, was da ein paar Zeilen über der Eingabebox steht:
1
Wichtige Regeln - erst lesen, dann posten!
2
   ...
3
Formatierung (mehr Informationen...)
4
5
    [c]C-Code[/c]

: Bearbeitet durch Moderator
von Attila C. (attila)


Lesenswert?

Ok ok! Richtig! Das habe ich vergeigt!
Also: Es  ist ein Atmega 8 und geschrieben in C.

Bei der ersten Version wird eine Temperatur über I2C ausgelesen und auf 
dem Display ausgegeben. Ich prüfe sämtliche Statuscodes so wie es im 
datasheet vom Atmega steht.

Bei der zweiten Version wird die Temperatur zusätzlich über ein GSM 
Modul online gestellt. Ansonsten ist alles gleich. Dennoch bleibt die 
I2C Übertragung beim ersten Aufruf bei der Prüfung des "repeated start" 
hängen. Ich habe versuchsweise auf "Start" geprüft (obwohl das 
eigentlich Unsinn ist da es ja in der kurzen Version funktioniert) Ohne 
Erfolg.

Sobald ich die Prüfung auf "repeated start" auskommentiere läuft die 
Übertragung reibungslos.

In meinen "naiven" Augen hat sich, was die I2C Abläufe betrifft 
überhaupt nichts geändert. Daher verstehe ich den Fehler nicht.

Bei meiner I2C Routine wird bei nicht erfolgreicher Prüfung "Stop" 
gesendet.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Attila C. schrieb:
> Sobald ich die Prüfung auf "repeated start" auskommentiere
Die aber nicht im gezeigten Code zu finden ist, oder?

> Bei meiner I2C Routine
Häng die doch einfach mal als *.c Datei hier an...

von Attila C. (attila)


Angehängte Dateien:

Lesenswert?

Sorry ich bin heute neben der Spur. Ich hatte vergessen noch folgendes 
zu erwähnen:

Das Modul für die Temperatur ist ein MPL3115A2. Ich hatte mal eins von 
Pololu und das lief mit dem beigefügten Auszug und noch zusätzlichen 
Routinen.

Das mir jetzt vorliegende Modul ist von Adafruit. Wesentlich Unterschied 
scheint mir zu sein das es auch 5 Volt verarbeiten kann also 
Levelshifter und Spannungsregelung mit an Bord hat.

Ich musste die I2C Gescchwindigkeit von 400 auf unter 100kHz reduzieren 
und (und da könnte der Hase im Pfeffer sein!) die "Stop" Anweisung am 
Ende auskommentieren damit es mit dem Modul von Adafruit lief.

von Rene K. (xdraconix)


Lesenswert?

Meine Glaskugel sagt mir bei Zeile 42:

Vielleicht wird "loss" aber auch nie 0 und er geht deshalb erst garnicht 
in die Prüfung?!

von Attila C. (attila)


Lesenswert?

Naja: Wenn loss nie 0 würde würde die auskommentierte Version nicht 
funktionieren.

Der Fehler ist, vermute ich, irgendwo im I2C zu suchen. Und dort 
vermutlich bedingt durch die geänderte Geschwindigkeit. Es sieht auch 
nicht wirklich schön aus auf dem Oszi. Mir erschliesst sich nur nicht 
warum der Fehler auftritt indem zusätzliche Programmteile angefügt 
werden die nichts mehr mit dem I2C Teil zu tun haben.

von Rene K. (xdraconix)


Lesenswert?

Du sagtest, das funktioniert:
1
 while (1)
2
   {
3
     upper=I2Creceive(0x04);
4
     lower=I2Creceive(0x05);
5
     temp=(float)(upper+(lower/256.0));
6
     dtostrf(temp, 2, 2, test);
7
     string(test);
8
     cursorhome();
9
   }

... und das funktioniert nicht:
1
 while (1)
2
   {
3
     if (loss==1)
4
     {
5
       network();
6
       httpTerm();
7
       httpInit();
8
     }
9
     if(loss==0)
10
     {
11
       upper=I2Creceive(0x04);
12
       lower=I2Creceive(0x05);
13
       temp=(float)(upper+(lower/256.0));
14
       dtostrf(temp, 2, 2, test);
15
       string(test);
16
       cursorhome();
17
       httpStream(temp);
18
     }
19
   }

Da wäre mein allererster Ansatzpunkt: Bekommt loss überhaupt 0 damit es 
in die Abfrage geht!

Wenn doch alles, ohne if Abfrage läuft, wieso sollte es denn dann nicht 
mit Abfrage laufen?! Da erschließt sich mir nur eine einzigste 
Fehlerquelle: loss wird nicht 0!

von Attila C. (attila)


Lesenswert?

Also, wie ich bereits sagte: Das Ding sendet bereits den ganzen Tag die 
aktuelle Raumtemperatur and meine Website weil ich, wei man am 
beigefügten Code sehen kann, die Prüfung des "repeated start" 
auskommentiert habe:

  //if ((TWSR & 0xF8) != 0x10)              // 0x10= repeated START
  //TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);        //

Es wird also nicht geprüft ob das TWI syatem 0x10 zurückgibt. Wenn ich 
es nicht auskommentiere bleibt das I2C an der Stelle stehen.

Es sei denn ich beschränke mich darauf die Temperatur nur hier auf dem 
Breadboard über das LCD auszugeben , also die Version die funktioniert. 
DANN kann und wird die "repeated start" Rückgabe geprüft.

von Attila C. (attila)


Lesenswert?

Der vollständigkeit halber: Mich stört auch ungemein dass ich bei beiden 
Versionen die "Stop" condition auskommentieren musste. Das kann nicht 
korrekt sein! Ich habe mit verschiedenen TWI Geschwindigkeiten und 
verschiedenen Delays zwischen den Abfragen rumprobiert aber nichts hat 
bislang geholfen.

von Attila C. (attila)


Angehängte Dateien:

Lesenswert?

Das STOP Problem ist jetzt gelöst. Der Sensor mochte das ACK nach dem 
Auslesen der Daten nicht.

Es bleibt bei der auskomentierten Prüfung der START condition. 
Allerdings jetzt bei beiden Versionen. Ich vermute da die Ausgabe auf 
das LCD wesentlich schneller geht als der "upload" ins Netz hat er die 
"repeated start" condition anerkannt.

Anbei der aktuelle Code.

von spess53 (Gast)


Lesenswert?

Hi

>Das STOP Problem ist jetzt gelöst. Der Sensor mochte das ACK nach dem
>Auslesen der Daten nicht.

Dann führe dir mal die

http://www.nxp.com/documents/user_manual/UM10204.pdf

Da steht so etwas drin.

MfG Spess

von Attila C. (attila)


Lesenswert?

Ja, vielen Dank! Sehr interessante Lektüre. Allerdings hilft es leider 
für das andere Problem nicht weiter. Die TWI Status Codes scheinen ja 
eher eine Atmel Sache zu sein.

von Joachim B. (jar)


Lesenswert?

Attila C. schrieb:
> Das STOP Problem ist jetzt gelöst. Der Sensor mochte das ACK nach dem
> Auslesen der Daten nicht.

für das letzte Byte muss ja auch NACK gemacht werden!

ACK nur wenn noch Bytes erwartet werden!

Dann gibt es noch i2c stretching, man muss nur warten bis beide SDA und 
SCL wieder auf high gehen, oder bei I2C EEProms prüfen bis sie wieder 
Antworten.

Für ACK und NACK schau dir mal den Fleury Code an!

http://homepage.hispeed.ch/peterfleury/avr-software.html

von Attila C. (attila)


Lesenswert?

So! Das Rätsel scheint gelöst. Meine Routinen warteten nicht darauf das 
die Stop condition ausgeführt wird und rannten sofort weiter zum Start. 
Ging manchmal gut und manchnmal nicht.

Ein:

while(TWCR & (1<<TWSTO));

hinter dem Senden des Stop Befehls schaffte Abhilfe.

Der Blick in den Fleury Code war sehr aufschlussreich.

Vielen Dank an all die mir hier geholfen haben, ich hoffe der Beitrag 
kann auch anderen helfen.

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.