mikrocontroller.net

Forum: Compiler & IDEs Ist mein Ram bereits voll?


Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich nutze einen AT90CAN128. Mein Compiler zeigt mir mittlerweile an, 
dass mein Speicher ziemlich voll sein sollte (vermute ich zumindest).
.bss ist 3420 groß und .data hat bereits 5107. Das sollte meinen Ram von 
4k um gut das doppelte sprengen, oder?

Ich habe des weiteren gelesen, dass Strings in printf oder in structs 
besser ins Flash gelegt werden sollen. Wenn ich mich auf diese beiden 
Threads beziehen, dann wird das nicht ohne große Änderungen am Programm 
möglich sein:
Beitrag "struct mit strings im flash unterbringen"
Beitrag "Strings im Flash"

Gibt es da noch eine besser Möglichkeit meine String-Variablen ins Flash 
zu legen?
Bzw. sollte das dann mit einer externen Ram-Erweiterung funktionieren? 
Kann das der Compiler schon bei der Generierung berücksichtigen?

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt compiler, die das automatisch können, allerdings nur unter 
Verletzung des C-Standards (Pointer sind dann z.B. 3 Bytes lang, etc).

Der GCC hält sich lieber an den Standard, und überlässt das hantieren 
mit Flash und EEProm dem Programmierer.

Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK. Das ist ja schon mal eine Aussage.

Was genau sagt mir eigentlich .bss? Ich habe gelesen, dass dies die zur 
Laufzeit generierten Variablen darstellt. Sprich: Das ist nur ein 
Worst-Case Fall, oder? Ich werde ja nicht alle meine Variablen zur 
gleichen Zeit nutzen. Wenn ich diese in einer Funktion generiere, dann 
sind die beim Verlassen der Funktion ja wieder weg, oder?
Muß ich mich dann nur um .data kümmern, so dass dieser die 4k nicht 
überzeigt bzw noch Luft für die Daten von .bss lässt?!

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
.bss sind Variablen, die beim Programmstart mit Nullen überschrieben 
werden.
.data sind Variablen, die beim Programstart einen Startwert aus dem 
Flash bekommen.

Sind also beides nicht "Worst-Case" Abschätzungen, sondern der 
tatsächliche Bedarf.
Der Rest vom Ram geht für Stack (und Heap, wenn verwendet) drauf, HIER 
braucht man die Worst-Case Abschätzung, z.B. max. Rekursionstiefe.
Sonst kann dein Stack über die Variablen "wachsen" und diese 
überschreiben...

Autor: Norgan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Was genau sagt mir eigentlich .bss?

http://en.wikipedia.org/wiki/.bss

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wenn ich mich auf diese beiden
>Threads beziehen, dann wird das nicht ohne große Änderungen am Programm
>möglich sein

So groß ist der Aufwand für die Strings doch gar nicht. Überall ein PSTR 
mit den zugehörigen Klammern eingefügt, dazu per replace die 
entsprechenden Funktionen durch ihre _P-Version ersetzt. Ist halt mal 
eine Stunde Fleißarbeit.

Was ich nicht nachvollziehen kann, ist, wie man so viel Code schreiben 
kann, ohne schon viel früher über das Problem zu stolpern.

Oliver

Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ich nicht nachvollziehen kann, ist, wie man so viel Code schreiben
kann, ohne schon viel früher über das Problem zu stolpern.

Die Antwort ist einfach. Alle Teile des Gesamtcodes hab ich schon 
irgendwo mal genutzt/geschrieben. Jetzt brauche ich zufälligerweise alle 
diese Funktionen für ein neues Projekt, dessen Hardware noch nicht 
vorhanden ist. Um mir die Zeit tot zu schalgen mach ich was, was man 
eigentlich nicht sollte. Ich schreibe schon mal alles zusammen und mache 
einen BigBang Test mit der Hardware, wenn sie denn mal da ist. Was 
sicher nicht gut gehen wird :)

Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: Das ganze ist nur so groß geworden, weil ich unmengen von Structs 
benutze wobei die meisten noch zu Struckarrays werden. Hab mal bei ein 
paar nachgerechnet. Da wird ein "kleines" Array schon mal 1,5k groß.

Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
.bss sind Variablen, die beim Programmstart mit Nullen überschrieben
werden.

Was mich wundert ist, dass Befehle wie z.B.
unsigned char inbuff[Filelength()];
Fread(inbuff,Filelength());
funktionieren wobei Filelength() zur Compilerzeit noch nicht definitv 
fest steht. Wie wird das dann da gehandhabt?

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
inbuff liegt auf dem Stack ("Automatic" Variable), d.H. es wird erst 
beim Funktionsaufruf bzw betreten des Scopes angelegt.
Die Größe muss zur Compilezeit also nicht feststehen.

Autor: Sepp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich die Funktion verlasse wird aber der Speicher wieder frei 
gegeben, oder? Mit malloc() wirds dann wohl ähnlich sein.
Erscheinen solche Konstaten dann in .bss oder .data?

Tut mir leid wenn ich da ein bißchen nervend bin, aber mich 
interessierts eben :)

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle automatischen (=lokalen) Variablen, sowie alle per malloc 
reservierten Speicherbereiche werden auf dem stack bzw. heap zur 
Laufzeit reserviert und freigegeben. Die erscheinen nicht in .bss oder 
.data. Dort landen nur globale Variablen.

Oliver

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, Beispiel, dann wirds hoffentlich klar:
uint8_t globale_variable1;
uint8_t goblale_variable2=42;

void func() {
  static uint8_t statisch1;
  static uint8_t statisch2=23;
  uint8_t automatisch1;
  uint8_t automatisch2=17;

  void * dynamisch;

  dynamisch=malloc(10);
}

So, was macht der Compiler draus?
Statische variablen werden wie globale behandelt, in der .data-Section 
landen also zwei Bytes, goblale_variable2 und statisch2.
Die Variablen ohne initialwert landen in .bss, das sind auch zwei Bytes,
globale_variable1 und statisch2.

Auf dem Stack landen die automatic-Variablen in func, ABER NUR bei 
Funktionsaufruf. D.h. am Anfang von func fügt der Compiler Code ein, der 
auf dem Stack 2+sizeof(void *) Bytes reserviert, einfach durch 
Verschieben des Stack-Pointers.
Ausserdem wird hier Code generiert, um "automatisch2" zu initialisieren.

Beim Verlassen der Funktion wird der Stackpointer wieder zurückgesetzt, 
dieser Speicher also wieder freigegeben.

der malloc-Aufruf reserviert Speicher vom Heap (bei AVR-GCC liegt der 
üblicherweise zwischen den fix allozierten Speicherbereichen und dem 
Stack). Bei Funktionsende wird dieser Speicher NICHT wieder automatisch 
freigegeben, das muss der Programmierer selber tun, mit "free"...

Autor: Pete K. (pete77)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Blick in das Mapfile kann vielleicht nicht schaden.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also wenn schon blicken, dann doch gleich RTFM. Da hat sich schließlich 
jemand viel Mühe gemacht, das alles aufzuschreiben.

http://www.nongnu.org/avr-libc/user-manual/mem_sections.html

Oliver

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>unsigned char inbuff[Filelength()];
>>Fread(inbuff,Filelength());

>>funktionieren wobei Filelength() zur Compilerzeit noch nicht definitv
>>fest steht. Wie wird das dann da gehandhabt?

>inbuff liegt auf dem Stack ("Automatic" Variable), d.H. es wird erst
>beim Funktionsaufruf bzw betreten des Scopes angelegt.
>Die Größe muss zur Compilezeit also nicht feststehen.

als Gegenargument könnte man einbringen, dass
in keine Funktion eher verzweigt wird, bevor stackframe
nicht eingerichtet ist. Genaudas würde aber FileLength machen.
Ich glaube Standard C = C89 hatte (bis C99) und c++
bis heute, die Bedingung dass Arraylängen compiletime constanten sind.
Wahrscheinlich aus diesem Grund, generell hast Du aber recht,
einfach zu berechnen sind sie schon .. nur halt mit dem Stackrahmen
kommt man in die Quere.
Wenn ich falsch liege, bitte berichtigt mich.

Grüsse,
    Daniel

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt nicht nachgelesen, aber mal kurz mit dem GCC angetestet:
#include <stdint.h>

extern int Filesize();
extern void do_something(uint8_t *);

void func() {
  uint8_t test[Filesize()];
  do_something(test);
}

Beim Compilieren gibts ne Warning:
> avr-gcc -Os -Wall -pedantic -S test.c
test.c: In Funktion »func«:
test.c:7: Warnung: ISO-C90 verbietet Feld »test« variabler Größe

Die aber bei C99 weg ist:
> avr-gcc -Os -Wall -pedantic -std=c99 -S test.c

Im assembler kommt dann sowas raus:
        .file   "test.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
        .global __do_copy_data
        .global __do_clear_bss
        .text
.global func
        .type   func, @function
func:
/* prologue: frame size=0 */
        push r16
        push r17
        push r28
        push r29
        in r28,__SP_L__
        in r29,__SP_H__
/* prologue end (size=6) */
        in r16,__SP_L__
        in r17,__SP_H__
        rcall Filesize
        in r18,__SP_L__
        in r19,__SP_H__
        sub r18,r24
        sbc r19,r25
        in __tmp_reg__,__SREG__
        cli
        out __SP_H__,r19
        out __SREG__,__tmp_reg__
        out __SP_L__,r18
        in r24,__SP_L__
        in r25,__SP_H__
        adiw r24,1
        rcall do_something
        in __tmp_reg__,__SREG__
        cli
        out __SP_H__,r17
        out __SREG__,__tmp_reg__
        out __SP_L__,r16
/* epilogue: frame size=0 */
        pop r29
        pop r28
        pop r17
        pop r16
        ret
/* epilogue end (size=5) */
/* function func size 32 (21) */
        .size   func, .-func
/* File "test.c": code   32 = 0x0020 (  21), prologues   6, epilogues   5 */

Also speichert er sich den alten Stackpointer in r16,r17 zwischen, ruft 
Filesize auf, verringert den Stackpointer um den Rückgabewert (Mit 
gesperrten Interrupts), ruft do_something auf, und setzt dannach den 
Stackpointer auf die gespeicherten Werte zurück, wieder ohne Interrupts.

Nicht grad schöner Code der dabei rauskommt, funktionieren sollts aber.

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.