www.mikrocontroller.net

Forum: Compiler & IDEs ATMEGA128 und for Schleife


Autor: Christian Rothe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich hab da mal ein Problem. Es ist echt zum verzweifeln.

ich habe ein Programm unter AVR-Studio in C für meinen ATMEGA128, in dem 
irgendwann eine Funktion angesprungen wird, die über lese und schreib 
char pointer einen Text in einen am Funktionsbeginn definierten Puffer 
schreiben soll. Das ganze passiert in einer 'for' Schleife, die z.b. 7 
mal durchlaufen wird(also 7 Zeichen kopieren). Den Schleifenzähler (ein 
int) setze ich vor der Schleife auf 0. Nun das Problem: Sobald ich im am 
Break point in der Zeile des Schleifenbeginns anhalte ist der Zähler auf 
0. Wen ich einen Schritt weiter gehe, überspringt er die Schleife und 
setzt den Zähler auf 1799.
Ich habe schon die ganze geschichte in eine andere Funktion 
nachgeschrieben mit garantiert nur einmalig vorkommenden Variablen und 
erhalte den gleichen Effekt.

Hat jemand eine Ahnung was das sein kann? Wofür ist den 1799 eine 
typische Zahl?

bin für jeden Hinweis dankbar

Gruß
Christian

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Fehler ist in Zeile 23 deines Programmes, das nur DU kennst.

Autor: Christian Rothe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt, jetzt sehe ichs :). OK hier das eigentlich triviale 
Code-Schnipsel:

int WriteTab(char *value, int row)
  {

  int m_c;
  int m_x;
  char m_text[]="Das ist der Text zum Test";
  char m_buf[64];

  char* bp;

  m_x = 5;
  m_c = 0;
  bp = m_buf;

      cli();  // testweise wegen Fehlersuche
  for (m_c=0; m_c < m_x; m_c++)  //hier ist m_c noch 0. Ein
                                    // Step weiter überspringt die 
Schleife
    {
    *bp = m_text[m_c];
    bp++;
    }
      sei();  //Testweise wegen Fehlersuche
  *bp=0;  // hier springt er hin und m_c=1799?????
  bp++;


//ab hier folgt noch anderer Code
}


Das ist natürlich nur ein Teil des gesamten Programmes und ich kann mir 
garnicht vorstellen, dass der Fehler in diesen Zeilen lieg.

Christian

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die komplette Schleife hat eine feste Funktion, die bereits zur
Compilezeit aufgelöst werden kann.  Der Optimizer kann also im
Extremfall ermitteln, dass er "Das i" in die ersten 5 Bytes von
m_buf[] schreiben kann, und damit hat sich's.

Trau bitte dem Compiler einfach mal übern Weg und versuch nicht,
viel zu weit vereinfachte Testfälle zu ,,debuggen''.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Trau bitte dem Compiler einfach mal übern Weg und versuch nicht,
>viel zu weit vereinfachte Testfälle zu ,,debuggen''.

Erklärungsversuch von mir:
Wenn die Optimierung eingeschaltet ist kann der Compiler
Schleifenzähler wegoptimieren. Er benutzt dann zum
Beispiel einfach den aktuellen Wert von Pointer bp als
Abbruchbedingung. Die Variable m_c existiert im optimierten
Code einfach nicht mehr, weil sie nicht benötigt wird.

Debuggen sollte man immer OHNE Optimierung.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn die Optimierung eingeschaltet ist kann der Compiler
> Schleifenzähler wegoptimieren.

Hätte ich auch vermutet, aber ich kenne es eigentlich so, daß der 
Debugger dann keinen Müll ausgibt, sondern explizit hinschreibt, daß die 
Variable an der Stelle wegoptimiert wurde.

> Debuggen sollte man immer OHNE Optimierung.

