- Labornetzteil AliExpress         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 26

Thema: Fehler in For-Schleife mit I2C Kommunikation

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199

    Fehler in For-Schleife mit I2C Kommunikation

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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.
    Klicke auf die Grafik für eine größere Ansicht

Name:	i2c_start.jpg
Hits:	12
Größe:	19,4 KB
ID:	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.
    Klicke auf die Grafik für eine größere Ansicht

Name:	i2c_fall1.jpg
Hits:	7
Größe:	17,9 KB
ID:	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).
    Klicke auf die Grafik für eine größere Ansicht

Name:	i2c_fall2.jpg
Hits:	5
Größe:	17,6 KB
ID:	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.
    Klicke auf die Grafik für eine größere Ansicht

Name:	i2c_fall3.jpg
Hits:	5
Größe:	19,9 KB
ID:	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.
    Angehängte Dateien Angehängte Dateien

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    Hier noch besser aufgelöste Bilder als *.png.
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken i2c_fall1.jpg   i2c_start.jpg   i2c_fall2.jpg   i2c_fall3.jpg  

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    irgendwie wandelt der Uploader meine png immer in blöde jpg um, daher hier nochmal als einzelne zip Dateien:
    Angehängte Dateien Angehängte Dateien

  4. #4
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    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.
    • Es ist mit ziemlicher Sicherheit Möglichkeit #4, eine data/stack-Collision. Du versuchst mehr RAM zu verwenden, als überhaupt da ist. Da werden dann Daten zerstört und die merkwürdigsten Effekte sind die Folge.
    MfG
    Stefan

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    Ja, super Idee. Allerdings sagt der Compiler:

    Size after:
    allrounder.elf :
    section size addr
    .text 4236 0
    .data 570 8388704
    .bss 14 8389274
    .eeprom 512 8454144
    .stab 1440 0
    .stabstr 183 0
    .debug_aranges 64 0
    .debug_pubnames 531 0
    .debug_info 2184 0
    .debug_abbrev 838 0
    .debug_line 3084 0
    .debug_frame 432 0
    .debug_str 801 0
    .debug_loc 1141 0
    Total 16030

    Sehe ich das richtig, dass der Compiler von den 1kByte SRAM 570 Bytes für die Variablen reserviert?
    Dann müßte der Stack aber schon sehr lang werden, damit das die Ursache für den Fehler sein kann...

    Oder liege ich da falsch?

    Danke und Gruß, uffi.

  6. #6
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von uffi Beitrag anzeigen
    Sehe ich das richtig, dass der Compiler von den 1kByte SRAM 570 Bytes für die Variablen reserviert?
    Nein, 584 Bytes. Und das sind nur die statischen Variablen.

    Zitat Zitat von uffi Beitrag anzeigen
    Dann müßte der Stack aber schon sehr lang werden, damit das die Ursache für den Fehler sein kann...
    Ja, wird er ja aber auch. Allein mit der Variable "distRAM" belegst du 512 Bytes auf dem Stack. Und schon bist du über den 1024 Bytes.


    Da du ja wohl kaum die Funktion main rekursiv aufrufen willst, solltest du als erstes mal die lokalen Variablen dort static machen. Dann sind sie vom Stack runter und tauchen mit in der Auflistung vom Compiler auf. Das gibt dir etwas mehr Überblick. Dann reduzierst du den RAM-Verbrauch, indem du alle konstanten Strings ins Flash verbannst. Und dann sehen wir weiter.

    Und mal so nebenbei:
    Dieses SREG-Gefummel in den ISRs ist völlig überflüssig. Darum kümmert sich der Compiler.
    Geändert von sternst (15.03.2011 um 16:34 Uhr)
    MfG
    Stefan

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    Vielen Dank sternst!!!

    Thema ist damit gelöst.

    Ich habe mit dem kleinen Program avrstackview und meiner .elf Datei den Stack-Verbrauch berechnen lassen. Hier das Ergebnis:

    Analysis complete: 0 errors, 0 warnings
    flash usage (words): 2118
    global RAM usage (bytes): 1096
    maximum func. subroutine levels: 6
    maximum func. stack (bytes): 554
    maximum int. subroutine levels: 1
    maximum int. stack (bytes): 9
    nested interrupts: 0
    maximum nest. int. stack (bytes): 0
    maximum total stack (bytes): 563
    maximum total subroutine levels: 7
    maximum total RAM usage (bytes): 1659

    Ich benutze also 1659 Bytes RAM und habe nur 1024.

    Vielen, vielen Dank nochmal, das ist die Lösung meines Problems!!!

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    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
       }
      }
    Angehängte Dateien Angehängte Dateien
    Geändert von uffi (15.03.2011 um 22:15 Uhr) Grund: Ergänzung

  9. #9
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Wie groß können denn die gelieferten Werte werden? Bestimmt doch auch größer als 99, oder? In dem Fall ist buffer zu klein. Für eine dreistellige Zahl muss buffer die Größe 4 haben (drei Ziffern plus Null-Terminierung).

    P.S. Frage noch an Stefan: welches sind string Konstanten in meinem Code?
    All die Strings in Anführungszeichen, z.B.
    Code:
    lcd_puts("Sensor Board 2 Results: ");
    Die belegen aktuell auch Platz im RAM, was aber nicht nötig wäre.
    MfG
    Stefan

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    ja, Du hast Recht, bei buffer kommen Zahlen bis 3-stellig vor:

    es muß heißen static char buffer(4);

    Komischerweise hat das aber bisher keinen Fehler gegeben, die LCD Anzeige ist korrekt mit 3 Ziffern. Kann das für den Schleifenabbruch verantwortlich sein?

    Vielen Dank für Deine Hilfe!

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen