Flash Speichers des ATMega328P ist voll? Mit 12,7 kb??

OP #4617939
Lesenswert?

Guten Morgen,
Ich bin zurzeit wieder am weiter programmieren meiner Wetterstation. Und 
wollte gerne noch eine Anzeige Modus hinzufügen wo man die Minimale 
Temperatur und die Maximale Temperatur sehen. Als ich es dann kompiliert 
habe, kam im Atmel Studio 7 unten eine Fehler Nachricht. Dieses sieht so 
aus:

Programm Memory Usage: 12788 bytes  39,0 % Full
Programm Memory Usage: 12788 bytes  39,0 % Full
                Data Memory Usage: 2054 bytes 100,3 % Full (Memory 
Overflow)

Hier nochmal als Bild: http://prntscr.com/bhug6u

Ich verwende denn ATMega328P mit 16 Mhz. Soweit ich weis und auch 
gesehen wenn ich bei einen neuen Projekt denn Controllor auswähle, hat 
dieser ein App./Boot Memory von 32 KBytes. Und auch im Datenblatt steht 
das dieses 32 Kbytes hat.

Muss ich da vorher noch was einstellen damit ich mehr nutzen kann? Ein 
anderen Controllor in meine Platine einzubauen ist nicht möglich. Da für 
ein ATMega644 oder ATMega32/16 kein Platz ist.

Mfg Felix.
OP #4617954
Lesenswert?

Joachim B. schrieb:
> schaffe Platz im RAM
>
> Texte aus dem Flash direkt
> globale Variablen verringern, auf lokale umsteigen wo möglich
> Platz für Variablen reservieren die mehrere Functions nutzen können
>
> usw.
>
> zeig mal deinen Code der alles RAM verbraucht

Jo, aber nicht erschrecken es ist nicht grade wenig Code
Angehängte Dateien:
#4617973
Lesenswert?

wie vermutet, zuviel globales Zeugs!

Kann man ja machen wenn man SRAM ohne Ende hat, so aber nicht mit nur 2K

ich tippe mal deine ganzen lcd_print Texte brauchen auch RAM, die sollte 
im freien Flash liegen und per strcpy_P nur bei Bedarf in eine 
leerzeile_str kopiert werden
Gast #4617975
Lesenswert?

Es hat keinen Sinn für jede Ausgabe einen extra Stringbuffer
zu reservieren. Er braucht auch maximal so gross sein wie
die Zeilenlänge des Displays.

also mache
1
char readingTemp[100];
2
char tempFinal[100];
3
char tempDelay[100];
4
char mesaurmentDelay[100];
5
char minTemp[100];
6
char maxTemp[100];

zu
1
char temp_str[50];  /+ due maximale Zeilenlänge + etwas  */

und mache deine ganzen Ausgaben in dieses Feld.
#4617976
Lesenswert?

Deine Variable wie readingTemp, etc verbraten alle jeweils 100 Bytes 
RAM. Gehe den Code durch und überlege dir wie viele Bytes du maximal 
benötigst, und verringere die Größe der Arrays entsprechend.

Andere arrays wie z.B. minuten[10] ist wiederum zu kurz für die Daten 
die du hinein schreibst und muss vergrößert werden.

Warum du in der Funktion avg_measurement() den selben Code 10 mal 
hintereinander kopiert hast ist mir auch nicht ganz ersichtlich. Hier 
kann man mit einer Schleife den code sicherlich verkürzen.

Der Tipp mit Strings in den flash verlegen wurde oben schon erwähnt. Wie 
das geht findest du im AVR-GCC Tutorial. Jeder deiner Strings liegt im 
RAM und verbraucht dort kostbaren Platz. Hier hast du auch oft quasi den 
selben String mehrfach im RAM(z.B. in avg_measurements()), wo sich der 
selbe String nur um eine Ziffer unterscheidet.
OP #4617979
Lesenswert?

Joachim B. schrieb:
> wie vermutet, zuviel globales Zeugs!
>
> Kann man ja machen wenn man SRAM ohne Ende hat, so aber nicht mit nur 2K
>
> ich tippe mal deine ganzen lcd_print Texte brauchen auch RAM, die sollte
> im freien Flash liegen und per strcpy_P nur bei Bedarf in eine
> leerzeile_str kopiert werden

Habe mal die ganzen Array auf 1 Byte gekürzt. Dann ich ja eh nur 1 Wert 
reinschreibe. Und zak nur noch 69,5 % des RAM verwendet.

