Forum: Compiler & IDEs Memory Map


von Ronny Schulz (Gast)


Lesenswert?

Mit der memory map habe ich immer wieder Probleme. Jetzt fängt es bei
meinem ATmega128 schon wieder an. So bald ich neue Dinge einbaue läuft
kaum noch was, obwohl das unabhängig von den vorhandenen Funktionen
ist. Ich nehme mal an, da wird wieder was im Speicher überschrieben.

Vielleicht könnte mir jemand helfen die Memory map zu verstehen, die
erzeugt wird. Hier aus dem map-file:

Memory Configuration

Name             Origin             Length             Attributes
text             0x00000000         0x00020000         xr
data             0x00800060         0x0000ffa0         rw !x
eeprom           0x00810000         0x00010000         rw !x
default        0x00000000         0xffffffff

und hier nach dem kompilieren beim Output:

Size after:
syscontrol.elf  :
section            size      addr
.data                80   8388864
.text              4782         0
.bss                 24   8388944
.noinit               0   8388968
.eeprom               0   8454144
.debug_aranges      220         0
.debug_pubnames    1209         0
.debug_info        4829         0
.debug_abbrev      1916         0
.debug_line        4608         0
.debug_str         1404         0
Total             19072

Der ".data" und ".bss" sollte doch das einzige Problem sein, denke
ich mal. Nur sind bis zu den 4K SRAM noch ne Menge Luft nach oben. Wo
könnte de Fehler liegen?`

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


Lesenswert?

Die Speicherauslastung sieht wirklich so aus, als solltest du da
selbst bei exorbitanter Stackbenutzung keine Probleme bekommen.

Entweder hast du irgendwo eine endlose Rekursion, oder aber irgendeine
Interruptroutine frisst alle Rechenzeit auf und ,,holt sich selbst
ein''.

von Ronny Schulz (Gast)


Lesenswert?

Danke! Also habe ich das oben auch mit den Daten so richtig verstanden.
Ich lege auch alle Strings im Flash ab und hole die dann mit den
entsprechenden Funktionen raus, um Hauptspeicher zu sparen.

Wobei noch 100 Bytes für meine fifo-Buffer (in/out) zur seriellen
Schnittstelle weggehen. Die werden mittels malloc() allokiert. Und
können natürlich vom Compiler nicht vorausgesagt werden.

Aber unterm Strich heißt das, ich muss nochmal genau schauen, wo der
Programmfehler liegt. Rechnenzeit it weniger das Problem. Das sind so
gravierende Fehler, wie im Terminal würd Datenmüll ausgegeben und
falsche Strings usw., da ich mir da ein Kommandozeileninterface
gebastelt habe. Das hängt aber eben direkt von der Programmgröße ab.
Kürze ich irgendwo völlig unabhängige Funktionen, dann läuft das.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

>Ich lege auch alle Strings im Flash ab und hole die dann[..]
>Aber unterm Strich heißt das, ich muss nochmal genau schauen, wo
>der Programmfehler liegt.

Vielleicht machst Du ja einen Fehler in der Verwendung der Program
Space Utilities. Poste Doch mal einen Ausschnitt aus Deinem Terminal,
in dem ganz sicher falsche Daten gesendet werden.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

wenn du die 100 Byte für den FIFO eh immer brauchst wprde ich die an
deiner Stelle nicht dynamisch per malloc() besorgen sondern statisch
mittels unsigned char fifo_in[100];

Dynamische Speicherverwaltung auf µC sollte man nur da einsetzen wo man
die Größe des benötigten Speichers zur Compilezeit nocht nicht kennt.

Matthias

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

>Dynamische Speicherverwaltung auf µC sollte man nur da einsetzen[..]

Ich würde das "auf µC" weglassen. Auf anderen Maschinen macht das
nämlich auch keinen Sinn :-)

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

ich hab das zuerst auch nicht drin gehabt aber wollte dann
irgendwelchen Diskussionen aus dem Weg gehen. Warscheinlich ists wurst
wie mans macht. Allen kann man es nicht recht machen.

Matthias

von Ronny Schulz (Gast)


Lesenswert?


von Ronny Schulz (Gast)


Lesenswert?

Die dynamische Speicherverwaltung hatte ich im übrigen eingesetzt, damit
man die fifo-Größe direkt als Parameter übergeben kann. Sollte ich das
unterbinden und das wirklich fix anlegen?

von Ronny Schulz (Gast)


Lesenswert?

Im übrigen noch ein Nachtrag. Ich bekomme ein paar GCC-Warnungen, die
vielleicht mit einspielen. Meiner Meinung nach aber keinen Sinn
machen:

Compiling: fan.c
avr-gcc -c -mmcu=atmega128 -I. -g -Os -funsigned-char
-funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=fan.lst  -std=gnu99 fan.c -o fan.o
fan.c: In function `fan_set':
fan.c:68: warning: comparison is always false due to limited range of
data type

