Hallo,
ich habe ein Programm geschrieben in welchem eine lineare Liste zur
Verwaltung von Peripherie eingesetzt wird.
Die lineare Liste besteht aus Strukturen. Jede Struktur enthält einen
Taster, eine Led und einen digitalen Schaltausgang, einen Verweis auf
die Toggel-Funktion sowie einen Verweis auf das nächste Element.
struct _control *st_next; /* Verweis auf nächstes Bedienelement */
8
}
9
/* Typdefinition des Bedienelements */
10
typedef struct _control control;
Um die Bedienelemente zu initialisieren gibt es eine Funktion
1
/* Neues Bedienelement anlegen */
2
volatile control *newControl(volatile control *st_control_list, unsigned char uc_pin_trigger, unsigned char uc_pin_led, unsigned char uc_pin_output) {
3
4
volatile control *st_ptr = malloc(sizeof(control));
5
...
6
return st_ptr;
7
}
Genau hier ist das Problem. Wenn ich mittels JTAG (Optimierung ist -O0
und Debugging ist -gdwarf2) nun Schrittweise durch das Programm gehe,
fängt der Controller nach Aufruf von malloc() an wild umher zu springen.
Letztendlich scheint er irgendwann zu resteten und schon beginnt der
Spaß von vorne ...
Was mach ich falsch? (Abgesehen von der Verwendung von malloc in einem
Mikrocontrollerprogramm ;-) )
Benjamin K. schrieb:
> Genau hier ist das Problem. Wenn ich mittels JTAG (Optimierung ist -O0> und Debugging ist -gdwarf2) nun Schrittweise durch das Programm gehe,
Falls Du AVR-GDB verwendest:
Wenn ich mich richtig erinnere, versteht der AVR-GDB das Format -gdwarf2
nicht richtig. du solltest "stubs" benutzen. Weiß gerade nicht, wie die
Option genau heißt.
Falls Du AVRStudio verwendest:
Das AVRStudio versteht das -gdwarf2 schon.
Wenn du einen Singlestep bei malloc machst, dann wird er normalerweise
auch in die Funktion malloc springen um diese zu debuggen. Das sollte
eigentlich gehen nur ohne Sourcecodeanzeige.
Edit: Ah Jörg, versteht der AVR-GDB das -gdwarf2 inzwischen? Dann ist
das oben natürlich infällig.
900ss D. schrieb:
> Wenn ich mich richtig erinnere, versteht der AVR-GDB das Format -gdwarf2> nicht richtig. du solltest "stubs" benutzen. Weiß gerade nicht, wie die> Option genau heißt.
-gstabs, sollte unter Unix/Linux der Default für -g sein.
> Edit: Ah Jörg, versteht der AVR-GDB das -gdwarf2 inzwischen?
Nicht richtig. Ich war erstmal von AVR Studio als Debugger ausgegangen
(stand ja nichts dabei).
@Jörg: Stack-überlauf bzw. eher HEAP-Überlauf halte ich für
unwahrscheinlich, da ich ja schon beim ersten benutzen von malloc das
Problem habe.
@900ss: Ich benutze AVRStudio
Benjamin K. schrieb:
> @Jörg: Stack-überlauf bzw. eher HEAP-Überlauf halte ich für> unwahrscheinlich, da ich ja schon beim ersten benutzen von malloc das> Problem habe.
Kann auch da schon passieren. Wie voll ist denn dein RAM?
beim kompilieren zeigt AVR studio an wieviel flash und RAM belegt werden
also statische angaben
wenn dort 90% stehen ist jede dynamische erweiterung ziemlich schnell am
ende ^^
deswegen verwende ICH bei µC kein malloc sondern statische variablen
in funktionen immer den überblick behalten was grade an ram verbraten
wird
Benjamin K. schrieb:
> Bei "Program" werden 3.2% angezeigt und bei Data 12 Bytes
Das ist ja nicht besonders groß :-)
Zeig doch mal.
Auch wenn ich davon ausgehe, dass du bei so etwas simplen keinen Fehler
eingebaut hast: Wir müssen systematisch vorgehen und eine Fehlerquelle
nach der anderen eliminieren. Ansonsten werden wir das Stadium "Stochern
im Nebel" nie verlassen.
Im Anhang der erstellte Quellcode.
Ich habe diese Art der Programmierung schon häufiger angewendet,
allerdings waren die Systeme leistungsfähiger als ein Mikrocontroller.
Ich würde dieses Konzept gerne beibehalten.
Hat nichts mit Deinem ursprünglichen Problem zu tun, aber:
1
/* Datenrichtung fuer Port A setzen 1=Ausgang (LEDs), 0=Eingang (Taster) */
2
DDRA=(PA3|PA2|PA1|PA0);
tut nicht, was Du möchtest. PA0..3 sind Bitnummern, nicht
Bitwertigkeiten.
Das da oben ist also 0|1|2|3 (reichlich sinnlos, weil 3) und nicht
1|2|4|8 (0x0f).
Die Bitwertigkeit von z.B. PA3 wäre 1<<PA3.
Noch eine Anmerkung: malloc auf "richtigen" Rechnern ist das Mittel der
Wahl, wenn es um die Verwaltung von Daten geht, die nicht von Natur aus
begrenzt sind. Arrays fester Länge für potentiell unbegrenzte Daten
wäre bäh und gelinkte Listen lassen sich schön verlängern, umsortieren,
an beliebiger Stelle verkleinern usw.
Man hat kein "hartes" Limit - ist der dem Prozess allozierte Speicher
voll, wird neuer angefordert, und reicht der nicht aus, geht's ins
virtuelle (Swap) und das Programm wird nur langsamer.
Beim Mikrocontroller hast Du dagegen von vornherein ein hartes Limit mit
knappem SRAM. Dazu kommt, dass malloc() Dir wohl den Speicher
verweigert, wenn sicher nichts mehr da ist, aber ein Gelingen eines
malloc() nicht garantiert, dass Du den sicher für immer und ewig
benutzen kannst. Der Stack kann runterlaufen und Dir in die Liste
reinschreiben oder, schlimmer noch, Du in den Stack, womit es dann Sense
mit dem Programmablauf wäre.
Du musst also ohnehin austarieren, wieviel Elemente maximal reinpassen,
bevor Unbill passiert und dies als harte Grenze festlegen. "Der Swap
wird's schon richten" ist nicht.
Es liegt nahe, dann gleich ein Array festgelegter Größe zu nehmen. Du
gehst so sparsamer mit dem ohnehin immer knappen Ram um (malloc belegt
Verwaltungsinformationen, die Links für die Listen entfallen, der
Programmoverhead der Speicherverwaltung ebenfalls).
Ob Du ein Indexarray sortierst oder eine verlinkte Liste, ist gerade
egal. Und meist geht's sogar ganz ohne Indexarray ab, denn bei den zur
Verfügung stehenden Ram-Größen kann man (wenn Zeit nicht kritisch ist)
auch alle Operationen inklusive Einfügen und Entfernen auf dem Array
direkt machen.
Überleg's Dir also genau, ob Du Dich in den malloc() verbeißen möchtest.
Mikrocontroller sind nunmal keine ausgewachsenen Computer und wollen
anders programmiert sein. Wozu auch gegen die Hardware anarbeiten,
wenn's einfacher geht?
@hazeh: Mir sind die Auswirkungen von malloc durchaus bekannt, trotzdem
danke das du das nochmal so ausführlich erläutert hast.
Weiterhin hast du natürlich mit den Datenrichtungszuweisungen recht, hab
ich wohl im Eifer des Gefechts übersehen.
Der Programmcode wie ich ihn geschrieben habe ist mit Sicherheit auch
langsamer im Vergleich zu den üblichen Vorgehensweisen. Mir ging es
eigentlich auch eher um "Komfort" als Geschwindigkeit.
Mein Problem hat sich heute auch lösen lassen. Wie man unter dem Link
http://www.mikrocontroller.net/articles/AVR_Checkliste lesen kann,
werden ATMega64 und ATMega128 mit programmierter CompMode-Fuse
ausgeliefert. Diese Kompatibelität führt zum Absturz des
Mikrocontrollerprogramms beim ersten Auftreten einer
RET-Assembler-Anweisung.
Nun stürzt der Controller nicht mehr ab und ich kann richtig debuggen,
danke für eure Hilfe.