Die Aussage ist so pauschal falsch. Debuggen sollte man immer den Code, 
der nachher auf dem System läuft und nicht irgendwelchen anderen. 
Optimierungen bringen oft noch einige Fehler im Code hervor, die man 
ohne Optimierungen gar nicht erkennt. Daher muß das Programm auf jeden 
Fall mit den Einstellungen gedebuggt werden, mit denen es auch nachher 
laufen soll. Im ersten Schritt kann man aber - sofern das Programm so 
überhaupt sinnvoll läuft (Stichwort Timing) - auch ohne Optimierungen 
debuggen, da das einfacher ist.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus wrote:

> Hätte ich auch vermutet, aber ich kenne es eigentlich so, daß der
> Debugger dann keinen Müll ausgibt, sondern explizit hinschreibt, daß die
> Variable an der Stelle wegoptimiert wurde.

Wenn es die Variable gar nicht mehr gibt, bekommt sie auch keine
Debuginformation, sodass der Debugger sie nicht anzeigen kann.
Was aber passieren kann ist, dass die Variable an anderer Stelle
noch benutzt wird und zum Beispiel auf ein Register(paar) gemappt
ist.  Dann zeigt der Debugger den Inhalt des Registers als
vermeintliche Variable an dieser Stelle an, was auch immer gerade
drin steht -- der Compiler kann (und sollte) an dieser Stelle die
entsprechenden Register ja freizügig für andere Dinge benutzen.

Es gibt glaub ich Ansätze, die Debuginformation nur für Teile einer
Funktion als zutreffend zu deklarieren, aber 1.) ist das meines
Wissens selbst für die mainstream targets des GCC noch in den
Anfängen, und 2.) denke ich, dass es noch ein Weilchen dauer wird,
bis auch ein Debugger wie AVR Studio derartige Features dann
unterstützen wird.

Autor: Christian Rothe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen Dank erstmal für die Diskussion,

ich habe das Problem im Moment nicht mehr, da ich anderen Code auslasse, 
d.h. wenn ich den problematischen Funktionsaufruf zu Begin des 
Programmes ausführe läuft es fehlerfrei. So nach ca. 10 Zeilen 
verschiedenster Initialisierungs routinen Aufrufe lässt sich die 
Funktion nicht mehr aufrufen. Scheint mir so, als würde ich irgendwas 
innerhalb dieser Routinen anrichten, was dann an anderer Stelle zum 
Problem führt. Die jetzige Lösung ist also recht unsicher, da ich ja die 
Ursache sicher nicht beseitigt habe.
Ich hab bei der Gelegenheit mal ne sicher recht einfache Frage, zu der 
ich aber keine Antwort finden kann. Wie ist denn der Speicher im 
ATMEGA128 organisiert (adressmäßig) und wie kann ich im AVRStudio die 
entsprechende Speichernutzung anzeigen lassen. Jeder scheint es zu tun 
und es ist wohl so einfach, dass keiner darüber spricht wie es 
geht...ich kann es nicht finden.

Christian Rothe

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Rothe wrote:
> ich aber keine Antwort finden kann. Wie ist denn der Speicher im
> ATMEGA128 organisiert (adressmäßig) und wie kann ich im AVRStudio die
> entsprechende Speichernutzung anzeigen lassen. Jeder scheint es zu tun
> und es ist wohl so einfach,

Nö.

> dass keiner darüber spricht wie es

Das hat einen einfachen Grund: Es interessiert praktisch nie.
Das ist das Bier des Compilers wie er den Speicher einsetzt, was
soll ich mich da einmischen.

Natürlich gibts Ausnahmen: Wenn der Speicher so voll wird, dass
der Heap in den Stack wandert, dann gibts Ärger. Aber abgesehen
davon, soll der Compiler die Variablen in den Speicher legen
wie es ihmam besten in den Kram passt. Ist mir relativ egal
wie er das macht.

Autor: Christian Rothe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also auch wenn es nervt, ich komme hier nicht weiter. folgender Code:

int WriteTab(char *value)
{
    int l=0;                          //hier ist l=3341
    int sz;                           //hier ist sz=2814
    //string length without EOS
    l=strlen(value) - 1;              //hier wird l=4, das stimmt
    sz=0;                             //hier wird sz=3314 HAARERAUF...
                                      //was ist denn da los???
    //if there is enough space at dbuf0
    if (dbwp0+l < dbuf0+TextBufSize)
    {
  //write string to buffer
  while(1<l)
  {
      *dbwp0=value[sz];
      dbwp0++;
//    sz++;
  }
  //add string end '0'
  *dbwp0 = 0;
  dbwp0++;
    }
    else
  //return error
  return 0;
    //return OK
    return 1;
}

