Forum: Mikrocontroller und Digitale Elektronik Datenspeicher überfüllt - wie effektiv nutzen / programmieren?


von Jannis (Gast)


Lesenswert?

Hallo Leut's;

ich habe einen ATTiny45 programmiert (im AVR Studio 4.13 mit GCC) um 
mein Prog zu schreiben. Nach dem kompilieren steht unter Memory Usage: 
Programm/ Data/ Eeprom - Speicher, dass mein Data Speicher zu 107,3% 
genutzt wird.

Ich möchte natürlich diesen Speicher reduzieren auf unter 100%. Die 
Frage ist: wie man generell Speicher-sparsam programmiert und auf 
unnütze Variablen verzichten kann. Was trägt zur Speicherreduzierung 
bei? Ich konnte in den Beiträgen zwar was über Speicher lesen, aber 
nicht wie man sprsam damit umgeht.

Wie sieht es bezüglich des Speicherbedarfs aus mit globalen Variablen 
oder mit Hilfsvariablen wei folgt:
1
uint8_t Zeit_180ms = 88;
2
uint8_t Zeit_100ms = 50;
3
uint16_t Strom_Nenn = 420;
4
...
Ich habe mal versucht z.B. die 16 Bit Variable in eine 8 Bit Variable zu 
verändern (natürlich auch die "420" auf unter 255 zu setzen) oder aber 
die Hilfsvariablen auszukommentieren und die Zahlen direkt zu verwenden 
oder globale Variablen in das Hauptprogramm zu verschieben. Aber 
irgendwie hat es nicht wirklich viel gebracht außer das ich jetzt 272 
byte (106,3%) verwenden.

Hat jemand Tipps oder einen Link zu einem Artikel wie man 
Speichersparsam programmiert? Was sollte man im Hinterkopf behalten 
während der Programmierung?

P.S.: Ich weiß, ich weiß. Wenn ich einen ATTiny 85 verwenden habe ich 
keine Probleme mit dem Speicher. Es geht mir mit diesem Thread nicht um 
die µC sondern wirklich um die tatsache der effizienten Progranmmierung 
bezüglich des vorhandenen Speichers.

Wäre für konstruktive Antworten dankbar.

von Fred S. (Gast)


Lesenswert?

Hallo Janis,

kennst Du Dich mit Assembler aus? Du kannst Dir in AVRStudio, wenn Du 
den Simulator benutzt, mit View/Disassembler ansehen, was der Compiler 
aus Deinem Code gemacht hat. So kannst Du lernen, wann und wie RAM 
belegt wird.

Mit uint8_t liegst Du schon recht gut gut. Vielleicht lassen sich in 
Schleifen usw. auch "register" Variable benutzen. Was für 
"Nebenwirkungen" die verschiedenen Compiler-Optimierungsstufen 
hinsichtlich der RAM-Nutzung haben, habe ich noch nicht probiert. Wäre 
vielleicht einen Versuch wert.

Gruß

Fred

P.S. Versuche möglichst wenige geschachtelte Funktionsausrufe zu 
benutzen, da dafür immer RAM gebraucht wird.

von Jannis (Gast)


Lesenswert?

Hallo Fred,

ich kenne mich leider nicht mit Assembler aus, sondern nur mit C.

von Andreas K. (a-k)


Lesenswert?

Der Compiler produziert ein Map-File, in dem die Speicherbelegung 
aufgeschlüsselt wird. Das ist bei der Suche die erste Adresse.

von Fred S. (Gast)


Lesenswert?

Hallo Janis,

noch ein Idee: Hast Du "-mtiny-stack" in den Compiler Optionen 
eingestellt? Falls nicht, verwendet der Compiler 16 bit für die 
Stack-Addressierung, so dass diese Adressen als 2 Bytes im RAM (bzw. auf 
dem Stack selbst) landen. Falls Du es probierst und dann später doch zum 
Attiny85 wechseln solltest: vergiss dann nicht, diese Option wieder zu 
entfernen!

Gruß

Fred

von Peter D. (peda)


Lesenswert?

Jannis wrote:

