Liste der Anhänge anzeigen (Anzahl: 5)
Fehler in For-Schleife mit I2C Kommunikation
Hallo,
ich brauche Eure Hilfe bei einer Fehleranalyse, hab im Moment keine Ideen mehr.
Folgendes Problem:
Hardware: ATMEGA16, der über software I2C mit 3 Ultraschallsensoren und einem weiteren Sensor-Board kommuniziert. LCD zum Debuggen im 4-bit Datenmodus.
Setup: externer Quartz mit 18,432 MHz (übertaktet), Fehlerbild ist bei Nutzung des internen RC-Oszillators mit 8 MHz aber identisch.
Software: C-Code anbei, nutzt die I2C Lib (mit Software-TWI und Assembler Source) und LCD Lib (4-bit Datenmodus) von Peter Fleury.
Zuerst wird der I2C Bus initialisiert und die Messungen auf den 3 US-Sensoren wird mit einem General-Schreibbefehl (Adresse 0x00) und das weitere Sensorboard mit einem Schreibbefehl an die I2C Adresse 0xD0) gestartet.
Anhang 18244
Zum Auslesen der 3 US-Sensoren wird eine For-Schleife benutzt. Je nachdem, an welcher Stelle der Aufruf i2c_stop() plaziert wird innerhalb der Schleife, ergeben sich unterschiedliche Fehlerbilder.
Fall1: i2c_stop(); im Code direkt nach dem Lesen des US-Sensors plaziert. Die 3 Senoren (I2C-Adresse E0, E2 und E4) werden richtig gelesen. Aber danach wird die For-Schleife nicht wie beabsichtigt beendet, sondern es wird versucht, weiter endlos die jeweils um 2 inkrementierten Addressen zu lesen. Die FOR-Schleife wird endlos ausgeführt.
Anhang 18243
Code:
// select display
lcd_select(0);
// move cursor to position on line 0
lcd_gotoxy(10,0);
for ( i = 0 ; i < 3 ; i++ )
{
// check if ultrasonic sensor is busy
busy_US = i2c_start(US_left + (2*i) + I2C_READ);
// address I2C device ultrasonic sensor with read access
if (busy_US == 0)
{
[i] distance = i2c_readNak(); // read one byte
i2c_stop(); // release I2C bus
[i] utoa(distance, buffer, 10);
// put string to display (line 0)
lcd_puts(buffer);
lcd_puts(" ");
if (i==2)
{
i2c_start(US_general + I2C_WRITE);
// address I2C device ultrasonic sensor with write access
i2c_write(Start_US); //start new ultrasonic measurement
i2c_stop(); // release I2C bus
}
}
else
{
i2c_stop(); // release I2C bus
}
}
Fall2: i2c_stop(); im Code erst nach der LCD Ausgabe weiter hinten plaziert. Nur noch der erste Sensor wird korrekt gelesen. Dann folgt zweimal ein i2c-Schreibbefehl an die i2c Adresse 0x02. Die Schleife wird sodann beendet und das andere Sensorboard wird korrekt ausgelesen (i2c Adresse 0xD0).
Anhang 18245
Code:
// select display
lcd_select(0);
// move cursor to position on line 0
lcd_gotoxy(10,0);
for ( i = 0 ; i < 3 ; i++ )
{
// check if ultrasonic sensor is busy
[i] busy_US = i2c_start(US_left + (2*i) + I2C_READ);
// address I2C device ultrasonic sensor with read access
[i] if (busy_US == 0)
{
[i] distance = i2c_readNak(); // read one byte
[i] utoa(distance, buffer, 10);
// put string to display (line 0)
lcd_puts(buffer);
lcd_puts(" ");
i2c_stop(); // release I2C bus
if (i==2)
{
i2c_start(US_general + I2C_WRITE);
// address I2C device ultrasonic sensor with write access
i2c_write(Start_US); //start new ultrasonic measurement
i2c_stop(); // release I2C bus
}
}
else
{
i2c_stop(); // release I2C bus
}
}
Fall3: zusätzlich noch 2 (leicht modifizierte) Zeilen zum LCD select und Positionieren des Cursors in die Schleife gezogen vor den Aufruf i2c_stop(); Die I2C Kommunikation läuft korrekt ab. Nur die LCD Ausgabe ist fehlerhaft.
Anhang 18246
Code:
for ( i = 0 ; i < 3 ; i++ )
{
// check if ultrasonic sensor is busy
[i] busy_US = i2c_start(US_left + (2*i) + I2C_READ);
// address I2C device ultrasonic sensor with read access
[i] if (busy_US == 0)
{
[i] distance = i2c_readNak(); // read one byte
[i] utoa(distance, buffer, 10);
// select display
lcd_select(0);
// move cursor to position on line 0
lcd_gotoxy(10+(4*i),0);
// put string to display (line 0)
lcd_puts(buffer);
lcd_puts(" ");
[i][i] i2c_stop(); // release I2C bus
if (i==2)
{
i2c_start(US_general + I2C_WRITE);
// address I2C device ultrasonic sensor with write access
i2c_write(Start_US); //start new ultrasonic measurement
i2c_stop(); // release I2C bus
}
}
else
{
i2c_stop(); // release I2C bus
}
}
Die betreffenden Ausschnitte der I2C Kommunikation, wie ich sie mit einem Logic Analyser aufgezeichnet habe, seht ihr in den 3 anhängenden Bildern:
i2c_fall1.png
i2c_fall2.png
i2c_fall3.png
Der Code ist auch angehängt.
Folgende Fehlermöglichkeiten habe in bisher in Betracht gezogen:
- Übertaktung (18,432 MHz), kann ich aber ausschließen, da das Fehlerbild mit 8 MHz identisch ist.
- Alterung des Flash, Code wird fehlerhaft gelesen. Unwahrscheinlich, da ich den Chip nun seit 5 Jahren betreibe, aber sicher nur an 30 Tagen im Jahr mit ca. 10 Löschvorgängen pro Tag (macht 1500 Programmierzyklen).
- Compiler-Fehler, dafür hab ich auch die Listings angehängt, evtl mal draufschauen.
Bitte helft mir mit Ideen.
Danke, uffi.
Liste der Anhänge anzeigen (Anzahl: 4)
Hier noch besser aufgelöste Bilder als *.png.
Liste der Anhänge anzeigen (Anzahl: 4)
irgendwie wandelt der Uploader meine png immer in blöde jpg um, daher hier nochmal als einzelne zip Dateien:
Liste der Anhänge anzeigen (Anzahl: 1)
Uups, leider zu früh gefreut.
Hab jetzt den Code nach Stefan's Hinweisen modifiziert und das Stack-Problem beseitigt. Die Simulation mit avrstackview bringt nun folgendes Ergebnis:
Analysis complete: 0 errors, 0 warnings
flash usage (words): 2155
global RAM usage (bytes): 609
maximum func. subroutine levels: 6
maximum func. stack (bytes): 35
maximum int. subroutine levels: 1
maximum int. stack (bytes): 8
nested interrupts: 0
maximum nest. int. stack (bytes): 0
maximum total stack (bytes): 43
maximum total subroutine levels: 7
maximum total RAM usage (bytes): 652
Also o.k.
Jedoch zeigt sich nun folgendes Fehlerbild:
Nur noch der erste Sensor (Adresse E0) wird korrekt gelesen. Der zweite mit Adresse E2 wird auch noch gelesen, aber der Wert 02 kann nicht sein (so nahe Werte kann der US Sensor nicht ausgeben), auf dem LCD wird dieser Wert auch nicht mehr ausgegeben, sondern abrupt die FOR-Schleife vorzeitig beendet.
Dann wird das andere Sensorboard korrekt ausgelesen (i2c Adresse 0xD0).
Hat jemand noch eine Idee?
Anbei nochmal alle Sourcen, Daten und ein Bild vom Logic Analyzer gesammelt im File "Problem.zip".
Danke, Dirk.
P.S. Frage noch an Stefan: welches sind string Konstanten in meinem Code?
P.P.S. Wenn ich die Schleife auflöse und alle 3 US-Sensoren einzeln abfrage, funktioniert alles!!! Es muß also an dieser verflixten FOR-Schleife liegen, so sieht sie jetzt aus:
Code:
// select display
lcd_select(0);
for ( i = 0 ; i < 3 ; i++ )
{
// check if ultrasonic sensor is busy
busy_US[i] = i2c_start(US_left + (2*i) + I2C_READ);
// address I2C device ultrasonic sensor with read access
if (busy_US[i] == 0)
{
distance[i] = i2c_readNak(); // read one byte
i2c_stop(); // release I2C bus
utoa(distance[i], buffer, 10);
// move cursor to position on line 0
lcd_gotoxy(10+(4*i),0);
// put string to display (line 0)
lcd_puts(buffer);
lcd_puts(" ");
if (i==2)
{
i2c_start(US_general + I2C_WRITE);
// address I2C device ultrasonic sensor with write access
i2c_write(Start_US); //start new ultrasonic measurement
i2c_stop(); // release I2C bus
}
}
else
{
i2c_stop(); // release I2C bus
}
}