Geht um die Zeile in "fan_set()": if (value < 0) value = 0;

Die Meldung ist Schwachfug, da value vom Typ char ist und somit auch <
als 0 sein darf.

Compiling: cli.c
avr-gcc -c -mmcu=atmega128 -I. -g -Os -funsigned-char
-funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=cli.lst  -std=gnu99 cli.c -o cli.o
cli.c: In function `cli_docmd':
cli.c:113: warning: 'ptr' might be used uninitialized in this
function

Geht um die Zeile in "cli_docmd()": char *ptr;

Ist auch Unsinn, da die Variable in der Funktion initialisiert wird.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

>avr-gcc -c -mmcu=atmega128 -I. -g -Os -funsigned-char [..]
>fan.c:68: warning: comparison is always false [..]
>Die Meldung ist Schwachfug, da value vom Typ char ist [..]

Fast richtig ;-)
Mit der Option '-funsigned-char' wird eine definition wie 'char
cChar;' so behandelt, als würde dort explizit 'unsigned char cChar;'
stehen. Also musst Du entweder diese Option aus dem Compileraufruf
'rausnehmen, oder explizit 'signed char cChar;' verwenden.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

BTW:
Ob char signed oder unsigend ist ist "implementation defined". Darf
also bei jedem C-Compiler unterschiedlich sein.

Matthias

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


Lesenswert?

> cli.c: In function `cli_docmd':
> cli.c:113: warning: 'ptr' might be used uninitialized in this
function

> Geht um die Zeile in "cli_docmd()": char *ptr;

> Ist auch Unsinn, da die Variable in der Funktion initialisiert wird.

Der Compiler erkennt nicht notwendig jeden möglichen
Verarbeitungszweig, in dem eine Initialsierung vorgenommen wird.  Wenn
es nur rein semantisch sichergestellt ist, dass die Variable vor der
Benutzung auch initialisiert ist, dann ist das natürlich trotzdem OK.
Aber man sollte die Warnung ernst nehmen und nochmal hingucken.  Ich
habe es schon oft genug erlebt, dass der Compiler doch Recht
hatte. ;-)

von Ronny Schulz (Gast)


Lesenswert?

@Matthias:
Naja wieder was dazugelernt. Dann nehme ich das "-funsigned-char"
einfach raus. Oder änderes das in "signed-char". Wenn ich was
unsigned haben will, definiere ich mir das selbst.

@Jörg:
Ja ich bin den Codeschnipsel schon mehrfach durchgegangen. Aber das
scheint so schon korrekt zu sein. Entweder lasse ich das so oder setze
*ptr einfach auf NULL.

von Malte _. (malte) Benutzerseite


Lesenswert?

>Dynamische Speicherverwaltung auf µC sollte man nur da einsetzen wo
man
>die Größe des benötigten Speichers zur Compilezeit nocht nicht kennt.
>Ich würde das "auf µC" weglassen. Auf anderen Maschinen macht das
>nämlich auch keinen Sinn :-)
Das interessiert mich jetzt aber mal. Ich habe in einem Programm
welches ich gerade schreibe ein Array mit einer Größe von 256 Byte.
Dieses Array wird bei mir nur von einem Unterprogramm+weiterer
Unteraufrufe verwendet, andere Unterprogramme sollen die 256 Byte auch
als RAM zu Verfügung stehen, was eine globale Variable ausschließt. Ich
habe mich dazu entschieden die 256 Byte mit malloc zu reservieren und
beim Verlassen des Unterprogramms wieder freizugeben. Nach dem was ihr
oben schreibt wäre ein lokales 256 Byte Array aber das "richtige"
gewesen. Die 256 Byte müssen nicht initialisiert sein (leerer FIFO).
Was wäre nun effizienter/sinnvoller ?

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