> Ich habe mal versucht z.B. die 16 Bit Variable in eine 8 Bit Variable zu
> verändern (natürlich auch die "420" auf unter 255 zu setzen) oder aber
> die Hilfsvariablen auszukommentieren und die Zahlen direkt zu verwenden
> oder globale Variablen in das Hauptprogramm zu verschieben. Aber
> irgendwie hat es nicht wirklich viel gebracht außer das ich jetzt 272
> byte (106,3%) verwenden.


Ja, das ist klar. Einzelne Variablen zu optimieren bringt fast nichts.

Besser ist es, überall da, wo globale Variablen unnötig sind, sie lokal 
anzulegen.

Die größte Optimierung ist jedoch bei Arrays möglich, die schlagen ja in 
voller Länge zu Buche.
Und beim GCC werden ohne spezielle Syntax auch alle Konstantenarrays im 
SRAM abgelegt.



Peter

von Jannis (Gast)


Lesenswert?

Ich nochmal,

Trägt folgender Code zu Speichernutzung bei?
1
uint8_t Zeit_500 = 245;
2
[...]
3
if (Zeit >= Zeit_500)
4
  [...]

Ich will damit den Code übersichtlich halten. Die Variable wird im Prog 
nicht verändert und behält den Wert.

Kann ich das gleiche auch mit diesem Code erreichen?
1
#define Zeit_500 245;
2
[...]
3
if (Zeit >= Zeit_500)
4
  [...]
Oder wird dann die Zahl 245 als Text 245 benutzt?

Wenn nicht, wird dadurch der Datenspeicher entlastet?

von Andreas K. (a-k)


Lesenswert?

Ja, kannst du so machen wenn du hinten beim #define noch das Semikolon 
rauswirfst.

Häng hier mal das Mapfile rein.

von Jannis (Gast)


Lesenswert?

@Andreas Kaiser

>Der Compiler produziert ein Map-File, in dem die Speicherbelegung
>aufgeschlüsselt wird. Das ist bei der Suche die erste Adresse.

Das kann ich nicht bestätigen. Bei mir werden folgende Files produziert: 
*.elf, *.eep, *.hex; *.aps, *.aws

@Fred S.

>noch ein Idee: Hast Du "-mtiny-stack" in den Compiler Optionen
>eingestellt?

nein habe ich nicht, kann ich aber ausprobieren...

von Karl H. (kbuchegg)


Lesenswert?

Jannis wrote:
> Wie sieht es bezüglich des Speicherbedarfs aus mit globalen Variablen
> oder mit Hilfsvariablen wei folgt:
>
1
uint8_t Zeit_180ms = 88;
2
> uint8_t Zeit_100ms = 50;
3
> uint16_t Strom_Nenn = 420;
4
> ...

wenn sich diese Werte nie ändern, dann kannst du das ersetzen durch

#define Zeit_180ms  88
#define Zeit_100ms  50
#define Strom_Nenn  420

> Ich habe mal versucht z.B. die 16 Bit Variable in eine 8 Bit Variable zu
> verändern (natürlich auch die "420" auf unter 255 zu setzen) oder aber
> die Hilfsvariablen auszukommentieren und die Zahlen direkt zu verwenden

mit den #define machst du im Grunde nichts anderes, allerdings
in einer etwas besseren Form, als wie wenn die Zahlenwerte direkt
im Code stehen würden.

> oder globale Variablen in das Hauptprogramm zu verschieben.

Das bringt nicht viel.
Globale Variablen wirst du nur dann los, wenn sie nicht wirklich
global sein müssen und in Subfunktionen verfrachtet werden können.

Zeig mal dein Programm. Speichersparen ist meist eine
Gratwanderung, die man am realen Code machen muss.

PS: Selbst wenn du den Speicher auf knapp unter 100% bringen
kannst, reicht das noch nicht. Es muss schon deutlich unter
100% sein, da ja zur Laufzeit für Call/Return Stack und
lokale Variablen auch noch Speicher benötigt wird.

von Andreas K. (a-k)


Lesenswert?

Jannis wrote:

> Das kann ich nicht bestätigen. Bei mir werden folgende Files produziert:
> *.elf, *.eep, *.hex; *.aps, *.aws

Muss man möglicherweise im Studio in den Projekteigenschaften noch 
einschalten.

>>noch ein Idee: Hast Du "-mtiny-stack" in den Compiler Optionen
>>eingestellt?


Das spart ein paar Bytes Code, aber keine Daten.

von Fred S. (Gast)


