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


von Johnny66 (Gast)


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

von Floh (Gast)


Lesenswert?

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

von Johnny66 (Gast)


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.

von Chris (Gast)


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

von Floh (Gast)


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.

von Vlad T. (vlad_tepesch)


Lesenswert?


von Johnny66 (Gast)


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

von Glaskugel (Gast)


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.

von Purzel H. (hacky)


Lesenswert?

Plus. In C hat man eigentlich nichts mit dem Stack zu tun.

von Oliver (Gast)


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

von Vlad T. (vlad_tepesch)


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.

von oldmax (Gast)


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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von Johnny66 (Gast)


Angehängte Dateien:

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

von holger (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

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.
1
  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
1
  strncpy(breitengrad, "Warte...", sizeof(breitengrad));
2
  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
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.

von Johnny66 (Gast)


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:
1
//--------------------------------------------------------
2
//lcd_out_data()
3
//--------------------------------------------------------
4
void lcd_out_data(char c){
5
  PORTD &= 0x02;      //PD1 = LED!
6
  PORTD |= (1<<PD3);    //RS = 1
7
  PORTD |= c & 0xF0;
8
  lcd_enable_short();
9
  PORTD |= (c << 4) & 0xF0;
10
  lcd_enable();
11
  _delay_us(20);
12
}
13
14
//--------------------------------------------------------
15
//lcd_write()
16
//--------------------------------------------------------
17
void lcd_write(const char *s){
18
  while (*s != 0) lcd_out_data(*s++);
19
}

von Karl H. (kbuchegg)


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

von Johnny66 (Gast)


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

von Karl H. (kbuchegg)


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.

von holger (Gast)


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.

von Johnny66 (Gast)


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?

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
Noch kein Account? Hier anmelden.