Keine Ahnung ob die lcd_print sachen in denn RAM schreiben: So sieht der 
Code dazu aus: http://prntscr.com/bhuoh5
#4617984
Lesenswert?

Felix N. schrieb:
> Keine Ahnung ob die lcd_print sachen in denn RAM schreiben:

ne die sind es nicht, es ist dein:

lcd_printlc(1, 1, "Das Ergebnis wird");

könnte man auch umformen

//globale LCD Zeile

char leerzeile[50]={0}; // Größe nach maximaler Zeichenlänge+1, global 
vor PRG

strcpy_P(leerzeile, "Das Ergebnis wird");
lcd_printlc(1, 1, leerzeile);
Gast #4617993
Lesenswert?

U. F. schrieb:
> Deine ISR macht einen überladenen Eindruck!
>
> Auch sehe ich kein einziges "volatile".
> Ich schätze mal, das wird auch noch für Fehlfunktionen sorgen.
1
while (1){
2
    }

bei einer leeren Hauptschleife kann es keine Probleme mit Variabel in 
der ISR geben.
Gast #4617998
Lesenswert?

Felix N. schrieb:
> Wie meinst du das?

Zum Beispiel:

alt:
1
............
2
  sprintf(tempDelay, "%d ms", basicTempTime);
3
  lcd_printlc(3, 1, tempDelay);
4
............
5
  sprintf(mesaurmentDelay, "%d ms", basicMeasurementTime);
6
  lcd_printlc(3, 1, mesaurmentDelay);
7
............

neu:
1
............
2
  sprintf(temp_str, "%d ms", basicTempTime);
3
  lcd_printlc(3, 1, temp_str);
4
............
5
  sprintf(temp_str, "%d ms", basicMeasurementTime);
6
  lcd_printlc(3, 1, temp_str);
OP #4618021
Lesenswert?

Frickelfritze schrieb:
> Genau das, so wie hier schon beschrieben.
>
> Frickelfritze schrieb:
>> Es hat keinen Sinn für jede Ausgabe einen extra Stringbuffer
>> zu reservieren.

Ja kommt glaubig daher. Das ich bevor ich mit den Controllor angefangen 
bin Java programmiert habe. Und dort für jede Sache eine Variable 
angelegt zu habe. Denn beim Rechner mit ca. 4 bis 16 GB RAM ist das auch 
so zimmlich egal ob er jetzt 500 mb oder 1 gb belegt. Aber ich habe nun 
auch mal Variablen die ich nur innerhalb einer Methode benötige aus der 
Globalen List oben entfernt und in die Funktion rein gepackt. So sind es 
ja auch nur Temp Variablen oder?

Was hat das eigentlich mit diesen volatile auf sich. Ist das wichtig?
#4618117
Lesenswert?

Felix N. schrieb:
> Was hat das eigentlich mit diesen volatile auf sich. Ist das wichtig?

das die ISR die Variable immer liest und nicht welche aus dem Cache 
nimmt.
Das ist wichtig das wirklich die Variable immer in der richtigen 
Unterroutine mit den stimmigen Daten genommen wird.

Sub 1 x=10
ISR x++

ohne volatile ist in Sub 1 immer noch x=10

volatile kann man aber auch mal gurgeln

https://de.wikipedia.org/wiki/Volatile_(Informatik)
#4618392
Lesenswert?

kerle schrieb:
> Cache kann man gurgeln. Solltest du mal machen.

Krümelkacker, ob das nun cache oder var auf dem Stack oder aus dem 
Register r17 genannt wird ändert doch nix am Sachverhalt mit volatile 
dem Compiler oder den Nachbarn anzuweisen die Variable immer neu 
einzulesen.

kerle schrieb:
> Scho ma deinem eigenen Link gefolgt? Solltest du ma mmachen.

ja, für dich den Tip an deinem Leseverständnis zu arbeiten, wenns dir 
nicht wichtig ist werde Schaumschläger.
(Firma: Vescomp) #4618410
Lesenswert?

Joachim B. schrieb:
> das die ISR die Variable immer liest und nicht welche aus dem Cache
> nimmt.

Arduinoquäler schrieb:
> Käse.
>
> Es gibt beim Arduino (besser gesagt bei den AVR Controllern)
> keinen Cache.

kerle schrieb:
> Cache kann man gurgeln. Solltest du mal machen.

 Wenn Ihr beiden Trolle nicht imstande seid, zu verstehen was er
 sagen wollte, solltet ihr euch auch nicht zu Wort melden.
Gast #4618421
Lesenswert?

