der mir ein Menü auf nem LCD ausgiebt. Die Navigation erfolgt mittels
Scrollrad und einem Taster. Alles funktionierte problemlos. Binde ich
nun aber die errorHandler() zusätzlich ein, bekomme ich ständig einen
Reset beim Eintritt in die Hauptschleife. Das ist unabhängig davon, ob
ich die Funktion wirklich aufrufe oder nicht!
Hat jemand ne Idee woran das liegen könnte?
Ich bin mit meinem Latein langsam am Ende.
Ich weiss jetzt nicht, was die ganzen lcd_* funktionen für einen
Stackverbrauch haben und was sonst noch in dem Programm läuft, tippe
aber mal drauf, dass der Stack ins DATAT/BSS Segment bzw. Heap
hineinwächst und Dir da etwas schrottet.
Da würde ich zuerst nachhaken. Watchdog-Reset ist aus?
> Binde ich nun aber die errorHandler() zusätzlich ein, bekomme> ich ständig einen Reset beim Eintritt in die Hauptschleife.> Das ist unabhängig davon, ob ich die Funktion wirklich aufrufe> oder nicht!
Speicher (SRAM) voll und daher Stack zerschossen?
@Peter Dannegger
der Mega16 hat 1kB SRAM... meinst Du nicht, dass das für die paar
Strings reichen sollte? Wobei die Lösung mit den Strings im Flash
sowieso die bessere Alternative wäre...
Arne schrieb:
> @Peter Dannegger>> der Mega16 hat 1kB SRAM... meinst Du nicht, dass das für die paar> Strings reichen sollte?
Schau dir an, was da sonst noch passiert.
Offenbar gibt es eine dynamische Allokierung der Menüstruktur. Und sooo
wenige Strings sind das gar nicht. Mit den ganzen Menütexten und
Fehlertexten kommt da schon einiges zusammen. Dazu dann noch die
Menüknoten im SRAM ... (wie gross die Textfelder in den Menüknoten sind,
wissen wir leider nicht)
> Wobei die Lösung mit den Strings im Flash> sowieso die bessere Alternative wäre...
Yep.
Und die Menüstruktur nicht dynamisch zusammenbauen. Das kann man auch
statisch machen (und bei der Gelegenheit ebenfalls nach und nach ins
Flash verbannen). Aber auf jeden Fall im ersten Schritt soviel wie
möglich statisch allokieren, damit der SRAM Verbrauch, den der Compiler
ausrechnet so nah wie möglich am SRAM Verbrauch zur Laufzeit liegt und
daher auch aussagekräftig wird. Je mehr man dynamisch allokiert, desto
weniger hilft einem die Speicher Summary, die der Compiler berechnet.
Frank Kalka schrieb:
> Kann gut sein, dass nicht nur die Strings das Problem sind, sonder auch> das Menükonstrukt.>>
1
>typedefstructmenu{
2
>structmenu*father;
3
>structmenu*subs[4];
4
>char*zeile[16];
5
>int(*func)(int);
6
>}MENU;
7
>
>> Hatte bis jetzt noch nie Probleme mit dem Speicherplatz. In das> Themengebiet muss ich mich erstmal noch einarbeiten.
Sowas kannst du auf einem PC mit praktisch unbegrenztem Speicher machen.
Aber in einem µC mit limitierten Resourcen ist das unklug. Ebenso die
dynamische Allokierung.
Jeder Menüknoten belegt 44 Bytes.
Ich hab mir deinen Menübaum nicht komplett aufgezeichnet. Aber der Teil
den ich aufgemalt habe, sind bereits 10 Knoten. Macht 440 Bytes. Und das
sind nur die Knoten, keine Texte! Du hast aber nur 1024 Bytes!
Das ist alles viel zu verschwenderisch gemacht.
Ja, das Menü hatte ich auch ursprünglich bei nem kleine Programm für PC
benutzt. Dachte ich könnte es mit einigen kleinen Modifikationen auch
auf dem Controller nutzen.
Dann werd ich mir mal die Speicherverwaltung genauer ansehen müssen und
das Ganze doch neu schreiben.
Danke für die schnelle Hilfe. Jetzt hab ich nen Ansatzpunkt.
Gruß
Frank
>der Mega16 hat 1kB SRAM...
wovon grob geschätzt 400 Byte für die Stringkonstanten verbraucht
werden, dazu landen die Strings der Menutext zweimal im SRAM, in Summe
also ca. 500 Byte. Das alleine bringt das SRAM noch nicht zum
überlaufen.
Allerdings sieht mit die Funktion newNode() sehr nach dynamischer
Speicherverwaltung aus. Je nachdem, wie die implementiert ist, und was
noch alles in menu.c passiert, wird es dann doch eng im SRAM.
Oliver
Ohhh ja.... bei dem struct komme ich auf 44Byte je Instanz!
Da hat Karl-Heinz Recht: da solltest (musst) Du umstricken.
Aber in die Falle sind wohl die meisten von uns am Anfang gelaufen ;)
Der Rest deiner Menüstruktur ist mir klar, aber wozu brauchst du zeile?
Von den 44 Bytes pro Knoten gehen immerhin 32 nur für diese 16 Pointer
drauf. Und so richtig ist mir nicht klar, worauf diese 16 Pointer zeigen
könnten. Dein Menü kann offenbar pro Knoten 4 Submenüs enthalten. Ich
würde mal erwarten, dass für jeden Menüpunkt 1 char Pointer für den
Menütext vorhanden ist. Aber nicht 16.
(Ok, du hast im LCD offenbar 4 Zeilen. 4*4 macht 16. Nur seh ich den
Zusammenhang immer noch nicht)
@Karl heinz Buchegger
Bei den Pointern für die Zeilen hast du natürlich recht. Das war ein
Denkfehler von mir. Das sollte ein Pointer auf einen 16 Zeichen String
sein, weil mein LCD 16 Zeichen pro Zeile hat. Is so natürlich falsch.
Frank Kalka schrieb:
> @Karl heinz Buchegger>> Bei den Pointern für die Zeilen hast du natürlich recht. Das war ein> Denkfehler von mir. Das sollte ein Pointer auf einen 16 Zeichen String> sein, weil mein LCD 16 Zeichen pro Zeile hat. Is so natürlich falsch.
Ui. Dann bin ich beim Aufzeichnen der Datenstruktur noch viel zu
optimistisch vorgegangen
D.h. dann, dass das hier
Frank Kalka schrieb:
> Hmm, was ich beabsichtigt habe war eigentlich mehr sowas:
Mag sein.
Aber das ist mit deiner jetzigen Struktur nicht machbar :-)
Tip:
Füg dir noch eine Struktur ein. Die speichert einen Menüpunkt, also die
Kombination aus Text(-pointer) und Pointer auf das Submenü, dann
passiert dir sowas nicht
1
typedefstructmenu;
2
3
typedefstructmenuEntry{
4
char*text;
5
structmenu*sub;
6
};
7
8
typedefstructmenu{
9
structmenu*father;
10
structmenuEntryentries[4];
11
int(*func)(int);
12
}MENU;
Wenn jetzt viele deiner Menüs nur wenige Menüpunkte enthalten, könnte
man auch überlegen, nicht per Default 4 Einträge pro Menü zu haben,
sondern diesen Teil dynamisch zu halten (wenns denn unbedingt dynamisch
bleiben soll)
1
typedefstructmenu;
2
3
typedefstructmenuEntry{
4
char*text;
5
structmenu*sub;
6
};
7
8
typedefstructmenu{
9
structmenu*father;
10
int(*func)(int);
11
unsignedcharnrEntries;
12
structmenuEntryentries[];
13
}MENU;
Die Allokierung wird dann ein wenig trickreicher. Aber bei einem Menü
mit nur 2 Einträgen spart das immerhin 7 Bytes ein. Und deine ganzen
'Blättermenüpunkte' im Baum haben alle nur wenige Menüpunke.
Auch könnte man darüber nachdenken, ob es unbedingt notwendig ist, einen
Pointer auf das Vatermenü in der Struktur zu halten. Die maximale
Verschachtelungstiefe der Menüs ist bekannt und durch die
Aufrufhierarchie der Menüs kann man auch in einem Stack ganz einfach
einen Pointer auf den jeweiligen Vater halten. Spart schon wieder 2
Bytes pro Menü zu Lasten von (wenn ich das richtig gesehen habe) bei dir
einem globalen Array von 4 Menüpointern und einem 'Stackpointer' der als
uint8_t ausgeführt sein kann.
-> zurück zu Papier und Bleistift und eine Menüstruktur aufmalen. Bei
jedem Feld fragen: Brauch ich das unbedingt
Aber auch fragen: Kann ich mit dieser Menüstruktur arbeiten.
ich hab mir für strings immer die LCD funktionen gleich als lcd_P()
gebastelt
aufruf dann lcd_P( PSTR("text") );
oder eben über arrays im flash bei sehr vielen menütexten und einen
zeiger drauf
aber auch hier brauch man fast nur lcd_P
ebenso UART_P wenn ich strings verschicken will ..
alles so weit es geht in flash werfen
So, ich hab jetzt alle Strings die ich so hatte in den Flash gepackt und
jetzt gehts.
Damit ist das Ganze von der Struktur her zwar immer noch suboptimal,
aber zumindest kann ich damit arbeiten und mich jetzt um den Rest des
Programms kümmern.
Bei passender Gelegenheit werd ich dann die Struktur nochmal genau
überdenken und versuchen den Speicherbedarf weiter zu optimieren.
Nochmal herzlichen danke für die schnelle Hilfe!
Gruß
Frank