Was passiert denn mit der Variablen sz? Ich habe Eure Hinweise ja 
schonmal beachtet und deshalb sz von jeglicher Funktion befreit, 
abgesehen von deklaration und initialisierung. Es passiert jetzt 
unabhängig von der Schleife. Ist auch keine 'for' Schleife mehr und 
mittlerweile sogar eine Endlosschleife zum Test. Es geht nix.

Oh wei, ich scrolle gerade im Fenster mit den Build Textausgaben.
Da Steht:

AVR Memory Usage
----------------
Device: atmega128

Program:   18400 bytes (14.0% Full)
(.text + .data + .bootloader)

Data:      17628 bytes (430.4% Full)
(.data + .bss + .noinit)

EEPROM:      510 bytes (12.5% Full)
(.eeprom)


Build succeeded with 0 Warnings...

430% im Data Speicher ist wohl etwas viel, sehe ich das richtig??

Christian

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Data:      17628 bytes (430.4% Full)

Und da wunderst du dich noch?

Autor: Christoph __ (chris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uebrigens, while(1<l) ist eine eher ungluecklich gewaehlte 
Abbruchbedingung. Ich musste drei Mal hinschauen um zu sehen, dass da 1 
< length steht (1 als Zahl).

Variablennamen darfst du ruhig aussagekraeftig machen, denn die Namen 
tauchen im kompilierten Programm sowieso nicht mehr auf und belegen 
daher keinen Speicher. Variablen wie dbwp0, dbuf0, sz und eben l 
(kleines L) sind nicht aussagekraeftig genug.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Rothe wrote:

> 430% im Data Speicher ist wohl etwas viel, sehe ich das richtig??

Wenn du da keinen externen Speicher dran hast, schon.

Autor: Christian Rothe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Christoph,

nein, wie gesaget wunderts mich seit ich das gesehen habe nicht mehr. 
Ich habe dieses Output-Fenster so klein, dass ich nur immer 'Build 
succeeded with 0 Warnings...' gesehen habe. Das fand ich soweit gut, was 
offensichtlich aber nicht ausreichend Information war.

Zum Code muss ich sagen, die Schleife mit dem kleinen 'l' sah natürlich 
ursprünglich anders aus. Während der Fehlersuche hab ich Stück für Stück 
an Code reduziert. Hier ist ja garkeine sinnvolle Funktion mehr drinnen. 
Zur Schreibweise muss ich von mir sagen, ich stehe hal auf kurzen Code. 
Wenn es der eigene ist finde ich das übersichtlicher. Das sieht bei mir 
z.B. so aus:

/////////////////////////////////////////////////////////////
//  WriteFifo
/////////////////////////////////////////////////////////////
int WriteFifo0(char c)
  {
  if (FFLG & FF0)
    return 0;  //fifo is full

  *wp0 = (char*)c;
  wp0++;

  if (wp0==(fifo0+FSIZE))  //reset wp at fifo end
    {
    wp0=fifo0;
    FFLG |= CA0;  //set CARRY0 flag
    }
  FFLG |= DATAV0;    //set Data available flag
  if((wp0 == rp0)&&(FFLG & CA0))
    FFLG |= FF0;  //set fifo full flag
  return 1;
  }

Ich brauche immer viel Code-Inhalt auf einen Blick, weshalb mich die 
ganzen Entwicklungsumgebungen mit zwölf gleichzeitigen Fenstern nerven. 
Mit einem 24" Bildschirm wärs vielleicht auch für mich toll, hab aber 
halt keinen.

So, nun also danke an Alle für die Mühe. Jetzt muss ich den Controller 
erstmal mit RAM erweitern

frohes Schaffen
Christian Rothe

www.rabenkopf-studio.de

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.