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