Joachim B. schrieb:
> kerle schrieb:
>> Cache kann man gurgeln. Solltest du mal machen.
>
> Krümelkacker, ob das nun cache oder var auf dem Stack oder aus dem
> Register r17 genannt wird ändert doch nix am Sachverhalt mit volatile
> dem Compiler oder den Nachbarn anzuweisen die Variable immer neu
> einzulesen.

Den tatsächlichen Sachverhalt im ATMega328p sollte man bei deiner 
Antwort aber schon kennen, sonst hinterläßt sie mehr Verwirrung als 
Klärung.

> kerle schrieb:
>> Scho ma deinem eigenen Link gefolgt? Solltest du ma mmachen.
>
> ja, für dich den Tip an deinem Leseverständnis zu arbeiten, wenns dir
> nicht wichtig ist werde Schaumschläger.

Danke an ufuf, der die Ursache für das Versagen des Links bei Anklicken 
aufgeklärt hat. Du hast es ja nicht mal in deinem eigenen Post bemerkt.

Deine Antwort war einfach nur aufgeschlagener Schaum, dem man nur wegen 
den daraus folgenden richtigstellenden Posts Berechtigung einräumen 
könnte.
Gast #4618435
Lesenswert?

> Krümelkacker
> aufgeschlagener Schaum

Es wäre ja zu schön gewesen, und eigentlich war alles bis zur 8. Antwort 
geklärt.
Aber dann kommen die Rindviecher raus und meinen, sie müssten muhen.

Wieder mal ein schönes Beispiel für die Sozialkompetenz in diesem Forum.
#4618503
Lesenswert?

kerle schrieb:
> Danke an ufuf, der die Ursache für das Versagen des Links bei Anklicken
> aufgeklärt hat

OK das mit den Links hier ist mir auch schon öfter aufgefallen und ja 
ich hatte meinen Link vor dem Einstellen hier angeklickt nur nicht nach 
dem Einstellen! (Nach der ersten Antwort kann man den "Fehler" nicht 
mehr korrigieren)

Cowboy schrieb:
> Wieder mal ein schönes Beispiel für die Sozialkompetenz in diesem Forum.

stimmt!
Gast #4618569
Lesenswert?

Hab schon besser kommentierten Quelltext gesehen.
Wenn man häufig sich wiederholende Routinen benötigt
wo sich nur EIN Datum ändert, kann man sicher einen
besseren Algorithmus programmieren, der das alles
zusammenfasst.
#4618589
Lesenswert?

Das meiste RAM verbrauchen sicher die Text-Literale, die beim AVR-GCC 
ohne Überredung eben dort landen. Liegt an Harward vs. Neumann.

So wird der String im FLASH abgelegt und nur zu Weiterverarbeitung ins 
RAM geladen:
1
#include <avr/pgmspace.h>
2
 
3
int foo ()
4
{
5
    char string_im_ram[40];
6

7
    strcpy_P (string_im_ram, PSTR ("Hallo Welt"));
8
}

Eventuell hat die LCD-Lib ja eine lcd_printstr_P() Funktion, die direkt 
aus dem FLASH liest. Wenn nicht ist die nicht schwer zu bauen. Das Makro 
PSTR() sorgt dafür das das String-Literal im FLASH landet.

Die ersten grob 700 Byte gehen in überflüssigen Puffern verloren, dann 
noch mal ΠxDaumen 1000 Byte. Es werden also statisch 300 Byte gebraucht.
Wobei bedacht werden muß, das nichtstatisch sowas wie Stack zu den 
anfänglichen 100,3% noch dazukommt.
#4619062
Lesenswert?

@Carl Drexler (jcw2)

>Eventuell hat die LCD-Lib ja eine lcd_printstr_P() Funktion, die direkt
>aus dem FLASH liest. Wenn nicht ist die nicht schwer zu bauen. Das Makro
>PSTR() sorgt dafür das das String-Literal im FLASH landet.

#include "i2c.h"
#include "lcd.h"

Das ist mit hoher Wahrscheinlichkeit diese Library, sei es das Original 
oder die von mir aufpolierte Version.

Beitrag "Re: I2CLCD Library für HD44780 LCDs"

Man ersetzte die Funktionsaufrufe lcd_printlc durch lcd_printlc_P

Aus

lcd_printlc(1, 1, "Wetterstation:");

wird

lcd_printlc_P(1, 1, PSTR("Wetterstation:"));

Weiterhin sollte man

sprintf(readingTemp, "Temp: +%-.2f *C", currentTemp);

durch

