Forum: Mikrocontroller und Digitale Elektronik JTAG AVR Debugging und malloc


von Benjamin K. (exs)


Lesenswert?

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.
1
/* Definition der Struktur */
2
struct _control {
3
unsigned char uc_pin_trigger; /* Taster */
4
unsigned char uc_pin_led; /* LED */
5
unsigned char uc_pin_output; /* digitaler Ausgang */
6
void (*fcn)(volatile struct _control); /* Toggelfunktion */
7
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 ;-) )

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stack-Überlauf?  Vielleicht probierst du es ja mal mit dem
Einschalten der Optimierung?

von 900ss (900ss)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Benjamin K. (exs)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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?

von Benjamin K. (exs)


Lesenswert?

Wie kann ich den belegten RAM auslesen?

von gast (Gast)


Lesenswert?

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

von Benjamin K. (exs)


Lesenswert?

Bei "Program" werden 3.2% angezeigt und bei Data 12 Bytes

von Karl H. (kbuchegg)


Lesenswert?

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.

von Benjamin K. (exs)


Angehängte Dateien:

Lesenswert?

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.

von Hc Z. (mizch)


Lesenswert?

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.

von Hc Z. (mizch)


Lesenswert?

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?

von Benjamin K. (exs)


Lesenswert?

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

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.