mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik JTAG AVR Debugging und malloc


Autor: Benjamin K. (exs)
Datum:

Bewertung
0 lesenswert
nicht 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.
/* Definition der Struktur */
struct _control {
unsigned char uc_pin_trigger; /* Taster */
unsigned char uc_pin_led; /* LED */
unsigned char uc_pin_output; /* digitaler Ausgang */
void (*fcn)(volatile struct _control); /* Toggelfunktion */
struct _control *st_next; /* Verweis auf nächstes Bedienelement */
}
/* Typdefinition des Bedienelements */
typedef struct _control control;

Um die Bedienelemente zu initialisieren gibt es eine Funktion
/* Neues Bedienelement anlegen */
volatile control *newControl(volatile control *st_control_list, unsigned char uc_pin_trigger, unsigned char uc_pin_led, unsigned char uc_pin_output) {

volatile control *st_ptr = malloc(sizeof(control));
...  
return st_ptr;
}

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

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

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Benjamin K. (exs)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Benjamin K. (exs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie kann ich den belegten RAM auslesen?

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Benjamin K. (exs)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei "Program" werden 3.2% angezeigt und bei Data 12 Bytes

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benjamin K. (exs)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat nichts mit Deinem ursprünglichen Problem zu tun, aber:
/* Datenrichtung fuer Port A setzen 1=Ausgang (LEDs), 0=Eingang (Taster) */
  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.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Benjamin K. (exs)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.