Hallo Leute, ich stehe gerade vor einem ziemlich komplexen Problem: Meine Anwendung (ATmega16) soll einen Motor regeln, ein "Menü" über 6x 7segment Displays anzeigen und über uart kommunizieren. Mein Problem ist, dass ich mir teilweise meinen Programmablauf "zerschieße", weil offenbar irgendeine Variable oder Speicherbereich überschrieben wird. Debugge ich zB über uart, dann verhält sich der mc anders, als wenn ich das unterlasse - klar, könnte eine Timing-Sache sein. Ein Studienkollege hat vor kurzem gemeint, ich soll möglichst alle Variablen static deklarieren, damit sie einen festen Platz im Speicher haben und dieser Speicherbereich dann nicht dynamisch verändert werden kann (über das Thema habe ich schon [Beitrag "Globale Variablen brauchen mehr Speicher als lokale?"] einiges hier im Forum gelesen, wirklich weitergeholfen haben mir die Erklärenungen noch nicht). Das habe ich mit meinen globalen Variablen (leider gibt es einige davon!) und mit meinen lokalen Variablen aus den einzelnen Funktionen gemacht, jetzt treten andere Bugs auf. Wie gehe ich da am besten vor?? Für alle Tipps bin ich sehr dankbar, denn ich stehe schon ein wenig an....:/ Danke im Voraus!
>Wie gehe ich da am besten vor?
Weniger RAM verbrauchen. Zum Beispiel keine
meterlangen Debug Ausgaben, und wenn dann die Strings im Flash.
Ohne Code kann man dazu nicht mehr sagen.
static heißt auch, dass die Variable beim erneuten Starten der Funktion nicht zurückgesetzt wird (trotz initialisierung). Musste dann manuell machen. Vllt kommen die Bugs ja daher?
bbking schrieb: > Ein Studienkollege hat vor kurzem gemeint, ich soll möglichst alle > Variablen static deklarieren, damit sie einen festen Platz im Speicher > haben und dieser Speicherbereich dann nicht dynamisch verändert werden > kann (über das Thema habe ich schon das ist doch bullshit. Variablen, die nur lokal benötigt werden, gehören auf den Stack. Ausnahmen wären: wenn es keinen Stack gibt. wenn die Variablen so groß sind, dass sie nicht auf den Stack passen muss man sie halt auch mal statisch definieren. Das trifft aber nur für Prozessoren zu, die mehere Speicherbereiche haben. Wenn Stack und Ram im selben Speicher liegen (wie beim AVR), ist das natürlich sinnlos.
@Armin + Vlad Tepesch: Ihr hattet recht, eines der Bugs war eben wegen der static Deklaration der lokalen Variablen. Da hat eine Konvertierungsroutine jedes zweite Mal einen falschen Wert zurückgeliefert - ich frage mich nur, warum jedes Mal der erste Wert dann richtig war.... hm macht es einen Sinn, mit avr-gdb und SimulAVR zu arbeiten, v.a. wenn man auf Benutzerinteraktion wie Tastendrücke, etc. wartet? Habe mich mit dem Thema noch nicht beschäftigt, kann mir das aber nicht vorsellen... Danke
Dir würde ich mal ein C-Buch empfehlen. Das ist eine zuverlässigere Informationsquelle, als irgendwelche Studienkollegen, die es anscheinend auch nicht besser wissen ;-)
bbking schrieb: > macht es einen Sinn, mit avr-gdb und SimulAVR zu arbeiten, v.a. wenn man > auf Benutzerinteraktion wie Tastendrücke, etc. wartet? Nicht wirklich. Für so etwas ist VMLAB zu empfehlen. Ist zwar nicht ganz fehlerfrei, aber dafür reicht es allemal. Oliver
Modulares testen. Du testet einzelne Funktionen und zwar gündlich. Das bedeutet, Du machst Tests mit den Grenzwerten, also den max. und minimalen Werten in den Variablen. Du benutzt diese Funktionen mehrfach (Initialisierungsfehler) und Du schaust Dir an was passiert wenn Du eigentlich verbotene Werte/Kombinationen benutzt. Wenn Du dann wasserdichte Funktionen hast dokumentierst Du sie sauber und packst Sie am besten in Bibliotheken damit sie nicht mal schnell verändert werden. Das erzieht dann auch gleich zum sauber modularen programmieren.
Die Hauptursache #1 für diese Symptome ... > Mein Problem ist, dass ich mir teilweise meinen Programmablauf > "zerschieße", weil offenbar irgendeine Variable oder Speicherbereich > überschrieben wird. ... ist immer noch ein Arrayzugriff 'Out of Bounds'. Also das beschreiben eines Arrays an einem Index, der nicht existiert. Insbesondere Stringverarbeitung ist da sehr fehleranfällig.
Die behauptung, dass man auf den Speicher einer Static Variablen nicht zugreigen kann halte ich gelinde gesagt für naiv. Static bedeutet, dass eine lokale variable beim erneuten Funktionsaufruf immer noch den alten Wert vom letzten Aufruf enthält. Falls Du arrays als lokale Variablen verwendest, könnte es ein stackproblem sein. Diese einfach mal als Globale Variablen deklarieren, dann landen sie nict auf dem Stack. Gruß Tom
Thomas Burkhart schrieb: > Die behauptung, dass man auf den Speicher einer Static Variablen nicht > zugreigen kann halte ich gelinde gesagt für naiv. Wo hat jemand denn sowas behauptet?
Thomas Burkhart schrieb: > Diese einfach mal als Globale Variablen deklarieren, > dann landen sie nict auf dem Stack. Größer wird das SRAM dadurch auch nicht. Ein AVR hat nur ein SRAM. In den legt avr-gcc von oben nach unten die lokalen und statischen Variablen, von unten nach oben wächst der Stack. Überschreibt der Stack die globalen Variablen, knallt es. Ob man dabei jetzt Speicherblöcke vom Stack in den globalen Breich verschiebt, ist egal, es knallt trotzdem. Oliver
Karl heinz Buchegger schrieb: > Die Hauptursache #1 für diese Symptome ... > >> Mein Problem ist, dass ich mir teilweise meinen Programmablauf >> "zerschieße", weil offenbar irgendeine Variable oder Speicherbereich >> überschrieben wird. > > ... ist immer noch ein Arrayzugriff 'Out of Bounds'. Also das > beschreiben eines Arrays an einem Index, der nicht existiert. > Insbesondere Stringverarbeitung ist da sehr fehleranfällig. oder das Ineineanderlaufen von Ram und Stack
Oliver schrieb: > Ob man dabei > jetzt Speicherblöcke vom Stack in den globalen Breich verschiebt, ist > egal, es knallt trotzdem. Ok, war mir grad nicht geläufig, dass der Stack bim AVR nach oben läuft. Üblich ist dass er nach unten geht und dann kann man sich wunderbar innerhalb einer funktion parameter oder lokale variablen der nächsthöheren Funktion kaputtmachen, was bei globalen nicht so leicht passiert. Gruß Tom
Thomas Burkhart schrieb: > Ok, war mir grad nicht geläufig, dass der Stack bim AVR nach oben läuft. Wie das mit dem Stack funktioniert steht hier (er wächst vom Oben nach Unten): AVR-Tutorial: Stack Es kann durchaus sein, dass Du ein Problem mit dem Speicher hast, also schau hat mal bis zu welcher Adresse der Stack anwächst. Siehe dazu diesen Artikel: http://www.rn-wissen.de/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc Ausserdem kann der Fehler auch ganz wo anders liegen und ohne Code nur durch Glück erraten werden...
U.R. Schmitt schrieb: > Modulares testen. > Du testet einzelne Funktionen und zwar gündlich. > Das bedeutet, Du machst Tests mit den Grenzwerten, also den max. und > minimalen Werten in den Variablen. Du benutzt diese Funktionen mehrfach > (Initialisierungsfehler) und Du schaust Dir an was passiert wenn Du > eigentlich verbotene Werte/Kombinationen benutzt. > Wenn Du dann wasserdichte Funktionen hast dokumentierst Du sie sauber > und packst Sie am besten in Bibliotheken damit sie nicht mal schnell > verändert werden. > Das erzieht dann auch gleich zum sauber modularen programmieren. Das mache ich schon zum Teil. Ich bin dann komisch angesehen worden, warum ich für zB die Initialisierung meiner Timer Funktionen geschrieben habe...;)
Hast Du mal das Stackthema angeschaut, Kann auch einfach sein, dass Du einen Stacküberlauf bekommst wenn Du zuviele verschachtele Funktionsn oder eine davon rekursiv aufrufst Kannst Du nicht mal etwas code posten? Tom
mano schrieb: > Wie das mit dem Stack funktioniert steht hier (er wächst vom Oben nach > Unten): AVR-Tutorial: Stack > > > Es kann durchaus sein, dass Du ein Problem mit dem Speicher hast, also > schau hat mal bis zu welcher Adresse der Stack anwächst. Siehe dazu > diesen Artikel: > > http://www.rn-wissen.de/index.php/Speicherverbrauc... Thx, diese werde ich mir reinziehen, da ich noch als Zusatzaufgabe eine Analyse des dynamischen und des fix vergebenen Speichers erstellen soll. > Ausserdem kann der Fehler auch ganz wo anders liegen und ohne Code nur > durch Glück erraten werden... Den Code wollte ich Euch nicht antun, hat mittlerweile so um die 2000 Zeilen oder mehr... Wo es noch bestimmt fehler gibt und da habe ich noch keine Praxiserfahrung: wenn zwei verschiedene ISR (zB ein Timer-Overflow und UART-Empfang) die gleichen Daten manipulieren, komme ich ein wenig durcheinander. z.B. schicke ich über UART irgendwelche Kommandos, die in einem Array vom Typ eines selbstdefinierten Structs abgelegt werden. Mein Timer führt die Anweisungen aus und zählt einen Zähler von 0 bis zum zuletzt eingetranen Wert (max. 32) hoch. Das funktioniert derzeit, aber mich würde interessieren, wie man solche Aufgaben grundsätzlich löst. Vielen Dank für die bisherigen Antworten!
>Das habe ich mit meinen globalen Variablen (leider gibt es einige >davon!) und mit meinen lokalen Variablen aus den einzelnen Funktionen >gemacht, jetzt treten andere Bugs auf. Wie gehe ich da am besten vor?? diese globale Variablen sind in anderen Objektdateien zugreifbar. Das sollen sie eventuell auch sein (von der Logik her!) Machst du sie statisch, sollte der Linker Fehler melden.
Oliver schrieb: > Überschreibt der Stack die globalen Variablen, knallt es. Ob man dabei > jetzt Speicherblöcke vom Stack in den globalen Breich verschiebt, ist > egal, es knallt trotzdem. Natürlich knallt es trotzdem. Das ist ja auch gar nicht der springende Punkt. Der springende Punkt ist, dass einem die Speicherstatistik, die nach dem Build im AVR-Studio ausgegeben wird, einen Hinweis darauf gibt, wie weit man 'über den Daumen gepeilt' noch von diesem Punkt entfernt ist. Ja mehr globale und static Variablen man hat, desto aussagekräftiger wird diese Ausgabe. Von daher kann es schon Sinn machen, auch wenn mir das jetzt ein Zähneknirschen abverlangt, Variablen global zu machen. Selbst dann wenn es scheinbar allem widerspricht, was ich in all den Jahren als gutes Softwaredesign abseits der µC-Szene gelernt habe (daher das Zähneknirschen).
hier gabs mal ein Tool, was aus dem elf-File den maximalen Stack berechnet. wennich zuhause bin kann ich den Link auhc nachreichen.
Vlad Tepesch schrieb: > hier gabs mal ein Tool, was aus dem elf-File den maximalen Stack > berechnet. > > wennich zuhause bin kann ich den Link auhc nachreichen. Meinst Du ev. das hier? http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_ramoverlap Die letzten paar Zeilen der Ausgabe sind: 00800366 B __bss_end 00800366 ? _end 00800366 ? __heap_start 00810000 ? __eeprom_end Demnach hätte ich noch 9634 bytes zur Verfügung? Geht sich irgendwie mit der Spez von ATmega16 nicht aus (512 Bytes EEPROM...)? Uns wurde von der Übungsleitung dieses Tool zur Verfügung gestellt, bin ich noch nicht zum Ausprobieren gekommen. Vielleicht ist das für Euch auch von Nutzen: http://ti.tuwien.ac.at/rts/teaching/courses/eselu/downloads/example-programs/examplememeval-tar.gz/view
Nicht durcheinander kommen mit Flash, SRAM und EEPROM!
ne, ich meinte das hier: Beitrag "StackViewer (RAM Rechner) für WinAVR" das berechnet den maximale benutzten Stack. ob und wie gut das mit Rekursion oder Interupts klar kommt weiß ich nicht. ISRs sollte ja nicht so stackintensiv sein. so dass man selbst im Kopf noch die paar Bytes der dicksten ISR drauf packen kann.
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.