du könntest die 256 Byte beim Eintritt in die Funktion als lokale
Variable (also auf dem Stack) anlegen. An deine weiteren
Unterfunktionen übergibst du dann, wie bisher ja auch, einen Pointer
auf eben diese Variable. Beim verlassen der Unterfunktion wird diese
dann automatisch aufgeräumt.

Matthias

von Ronny Schulz (Gast)


Lesenswert?

Ich denke ich habe den Fehler eingegrenzt. Wenn auch ich das Problem
nach mehreren Stunden bisher nicht beheben konnte. Der Fehler liegt in
den FIFO-Puffern. Da liegt es mit Sicherheit daran, dass der
FIFO-Puffer per IRQ gefüllt wird, aber immer wieder so lange gelesen
wird, bis ein Byte da ist. Da wird es wohl Konflikte zwischen den
einzelnen Funktionen geben.

Das der da einen falschen Text anzeigt hat eine andere Ursache, die ich
allerdings noch nicht finden konnte. Den Starttext zeigt er ja richtig
an, also scheint zumindest der Zugriff auf mit pgmspace funktionieren.
Aber vielleicht liegt es ja auch da an den FIFO-Puffern. Die benötige
ich ja in beiden Richtungen.

von Thomas S. (tstuetz)


Lesenswert?

überprüf mal deine fifo.c, wenn während du ein Zeichen versuchst
auszulesen ein Zeichen ankommt kann es crashen.

Bedenke bitte das Zeiger mindestens 2 Byte lang sind und dadurch bei
einem 8 Bit-Bus ZWEI Zugriffe gemacht werden müßen. Wenn jetzt zwischen
dem Lesen des ersten Bytes und dem Lesen des 2.Bytes  dieser Zeiger
geändert wird...

Außerdem darfst du eigentlich ja nie (bufread - buffer) > bufsize sein
!! anscheinen passiert das aber doch (Siehe Source)

Gruss

von A.K. (Gast)


Lesenswert?

Mit 16bit Pointern geht das natürlich nicht, jedenfalls nicht ohne um
die Pointerzugriffe herum die Interrupts abzuschalten.

Was jedoch geht: Pointer durch Index ersetzen. Ok bis effektiver
Puffergrösse von 255 Bytes, meist reicht das aber. 8bit incr/decr sind
i.d.R. atomar.

Epmfehlenswerte Vorlage: Der UART-Code von Peter Fleury. Kommt komplett
ohne Abschalten des Interrupts aus.

von Ronny Schulz (Gast)


Lesenswert?

@TStütz:
Genau das ist auch meine Vermutung. Nun will ich den Code nochmal
besser überarbeiten, dass der erstens nicht so murksig aussieht und
dann kann ich auch eine kleine Loop machen, indem ich da ein Busy-Bit
setze. Allzu lang muss ich da ja nicht warten.

Das mit dem "(bufread - buffer) > bufsize" kann durchaus sein. Wie
gesagt verwende ich einen Ringpuffer und wenn der zu Ende ist, muss ich
wieder von vorn anfangen und auf "buffer" zurücksetzen. Das Gleiche
passiert bei "bufwrite" genauso.

@A.K.:
Ja mit indexen habe ich auch überlegt zu arbeiten. Aber da müsste ich
mir direkt merken, wo ich im index stehe und wie viele Bytes im puffer
stehen. Das Prinzip ist eigentlich auch das gleiche.

Der Code von Peter Fleury .. wo kann man da mal schauen?

von Elektrikser (Gast)


Lesenswert?


von Ronny Schulz (Gast)


Lesenswert?

Hätte ich mir die ganze Arbeit ja sparen können und gleich das Teil von
Peter Fleury nehmen können. Naja nun ist egal und ich weiß, was ich
getan habe.

Ich habe meine Funktionen nochmals überarbeitet. Dennoch habe ich noch
nicht so recht Schimmer, wie ich das mit dem IRQs handeln soll. Ich
habe zwar inzwischen einen BUSY-Check drin, aber der ist Unsinn. Sobald
ein IRQ kommt bleibt das Ganze stehen.

Wie kann ich das in der vorhandenen Konstellation denn eigentlich am
Besten lösen, da ja die IRQs für eingehende als auch für ausgehende
Zeichen ausgelöst werden.

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.