sprintf_P(readingTemp, PSTR("Temp: +%-.2f *C"), currentTemp);

ersetzen, damit landen die Formatstrings auch direkt im Flash, ohne 
zusätzlich RAM zu verschwenden.


Und daß EIN einziger String für alle variablen Ausgaben reicht, wurde ja 
nun schon mehrfach gesagt. Der muss auch nicht länger als eine LCD-Zeile 
+ Terminator sein, d.h. 21 Zeichen sind ausreichend.

Man kann das Programm auch noch deutlich straffen, denn Programmierer 
sind nicht nur (tipp)faul, sie sind auch im allgemeinen 
Effizienzfanatiker ;-)
1
void tempSavePage(void) {
2
  lcd_clear();
3
  lcd_printlc_P(1, 1, PSTR("Settings Page 1/2"));
4
  lcd_printlc_P(2, 1, PSTR("Delay Temperatur"));
5
  lcd_printlc_P(3, 1, PSTR("Speichere...."));
6
  _delay_ms(750);
7
  uint8_t writer = 0x00;
8

9
  switch (basicTempTime) (
10
    case  250 : writer = 0x01; break;
11
    case  500 : writer = 0x02; break;
12
    case  750 : writer = 0x03; break;
13
    case 1000 : writer = 0x04; break;
14
    case 1250 : writer = 0x05; break;
15
    case 1500 : writer = 0x06; break;
16
    case 1750 : writer = 0x07; break;
17
    case 2000 : writer = 0x08; break;
18
    case 2250 : writer = 0x09; break;
19
    case 2500 : writer = 0x10; break;
20
    case 2750 : writer = 0x11; break;
21
    case 3000 : writer = 0x12; break;
22
  }
23
  lastTempState = basicTempTime;
24
  writeEEPROM(12, writer);
25
  lcd_printlc_P(4, 1, PSTR("Gespeichert!"));
26
  _delay_ms(1000);
27
  loadSettings();
28
}


Oder noch einfacher, wenn man ein bisschen Mathematik versteht ;-)

