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
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
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''.
>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.
> 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.
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.
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
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.
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
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.
Christian Rothe wrote:
> 430% im Data Speicher ist wohl etwas viel, sehe ich das richtig??
Wenn du da keinen externen Speicher dran hast, schon.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.