mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik C-Problem, Debugging, und wieder mal "static"


Autor: bbking (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Armin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: bbking (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ;-)

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: U.R. Schmitt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

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

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Thomas Burkhart (escamoteur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Thomas Burkhart (escamoteur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: mano (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/Speicherverbrauc...


Ausserdem kann der Fehler auch ganz wo anders liegen und ohne Code nur 
durch Glück erraten werden...

Autor: bbking (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...;)

Autor: Thomas Burkhart (escamoteur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: bbking (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

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

Bewertung
0 lesenswert
nicht lesenswert
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).

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier gabs mal ein Tool, was aus dem elf-File den maximalen Stack 
berechnet.

wennich zuhause bin kann ich den Link auhc nachreichen.

Autor: bbking (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.htm...
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/...

Autor: mano (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht durcheinander kommen mit Flash, SRAM und EEPROM!

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

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.