1
void tempSavePage(void) {
2
  lcd_clear();
3
  lcd_printlc_P(1, 1, PSTR("Settings Page 1/2"));
4
  lcd_printlc_P(2, 1, PSTR("Delay Temperatur"));
5
  lcd_printlc_P(3, 1, PSTR("Speichere...."));
6
  _delay_ms(750);
7
  uint8_t writer;
8

9
  if (basicTempTime < 2500) {
10
    writer = basicTempTime / 250;
11
  } else {
12
    writer = (basicTempTime / 250) + 6;
13
  }
14

15
  // ist das WIRKLICH so gewünscht oder eher ein Tippfehler?
16
  // Soll 0x01-0x12 rauskommen (HEXADEZIMAL!)
17
  // oder eher 1-12 (DEZIMAL)?
18

19
  lastTempState = basicTempTime;
20

21
  writeEEPROM(12, writer);
22
  lcd_printlc_P(4, 1, PSTR("Gespeichert!"));
23
  _delay_ms(1000);
24
  loadSettings();


Diese Arien an mehreren Stellen mit einem Dutzend if() else() kann man 
so leicht wegrationalisieren. Das spart nicht nur massiv Tipperei, 
sondern bringt vor allem Übersicht.
#4619514
Lesenswert?

Falk B. schrieb:
> Aus
>
> lcd_printlc(1, 1, "Wetterstation:");
>
> wird
>
> lcd_printlc_P(1, 1, PSTR("Wetterstation:"));
>
> Weiterhin sollte man
>
> sprintf(readingTemp, "Temp: +%-.2f *C", currentTemp);
>
> durch
>
> sprintf_P(readingTemp, PSTR("Temp: +%-.2f *C"), currentTemp);

Hallo Falk.
Nach diesen Änderungen im Code ist das alles nur am Buggen. Beim 
verändern des Delays der Temperatur wenn ich dort um -250 verkleinern 
will kommt dort "/no to change" in die Zeile. + 250 Addieren geht aber. 
Beim Delay für das Measurment funktioniert es problemlos.
#4619528
Lesenswert?

Vielleicht mal mit einfacher Ausgabe eines "Flash-Strings" starten, um 
dieses Legosteinchen zu testen und dann erst alle potentiellen Fehler in 
einen Topf schmeißen.
 Bitte den Eingangssatz nicht falsch verstehen, aus deinem bisher 
geschriebenen sprechen nicht unbedingt Jahrzehnte Programierpraxis.
Und selbst nach 35 Jahren muß man das manchmal, immer seltener 
vielleicht, genau so machen. Stück für Stück.
OP #4619573
Lesenswert?

S. Landolt schrieb:
> Es scheint, als brächte er nicht nur seine Identitäten durcheinander.

Nein eigentlich nicht. Das kam daher das ich vom Laptop dieses 
geschreiben habe und warum auch immer mit der E-Mail Adresse meines 
Kumpels einloggt. Denn ich habe mal was eingestellt bei gmail. Und seit 
dem meldet Mikrocontrollor.net mich immer mit seinen Account an. Der 
übriges auch µC programmiert.

Zum Problem. Das Problem wahr das ich die ganze Zeit weiter sprintf mit 
PSTR genutzt habe aber nich sprintf_P
#4619580
Lesenswert?

@Jan Hampel (jan_h865)

>Nach diesen Änderungen im Code ist das alles nur am Buggen.

Du bist doch gar nicht der OP des Threads?

> Beim
>verändern des Delays der Temperatur wenn ich dort um -250 verkleinern
>will kommt dort "/no to change" in die Zeile. + 250 Addieren geht aber.
>Beim Delay für das Measurment funktioniert es problemlos.

Das Programm hat so oder so noch einen Bug. In der ISR macht man keine 
LCD Ausgaben! Erstens, weil das recht lange dauert und 2. weil sich das 
mit den LCD-Ausgaben im Hauptprogramm überschneiden kann! Dann kommt 
Mist raus, Stichwort reentrante Funktionen (die LCD-Funktionen sind es 
NICHT!).
Die saubere Methode ist die Verwendung von Flags zwischen ISR und 
Hauptprogramm.

https://www.mikrocontroller.net/articles/Interrupt#Steuersignale_zwischen_ISR_und_Hauptprogramm
OP #4619595
Lesenswert?

Falk B. schrieb:
> Du bist doch gar nicht der OP des Threads?

Wie bereits gesagt. Das die Antwort von ein anderen Account erstellt 
wurde liegt daran das ich dieses Antwort vom Laptop ausgeschrieben habe. 
Und ich mich bei GMail angemeldet habe um mein Kumpel zu helfen bei 
Problem mit sein Mail Account. Mich aber vergessen abzumelden. Und weil 
ich mich bei Mikrocontrollor.net mit dem Google Konto anmelde. Hat er 
mich mit dem Account angemeldet. Weil ich mit diesen angemeldet wahr. 
Und mich mit ein eigenen(Felix Neumann) abgemeldet habe. Ich hatte mich 
nur vergessen um zu melden nachdem ich mein Kumpel geholfen habe.

Falk B. schrieb:
> Das Programm hat so oder so noch einen Bug. In der ISR macht man keine
> LCD Ausgaben! Erstens, weil das recht lange dauert und 2. weil sich das
> mit den LCD-Ausgaben im Hauptprogramm überschneiden kann! Dann kommt
> Mist raus, Stichwort reentrante Funktionen (die LCD-Funktionen sind es
> NICHT!).
> Die saubere Methode ist die Verwendung von Flags zwischen ISR und
> Hauptprogramm.

Okay, werde das gleich mal lesen. Der Bugg wahr das ich die ganze Zeit 
mit sprint und PSTR gearbeitet habe und nicht mit sprint_P nach der 
Änderung auf sprint_P funktionierte alles wieder.
#4619600
Lesenswert?

Felix N. schrieb:
> Denn beim Rechner mit ca. 4 bis 16 GB RAM ist das auch
> so zimmlich egal ob er jetzt 500 mb oder 1 gb belegt.

Klingt nach jemandem der Chrome programmiert hat.
Mit dieser besch..... Einstellung ist es kein Wunder das Anwendungen 
immer mehr Speicher fressen.
Wenn man gezwungen ist, mit begrenztem Speicher zu programmieren lernt 
man, das diese Einstellung nicht die Beste ist.
OP #4619604
Lesenswert?

Frank B. schrieb:
> Klingt nach jemandem der Chrome programmiert hat.
> Mit dieser besch..... Einstellung ist es kein Wunder das Anwendungen
> immer mehr Speicher fressen.
> Wenn man gezwungen ist, mit begrenztem Speicher zu programmieren lernt
> man, das diese Einstellung nicht die Beste ist.

Ja gut, aus Fehlern lernt man. Nun weis ich ja wie man es am besten 
nicht machen sollte um viel Speicher zu fressen :D
Werde es mir nun angewöhnen, möglichstes RAM schonend zu programmieren.

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