Lesenswert?

Jannis wrote:
>>Der Compiler produziert ein Map-File, ...
> Das kann ich nicht bestätigen. ...

Dann setze mal bei den Compiler-Optionen (erstes Fenster, wenn Du 
"configuration options" im Studio anklickst) ein Häkchen vor "generate 
map file"! Und den map file dann im Unterordner "default" (oder wohin 
bei Dir der Compiler schreibt) suchen.

Gruß

Fred

von Jannis (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt mal alle Werte die sich nicht ändern in defines 
definiert. Hat nicht wirklich was gebracht.

Das Map-file ist jetzt im Anhang, (danke für die Info a-k)

von Andreas K. (a-k)


Lesenswert?

Dir verhagelt der Floating-Point Fehler der aktuellen Version vom WinAVR 
Code und Daten. Es wird am einfachsten sein, wenn du die WinAVR Version 
von Mai 2007 verwendest.

von Jannis (Gast)


Lesenswert?

>Dir verhagelt der Floating-Point Fehler der aktuellen Version vom WinAVR
>Code und Daten. Es wird am einfachsten sein, wenn du die WinAVR Version
>von Mai 2007 verwendest.

Vielen Dank für die Info, aber ich muss Windows Vista benutzen und bei 
der Mai-Version gibt es da Probleme. Mein Administrator musste mir daher 
die aktuelle Version aufspielen.

Shit - und nu?

ich führe zwei berechnungen it floating point durch:
1
 I_Min = (wert * 0.7); // untere Grenze
2
 I_Max = (wert * 1.3); // obere Grenze

ich brauche aber definitiv die Werte für +/- 30 Prozent, Kann ich anders 
daran kommen?

von Karl H. (kbuchegg)


Lesenswert?

Jannis wrote:

> Shit - und nu?
>
> ich führe zwei berechnungen it floating point durch:
>
1
>  I_Min = (wert * 0.7); // untere Grenze
2
>  I_Max = (wert * 1.3); // obere Grenze
3
>
>
> ich brauche aber definitiv die Werte für +/- 30 Prozent, Kann ich anders
> daran kommen?


I_Min ist ein Integer?

  Delta = ( wert + 5 ) * 3 / 10;

  I_Min = wert - Delta;
  I_Max = wert + Delta;

(Die + 5 sind die Hälfte von den 10 und sollen eine korrekte
Rundung sicherstellen)

Aufpassen musst du, dass die Berechnung zwischendurch nicht
überlaufen kann. Hängt von wert ab (Datentyp und Wertebereich).

von Berti (Gast)


Lesenswert?

Integer arethemtik!
Da bleibt dann mehr oder weniger ein bisschen schieben übrig

von Jannis (Gast)


Lesenswert?

>Dir verhagelt der Floating-Point Fehler der aktuellen Version vom WinAVR
>Code und Daten. Es wird am einfachsten sein, wenn du die WinAVR Version
>von Mai 2007 verwendest.

DEFINITIV

Wenn ich mit ganzen Zahlen rechne habe ich folgendes:
Data:          4 bytes (1.6% Full)

Also ganze 100% weniger

@a-k
Woran hast du das in dem map-file erkannt?

@kbuchegg
Danke für Dein Rechenbeispiel, damit komme ich und auch mein 
Datenspeicher { ;-) } klar. Die Rundungsfehler sind in diesem Beispiel 
nicht soooo wichtig!

Vielen Dank euch allen für eure ausführlichen Informationen.
Mir ist noch wichtig, wie man das im map-file erkennt und vielleicht 
trotz euren Infos, wo man Artikel oder Infos über speicheroptimierte 
Programmieren findet.
Denn ich interessieren mich generell für einen sauberen Programmierstil, 
weil ich mehr oder weniger gerade erst anfange und von Anfang an grobe 
Fehler vermeiden möchte, die sich sonst ins Hirn brennen und später nur 
noch schlecht loszuwerden sind!

von Andreas K. (a-k)


Lesenswert?

Jannis wrote:

> @a-k
> Woran hast du das in dem map-file erkannt?

In diesem Fall an der Variablen __clz_tab aus der libgcc. Diesen Bug 
hatte ich schon im Dezember gefunden. Siehe Thread kurz nach der Release 
vom neuen WinAVR.

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.