Hallo,
bin schon länger am forschen, warum mein Programm so komische Dinge
macht... Arbeite mit AVR-Studio für den Atmega8. Jetzt bin ich
inzwischen dahinter gekommen, dass es vermutlich an einem Stackoverflow
liegt. Ich habe einige Variablen in meinem Programm und zwei ISR in
denen jeweils auch nochmal einige Variablen drin liegen.
AVR-Studio zeigt mir an, dass der Datenspeicher (SRAM) zu 80% belegt
ist, also 800 Byte von 1K sind belegt.
Wie kann man etwa herausfinden, wieviel der Stack zu Laufzeit benötigt?
Oder ist die Größe für den Stack in der Angabe schon eingerechnet?
Bin um Ratschläge dankbar!
Johnny
Das ist einiges an Code, das wäre denk ich zu unübersichtlich...
Mir gehts eigentlich eher um das Prinzip... wie man z.B. einen
Stackoverflow vermeidet.
Programmierst Du in ASM? Wenn ja, schau mal nach folgenden allseits
beliebten Fehlerquellen:
1. Stack vergessen zu initialisieren
2. Vergessen das SFR zu beginn einer ISR zu sichern bzw. es am ende
zurückzuschreiben
Johnny66 schrieb:> wie man z.B. einen> Stackoverflow vermeidet.
genügend Ram haben.
Mal im Ernst, ohne Code kann man dir hier alle möglichen Fehlerursachen
beschreiben, das artet dann echt in Arbeit aus, die zu 99% sinnlos ist,
da sie dich nicht betreffen/du den Fehler nicht gemacht hast.
Also gibts bessere Antworten, wenn du deinen Code mal als Anhang
mitschickst.
Danke erstmal... Das mit dem StackViewer ist eine Idee, habe ich aber
noch nicht gemacht... Ich Programmiere übrigens in C (@Chris).
Habe nochmal etwas im Forum recherchiert... es ist ja auch sinnvoll z.B.
eine häufig benuzte globale Variable in einem Register abzulegen oder?
Ist das auch bei lokalen Variablen sinnvoll? Welche Register kann man
dafür nehmen?
Ich habe auch gelesen, dass man mehrere gloable Variablen in einer
Struktur zusammenfassen sollte zwecks Addressierung, aber das bringt mir
doch keinen freien Speicher im RAM oder wird der Stack dann kleiner?
Habe ein paar globale char Arrays die ich in der main beschreibe und in
der ISR auf dem LCD ausgebe...
Hat jemand noch eine Idee...?
Situation:
1. Quelltext liegt nicht vor.
2. Ergebnis von StackViewer liegt nicht vor.
3. Grund für Annahme das Stack overflow stattfindet, unbekannt.
4. Stack overflow unbestätigt.
Schlussfolgerung:
1. Bis zum vorliegen weiterer Informationen kein Vorschlag sinnvoll.
Johnny66 schrieb:> Hat jemand noch eine Idee...?
Vergiß alles, was du mal irgendwo gelesen, aber nicht verstanden hast.
Es gibt keine "Kochrezepte". Entweder analysierst du das Problem
ernsthaft, oder du kaufst dir einen pinkompatiblen Mega mit mehr Ram.
So, wie du das Problem darstellst, führt die zweite Lösung für dich
schneller zum Ziel.
Oliver
Hi
Hmm, war mein sonntäglicher Leckerbissen...
>bin schon länger am forschen, warum mein Programm so komische Dinge>macht... Arbeite mit AVR-Studio für den Atmega8. Jetzt bin ich>inzwischen dahinter gekommen, dass es vermutlich an einem Stackoverflow>liegt. Ich habe einige Variablen in meinem Programm und zwei ISR in>denen jeweils auch nochmal einige Variablen drin liegen.
Das ist doch ne tolle Basis zur Fehleranalyse.....
Irgend ein Fehler
vom Programm ist nicht einmal der Nutzen bekannt, außer das 80% SRam für
irgendwelche Variablen benutzt werden...
Ach ja, Programmiersprache C, da kann das Programm ja eigentlich nur
ganz wenig Aufgaben erledigen.... müßte doch bestimmbar sein
Oh, fast übersehen Atmega 8 und Studio, was kann man 23 IO schon
abverlangen... eine LED an und wieder aus.. seht ihr, so einfach läßt
sich die Analyse angehen.
Stackoverflow ..... whow... das ist ja einfach.. die ISR wird durch ISR
aufgerufen... das soll es geben... und pling, schon ist der Stack im
Variablenbereich. Wenn dann noch Variablen, die oben liegen, innerhalb
der ISR beschrieben werden , Bingo, ist die Rücksprungadresse im
Nirwana...
Oh, zwei ISR, jetzt wirds aber interessant......
leider, und das mein ich aufrichtig, bin ich nicht gut genug, daraus
auch nur irgendwelche Informationen zur Fehlerbeseitigung abzuleiten.
Hat mich aber gefreut, diesen Beitrag lesen zu dürfen....
Gruß oldmax
Mit einer kleinen Routine lässt sich der RAM-Verbrauch nach unten
abschätzen, siehe
http://www.rn-wissen.de/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc
Die Routine selbst nimmt nicht viel Resourcen, allerdings braucht man
auch einen Weg, um an die Auswertung zu gelangen (Display, UART, ...)
Tut mir leid ihr habt recht, ohne Code kommen wir nicht weiter ;-)
Habe mal die relevanten Dateien angehängt... wäre toll es könnte mal
jemand anschauen!
In der Datei fat16.c wird auf die Variable "unsigned char
FileBuffer[512]" zugegriffen. Glaube die klaut mir viel RAM... aber man
muss ja Blockweise auf die SD-Karte schreiben mit 512 Byte.
@Johann L.: Danke auch für diesen Tip!
Gruß Johnny
>Tut mir leid ihr habt recht, ohne Code kommen wir nicht weiter ;-)
Vollständiger Code wäre besser gewesen. So kann man nur
Annahmen treffen:
Ausgabe mit lcd_write() in main und in der ISR geht gar nicht.
Entweder, oder. Aber nicht beides. Ich kenne deine lcd_write()
nicht, aber es könnte sein das die Strings alle im RAM liegen.
Wenn es ein lcd_write_P() gibt, dann nimm das für konstante Strings
oder bau dir eins. Ein paar strcpy, strncpy könnte man zu
strcpy_P und strncpy_P ändern.
Da scheint es noch einige Unklarheiten zu geben, was Stringverarbeitung
angeht
1
strncpy(breitengrad,"Warte...",8);
Dre String "Warte..." hat keine Länge von 8 Zeichen, sondern es sind 9
Zeichen (du hast auf das abschliessende \0 vergessen). Ausserdem
solltest du dir angewöhnen, dass das letzte Argument von strncpy im
Regelfall nicht vom Quellstring abhängt, sondern immer (meistens) die
Größe des Zielarrays darstellt. Nur dann bringt dir strncpy irgendetwas,
sonst könntest du das nämlich auch einfach lassen und strcpy benutzen.
Dazu kommt, dass man diese Größenangabe nach Möglichkeit niemals selber
in Form einer Zahl ausdrückt, sondern das dem Compiler überlässt. Denn
der verzählt sich nicht und zweitens macht er die notwendige Anpassung
von alleine, wenn sich mal die Arraygröße verändert.
strncpy ist aber nur die halbe Miete, denn strncpy hat hier ein
Designproblem: Wenn der String gerade noch ohne das obligatorische \0 in
das Ziel passt, dann wird das obligatorische \0 Zeichen nicht
mitkopiert. Damit hat man aber im Zielarray dann einen ungültigen String
vorliegen.
Verhindern kann man das nur so
Wieder: verusch nicht selber die Zahlenwerte auszurechnen, sondern
versuche die Dinge mittels sizeof auszudrücken.
Auf die Art hast du viel weniger Fehler, die auf simples "Ich hab mich
verzählt" zurückzuführen sind.
Also:
* beim strncpy ist das 3. Argument normalerweise die Größe des
Zielarrays.
Mann kann strncpy auch zweckentfremden, so wie du das hier
gemacht hast
1
strncpy(breitengrad,&nmea_in[16],9);
und strncpy als Teilstring-Extraktor benutzt. Immer zwischen den
beiden Fällen streng unterscheiden!
* keine Zahlenwerte im Code, sondern nach Möglichkeit einen Weg finden
wie der Compiler den Zahlenwert selbst ermittelt.
* niemals auf das abschliessende \0 Zeichen in einem String vergessen.
Super, vielen Dank für diese Tips!
@Karl Heinz Buchegger: wird bei strcpy() das '\0' automatisch gesetzt?
@holger: Das könnte erklären, warum ich oft falsche Strings angezeigt
bekomme... Aber das mit lcd_write_P() und strncpy_P() hab ich irgendwie
nicht verstanden! Die LCD Funktionen sehen übrigens so aus:
Johnny66 schrieb:> Super, vielen Dank für diese Tips!>> @Karl Heinz Buchegger: wird bei strcpy() das '\0' automatisch gesetzt?
Ja wird es.
> @holger: Das könnte erklären, warum ich oft falsche Strings angezeigt> bekomme... Aber das mit lcd_write_P() und strncpy_P() hab ich irgendwie> nicht verstanden!
Es geht darum, dass Strings im Flash anders behandelt werden müssen als
Strings im SRAM.
Das AVR-GCC-Tutorial weiß mehr darüber
Danke... das Tutorial konnte mir sagen wie man Strings aus dem Flash
schreibt. Aber in dieser Funktion (lcd_string_P) werden ja dann die
chars mit "tmp = pgm_read_byte( data );" auch wieder in den RAM
geladen...
In meinem Code habe ich doch alles Strings im RAM oder? Und was bringt
es mir, wenn ich die Strings immer in den Flash kopiere und dann wieder
zurück in den RAM schreibe? Es leuchtet mir ein, dass die Strings im RAM
durch die ISR durcheinander geraten können... mir fehlt grad etwas der
Ansatz.
Wäre super, es würde nochmal jemand kurz was dazu sagen...
Johnny66 schrieb:> Danke... das Tutorial konnte mir sagen wie man Strings aus dem Flash> schreibt. Aber in dieser Funktion (lcd_string_P) werden ja dann die> chars mit "tmp = pgm_read_byte( data );" auch wieder in den RAM> geladen...
Ja. Aber immer nur einer.
UNd das macht dann einen Unterschied ob du mittels
"The quick brown fox jumps over the lazy dog"
44 (wenn ich mich nicht verzählt habe) Bytes im SRAM blockierst, oder
nur eines. Zumal die 44 Bytes sowieso auf jeden Fall immer im Flash sind
(denn wie kommen sie denn ins SRAM? Die sind ja nach dem Anlegen der
Stromversorgung nicht magisch im SRAM)
> In meinem Code habe ich doch alles Strings im RAM oder?
Ja
> Und was bringt> es mir, wenn ich die Strings immer in den Flash kopiere
Du kopierst sie nicht ins Flash. Die sind bei Programmstart schon im
Flash. So wie auch dein Programm im Flash ist.
> zurück in den RAM schreibe? Es leuchtet mir ein, dass die Strings im RAM> durch die ISR durcheinander geraten können...
An dieser Stelle geht es nicht um Strings im Flash oder Strings im RAM.
Überleg einfach mal, was wohl alles passiert, wenn der Interrupt genau
zu dem Zeitpunkt kommt, wenn eine andere Ausgabe auf das LCD im Gange
ist.
<An dieser Stelle geht es nicht um Strings im Flash oder Strings im RAM.
>Überleg einfach mal, was wohl alles passiert, wenn der Interrupt genau>zu dem Zeitpunkt kommt, wenn eine andere Ausgabe auf das LCD im Gange>ist.
Einfaches Beispiel:
Gurkensalat in der main
Paprikasalat in der ISR
Ausgabe GPuarpkreinksaaslatlaatt wenn du Glück hast;)
Oder stells dir so vor: Einer redet und der andere sabbelt
dazwischen. Im Endeffekt verstehst du kein Wort mehr.
Danke für die Erklärungen! Aber ich lese ja aus von einem GPS Modul
einen NMEA String aus. Dann kopiere ich aus diesem String einen Teil in
die Variable Breitengrad usw. d.h. im Flash ist kein String gespeichert
oder?
Das mit der ISR ist klar, wenn sie die Ausgabe unterbrincht. Könnte man
das auch mit cli() und sei() verhindern?
Wenn ich lcd_write("AUFNAHME...") schreibe befindet sich AUFNAHME... als
String im Flash oder wie ist das?