JTAG AVR Debugging und malloc

OP #1452611
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 ;-) )
#1452634
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.
Moderator Persönliche Seite #1452753
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).
Gast #1453914
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
#1453962
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.
#1454020
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.
#1454076
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?
OP #1454800
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren