www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ISR und Stackgröße


Autor: Johnny66 (Gast)
Datum:

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

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Bin um Ratschläge dankbar!
Zeig mal deinen Code her. :-)

Autor: Johnny66 (Gast)
Datum:

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

Autor: Chris (Gast)
Datum:

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

Autor: Floh (Gast)
Datum:

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

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Johnny66 (Gast)
Datum:

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

Autor: Glaskugel (Gast)
Datum:

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

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Plus. In C hat man eigentlich nichts mit dem Stack zu tun.

Autor: Oliver (Gast)
Datum:

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

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doppel Oschi schrieb:
> Plus. In C hat man eigentlich nichts mit dem Stack zu tun.

stimmt, man sieht ihn in der REgel erst wenn er kaputt geht.

Autor: oldmax (Gast)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit einer kleinen Routine lässt sich der RAM-Verbrauch nach unten 
abschätzen, siehe

http://www.rn-wissen.de/index.php/Speicherverbrauc...

Die Routine selbst nimmt nicht viel Resourcen, allerdings braucht man 
auch einen Weg, um an die Auswertung zu gelangen (Display, UART, ...)

Autor: Johnny66 (Gast)
Datum:
Angehängte Dateien:

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

Autor: holger (Gast)
Datum:

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

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

Bewertung
0 lesenswert
nicht lesenswert
Da scheint es noch einige Unklarheiten zu geben, was Stringverarbeitung 
angeht
  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(breitengrad, "Warte...", sizeof(breitengrad));
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
  strncpy(breitengrad, "Warte...", sizeof(breitengrad));
  breitengrad[ sizeof(breitengrad)-1 ] = '\0';

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
      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.

Autor: Johnny66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
//--------------------------------------------------------
//lcd_out_data()
//--------------------------------------------------------
void lcd_out_data(char c){
  PORTD &= 0x02;      //PD1 = LED!
  PORTD |= (1<<PD3);    //RS = 1
  PORTD |= c & 0xF0;
  lcd_enable_short();
  PORTD |= (c << 4) & 0xF0;
  lcd_enable();
  _delay_us(20);
}

//--------------------------------------------------------
//lcd_write()
//--------------------------------------------------------
void lcd_write(const char *s){
  while (*s != 0) lcd_out_data(*s++);
}

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

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

Autor: Johnny66 (Gast)
Datum:

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

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

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

Autor: holger (Gast)
Datum:

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

Autor: Johnny66 (Gast)
Datum:

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

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.