Hallo *,
ich möchte mit einem '85er einen "tiny-computer" bauen. Eigentlich
funktioniert alles wie gewünscht, bis der Programmcode grösser 3.5kB
wird. Dann fängt der tiny an zu spinnen. Das Programm läuft nicht durch,
verrückte Zeichen auf dem Display, usw. ...
Die Idee:
An einem ATtiny85 hängen in Modulbauweise Netzteil, Display,
Portexpander, Analogeingänge / -ausgänge, Soundausgang, ähnliches.
Portexpander werden erkannt und können über Menüstruktur manuell
geschaltet oder mit Zeitschaltern programmiert werden. Das Menü wird
über Taster und ein Poti eingestellt und gewählt.
Umsetzung:
a) Hardware:
Der "Computer" ist experimentell schon aufgebaut (siehe Foto). Er
verfügt über Reset-Knopf, links, rechts, rauf, runter, Eingabe - Taster,
Poti an analog Eingang, funktionierende i2c Schnittstelle und 2x16
Display.
b) Software:
Die SW wird entwickelt über die Arduino GUI 1.0.5-r2 und die
arduino-tiny Umgebung ( https://code.google.com/p/arduino-tiny/ ).
Zum Einsatz kommen die libraries TinyWireM für den i2c Bus (
http://playground.arduino.cc/Code/USIi2c ) und LiquidCrystal_I2C_85V1
für das Display ( gleiche Webseite auf arduino playground ).
Programmiert wird der uC über die 'Arduino as ISP' Funktion am Arduino
UNO.
Ich habe schon mehrere Programm-Module geschrieben, echte
Problemlösungen für Menü, Display, Tasten, usw.
Das Problem:
Alle Programm-Module funktionieren für sich ganz gut. Bis der Code
ungefähr die 3.5 kB Grenze überschreitet. Dann wird's seltsam (wenn es
komisch wäre, müsste ich ja lachen). An ein Zusammenfügen der Programme
ist erst gar nicht zu denken.
Die Fragen:
Hat jemand schon Erfahrung mit dem arduino-tiny Aufsatz auf die arduino
GUI gemacht? Hier vermute ich das Problem.
Kennt jemand libraries (i2c und i2c-display) für c -
Programmierumgebungen wie programmers notepad oder Atmel - Studio? Mit
libraries kenne ich mich überhaupt nicht aus, besonders die i2c-Display
Ansteuerung deucht mir höchst komplex und über meine
Programmier-Kenntnisse.
Aufruf:
Bei Interesse bin ich gerne bereit, alles bereits entwickelte frei zu
geben, HW und SW.
Vielleicht könnte man ja in einer gemeinsamen Projektarbeit zu einem
guten Ergebnis kommen?
Sorry für den langen Roman, aber ich fische mit dem Fehler absolut im
Trüben. Vielleicht findet ja der Eine oder Andere Interesse an der Idee
und macht mit ...
Danke jedenfalls für das coole Forum hier.
Viele Grüsse aus Augsburg,
Helge
Vielleicht läuft Dein Stack in Deine Variablen 'rein?
Also mal Deinen RAM betrachtet: von unten werden die Variablen
gespeichert, von oben der Stack (Unterprogrammaufrufe in
Unterprogrammaufrufen in Unterprogrammaufrufen etc).
?
Hallo Rainer,
danke für Deine schnelle Antwort!
So etwas habe ich mir auch schon gedacht, aber wie kann ich das
nachvollziehen? Und vor Allem: Wie könnte ich das vermeiden?
Gruss, Helge
Hi
>ich möchte mit einem '85er einen "tiny-computer" bauen. Eigentlich>funktioniert alles wie gewünscht, bis der Programmcode grösser 3.5kB>wird.
Von wo stammt der Wert 3.5k?
MfG Spess
Helge Schick schrieb:> So etwas habe ich mir auch schon gedacht, aber wie kann ich das> nachvollziehen? Und vor Allem: Wie könnte ich das vermeiden?> Gruss, Helge
Kannst Du einen Chip mit mehr SRAM verwenden? Ausrechnen ist nicht so
leicht - Du müsstest theoretisch in der Ausgabe vom Compiler sehen, wie
weit die Variablen gehen. (oder Du überschlägst es anhand der Typen und
ihrer Anzahl, besonders bei Arrays, Strings, ..) Im Programm kannst Du
den SP (Stack pointer) auslesen.
Generell weniger verschachtelte Funktions- bzw. Unterprogrammaufrufe
verwenden ist nur eine Notlösung.
Peter II schrieb:> der Stack hat doch nichts mit der Programmgröße zu tun.
nein, aber mit dem SRAM, und wenn er mehrere Programmteile
zusammensetzt, ist es wahrscheinlich, dass die auch mehr Variablen
benutzen.
Auf Peter hat niemand gehört. Daher nochmal:
Die Programmgröße (FLASH) hat nichts mit Heap oder Stack (SRAM) zu tun.
Den Flash kannst du zu 100% zuknallen. Kein Problem. Beim SRAM muss
Platz für den gelassen werden.
Stammen die 3,5kb von der avr-size Ausgabe?
Welche Belegung zeigt es für den Ram an?
Peter II schrieb:> Rainer Unsinn schrieb:>> Vielleicht läuft Dein Stack in Deine Variablen 'rein?>> der Stack hat doch nichts mit der Programmgröße zu tun.
Je mehr Programmcode, desto mehr Variablen, desto mehr RAM. Die
Beziehung ist vielleicht nicht linear, aber Du wirst mir zustimmen, dass
man in den seltensten Fällen durch Hinzufügen von Programmcode den
RAM-Bedarf verringert ;-)
Das "komische Verhalten", dass der TO anführt, spricht auch dafür. Oft
trifft das Problem bei LCD-Routinen auf, die viel Texte ausgeben, welche
beim Start vom flash ins RAM kopiert werden. PROGMEM hilft dagegen.
Frank M. schrieb:> Je mehr Programmcode, desto mehr Variablen, desto mehr RAM. Die> Beziehung ist vielleicht nicht linear, aber Du wirst mir zustimmen, dass> man in den seltensten Fällen durch Hinzufügen von Programmcode den> RAM-Bedarf verringert ;-)
das nicht, aber es wird auch nicht mehr Ram verbraucht wenn ich noch 2
zusätzliche Funktionen schreibe.
Hallo Cyblord,
die Meldung
Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)
stammt aus der Arduino IDE nach dem upload.
Danke für Deine Hilfe.
Gruss, Helge
Helge Schick schrieb:> Hallo Cyblord,> die Meldung> Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)> stammt aus der Arduino IDE nach dem upload.
Achso. Arduino. Na dann viel Spass weiter.
Peter II schrieb:> aber es wird auch nicht mehr Ram verbraucht wenn ich noch 2> zusätzliche Funktionen schreibe.
Vielleicht werden die aber auch mal aufgerufen?
Ralf G. schrieb:> Peter II schrieb:>> aber es wird auch nicht mehr Ram verbraucht wenn ich noch 2>> zusätzliche Funktionen schreibe.>> Vielleicht werden die aber auch mal aufgerufen?
Was auch nicht mehr RAM braucht. Solange die Schachtelungstiefe nicht
zunimmt. Und das tut sie nunmal nicht automatisch nur weil es mehr Code
oder mehr Funktionen gibt.
Ralf G. schrieb:> Vielleicht werden die aber auch mal aufgerufen?
auch dann nicht zwingend. Denn es laufen ja nicht alle Funktionen
gleichzeitig.
Es gibt keine wirklichen Zusammenhang zwischen Flash und Ram verbrauch.
Man kann 8kb Flash nutzen und nur 10byte Ram, oder auch 10byte Flash und
8kb RAM.
Bitte nicht falsch verstehen: Der Arduino ist eigentlich nur der ISP. OK
die Entwicklungsumgebung ist fragwürdig. Habe ich ja anfangs auch
geschrieben. Würde ja auf pn oder Atmel Studio wechseln, nach C, aber
die libraries schreibe ICH auf keinen Fall, zu wenig Programmierpower
...
Helge Schick schrieb:> lcd.print("PCF8574 @: ");> lcd.print(" ready, press ");> // lcd.print(" tinycomputer ");> lcd.print("* IIC error:");> [und noch ca. 20 weitere Zeilen mit lcd.print]> Das ist doch verrückt, oder?
Nein, überhaupt nicht verrückt. Du verwendest jede Menge Textkonstanten,
die alle beim Boot ins RAM kopiert werden.
Stelle das für alle Textkonstanten um auf:
lcd.print(F("My string in FLASH"));
Ach das Problem liegt, wie immer, darin dass man natürlich Arduino
Module nicht einfach so kombinieren kann. Niemand weiß welche Resourcen
die Module belegen. Und dann noch das Arduino-Tiny Gefrickel. Ich würde
als TE mal die lib "info-to-brain" ausprobieren und den Tiny direkt in C
programmieren. Aber neee das geht natürlich nicht. Dafür ist man zu
faul, aber auf dicke Hose mit nem "tiny computer" machen. Ist doch
lächerlich dafür dann Arduino zu nehmen. Da braucht man erst recht
direktere Zugriff auf seine Resourcen. ich gönne solchen Leuten
jeglichen Fehler und alle Probeme im Projekt. Nur zu. So lernt man das.
Auf die harte Tour.
Hallo Frank,
das ist es bestimmt! Aber die Zeile
lcd.print(F("My string in FLASH"));
verstehe ich nicht. Wo ist das dokumentiert? Was bedeutet das "F"? Wie
kommt dann die Meldung
Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)
zustande?
Gruss, Helge
Peter II schrieb:> Es gibt keine wirklichen Zusammenhang zwischen Flash und Ram verbrauch.
Prinzipiell und wenn man seinen Code 100%ig selbst unter Kontrolle hat
natürlich nicht. Bei Hochsprachenverwendung ist dann aber doch
Frank M. schrieb:> Je mehr Programmcode, desto mehr Variablen, desto mehr RAM
wahrscheinlicher.
Moby AVR schrieb im Beitrag #4021145:
> Prinzipiell und wenn man seinen Code 100%ig selbst unter Kontrolle hat> natürlich nicht. Bei Hochsprachenverwendung ist dann aber doch
Weil Hochsprachen in Mobys kranker troll Phantasie gerne mal
kilobyteweise Ram belegen, einfach so. Spontan. Kannste nix dagegen
machen. Hilft nur Assembler. iss so.
Helge Schick schrieb:> Hallo Frank,> das ist es bestimmt! Aber die Zeile> lcd.print(F("My string in FLASH"));> verstehe ich nicht. Wo ist das dokumentiert? Was bedeutet das "F"? Wie> kommt dann die Meldung
Das Makro F(s) definiert einen konstanten String im Flash, welcher zur
Laufzeit NICHT ins RAM kopiert wird. Ich hatte ja oben schon in meinem
ersten Posting das Stichwort PROGMEM angegeben. Aber offenbar ist es so,
dass man erstmal Tipps ignoriert, welche man nicht versteht ;-)
Übrigens: Dieses Problem tritt nicht nur bei Arduino-AVRs auf, sondern
auch, wenn man in "nacktem C" AVRs programmiert. Das nur mal so nebenbei
als Hinweis an cyblord. (Auch wenn ich ihm recht gebe: Man braucht keine
Arduino-Lib, um AVRs zu programmieren).
Zurück zum Thema. Google-Suche nach "Arduino PROGMEM" wirft u.a.
folgende Links aus:
http://arduino.cc/en/pmwiki.php?n=Reference/PROGMEMhttps://learn.adafruit.com/memories-of-an-arduino/optimizing-sram
(und noch viele andere)
> Wie kommt dann die Meldung> Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)> zustande?
Je mehr lcd.print()-Aufrufe Du machst, desto mehr Speicher im RAM
brauchst Du, wenn Du die Text-Konstanten nicht ausdrücklich für den
Flash-Speicher deklarierst. Insofern sieht das Peter etwas zu
engstirnig.
Peter II schrieb:> Ralf G. schrieb:>> Vielleicht werden die aber auch mal aufgerufen?>> auch dann nicht zwingend. Denn es laufen ja nicht alle Funktionen> gleichzeitig.
Tja, es kommt darauf an, was für Funktionen dazukommen. Wenn eine
Funktion die nächste aufruft, dann wächst der Stack.
Hallo Frank,
das ist die Lösung, es stimmt! Habe es ausprobiert. Danke für Deine
Hilfe.
Auch Danke an alle Anderen engagierten Mitstreiter!
Man muss Textkonstanten explizit in den Flash schreiben, dann geht es.
Frage gelöst ...
Gruss, Helge
Wenn man mit einer Umgebung arbeiten würde, die den statischen SRAM
Verbrauch direkt anzeigt, dann hätte man das sofort gesehen. Aber man
will es sich ja schwer machen.
Helge Schick schrieb:> PS: Die adafruit - Seite ist gut.
Wie gesagt: Es gibt auch noch andere Seiten, wo PROGMEM & Co näher
erklärt werden.
Auch Arduino dokumentiert das F(s) in der print()-Methode:
http://arduino.cc/en/Serial/print
Zitat:
-------------------------------- schnipp -------------------------------
You can pass flash-memory based strings to Serial.print() by wrapping
them with F(). For example :
Serial.print(F(“Hello World”))
-------------------------------- schnapp -------------------------------
Das ist zwar jetzt das print() für serielle Schnittstellen, aber das
Zeugs ist ja sowieso alles voneinander abgeleitet bzw. irgendwo vererbt.
Helge Schick schrieb:> Man muss Textkonstanten explizit in den Flash schreiben, dann geht es.>> Frage gelöst ...
Das wird das Problem lediglich verschoben haben, nur wenn das der
fertige Code ist, dann wäre die Sache erledigt.
Der ATiny85 besitzt 512 Byte SRam, das Programm sieht nicht nach 100
genutzten Bytes SRam aus, keine rekursiven Funktionen, keine Arrays
usw., da bleibt jede Menge für den Stack über.
Wenn so kurzer Code dabei versagt, liegt der tatsächliche Fehler
woanders.
Cyblord ---- schrieb:> Wenn man mit einer Umgebung arbeiten würde, die den statischen SRAM> Verbrauch direkt anzeigt, dann hätte man das sofort gesehen. Aber man> will es sich ja schwer machen.
Das ist natürlich das Totschlagargument gegen Arduino! ;-)
Nicht schlecht, zu welchen Strohhalmen Du manchmal greifst, um mit
diesen dann um Dich zu werfen, wenn all Deine Argumente vorher
entkräftet werden.
Ich teile ja Deine Meinung zu Arduino. Aber diese übermäßige Schimpferei
ist kontraproduktiv. Leben und leben lassen.
Cyblord ---- schrieb:> Moby AVR schrieb im Beitrag #4021145:>> Prinzipiell und wenn man seinen Code 100%ig selbst unter Kontrolle hat>> natürlich nicht. Bei Hochsprachenverwendung ist dann aber doch>> Weil Hochsprachen in Mobys kranker troll Phantasie gerne mal> kilobyteweise Ram belegen, einfach so. Spontan. Kannste nix dagegen> machen. Hilft nur Assembler. iss so.
Nicht kilobyteweise. Aber bei kleinen AVRs (Tiny85 haben gerade 0,5K
SRAM) können auch schon mal wenige dutzend Bytes zuviel sein. Zum
Beispiel durch unnützes Push/Pop... iss so ;-)
MWS schrieb:> Wenn so kurzer Code dabei versagt, liegt der tatsächliche Fehler> woanders.
Unsinn. Hast Du mal die Bytes seiner mehrere Dutzend vielen Strings
zusammengezählt? Da kommen schon ein paar hundert Bytes zusammen.
Frank M. schrieb:> Nicht schlecht, zu welchen Strohhalmen Du manchmal greifst, um mit> diesen dann um Dich zu werfen, wenn all Deine Argumente vorher> entkräftet werden ;-)
Was wird denn da entkräftet? Wie MWS richtig bemerkt, das Problem ist ja
nicht gelöst.
Der dynmische Teil mit Stack und Rekursionen ist bei knappem RAM nochmal
eine Aufgabe für sich. Und mit Arduino nicht zu handeln. Da hilft nur
unmengen am RAM, Augen zu und durch.
Wenn aber noch nichtmal einen Überblick über den einfachen statischen
RAM Verbrauch hat, wie soll man da bitte was vernünftiges zustane
bringen?
>> Ich teile ja Deine Meinung zu Arduino. Aber diese übermäßige Schimpferei> ist kontraproduktiv. Leben und leben lassen.
Nur sieht man hier schön deutlich wo das Problem mit Arduino liegt. Null
Übersicht, null Kontrolle.
Karl Heinz schrieb:> Helge, kannst du dein Programm noch mal posten.> Ich habs wieder mal verbockt.
wollte schon sagen, der code war doch mal da..
gibt es kein Backup?
Peter II schrieb:> Karl Heinz schrieb:>> Helge, kannst du dein Programm noch mal posten.>> Ich habs wieder mal verbockt.>> wollte schon sagen, der code war doch mal da..>> gibt es kein Backup?
Nein, leider nicht. Ich hab keine Chance für einen Undo.
Cyblord ---- schrieb:> Was wird denn da entkräftet? Wie MWS richtig bemerkt, das Problem ist ja> nicht gelöst.
Das sehe ich anders. Er hat das RAM mit weit über 50% Textkonstanten
zugeballert. Das Problem liegt genau da.
Auch diese Arrays könnte man mittels PROGMEM komplett im Flash belassen.
Man müsste sie allerdings mit memcopy_P() vorher einzeln in ein im RAM
befindliches befindliches Array kopieren, bevor man sie mit
lcd.createChar() anwendet.
Spart weitere 8 * 8 = 64 Bytes im RAM - abzüglich des einen RAM-Arrays.
Verbleiben also 56 Bytes Ersparnis.
, aber ist nur ein Teil ...
Danke.
Hab das Original wieder restauriert und oben eingesetzt.
Entschuldigung für die Unannehmlichkeiten.
Eigentlich wollte ich nur die Formatierzeichn ergänzen, als mir die
Arrays aufgefallen sind und da hab ich dann einen Schritt ausgelassen
:-)
Hallo MWS, hallo Karl Heinz,
gute Hinweise, wie verwende ich das F - Macro denn bei Arrays und
einzelnen Byte Deklarationen? Weder bei der Deklaration ( byte
ch_tiny2[8] ... ) noch bei der Übernahme ( lcd.createChar(2, ch_tiny2);
) kann ich es verwenden.
Frank M. schrieb:> Unsinn. Hast Du mal die Bytes seiner mehrere Dutzend vielen Strings> zusammengezählt? Da kommen schon ein paar hundert Bytes zusammen.
Nun, da täuscht Du Dich ein ganz klein wenig.
Ein:
1
lcd.print(" ready, press ");
dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press
" dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den
String aus dem Flash für die Ausgabe in's SRam zu kopieren.
Die Anweisung F("...") dürfte also lediglich den Ausgabepuffer und auch
das Umkopieren sparen, die Ausgaberoutine gibt dann direkt aus dem Flash
wieder.
Das deckt sich mit dem hier, ganz unten:
http://forum.arduino.cc/index.php?topic=111131.0
Die "mehrere Dutzend vielen Strings" muss ich also nicht zusammenzählen,
denn die finden sich nicht als selbstständige Variablen wieder.
Also nicht Unsinn ;-)
>> Auch diese Arrays könnte man mittels PROGMEM komplett im Flash belassen.> Man müsste sie allerdings mit memcopy_P() vorher einzeln in ein im RAM> befindliches befindliches Array kopieren, bevor man sie mit> lcd.createChar() anwendet.
Hmm.
Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.
Immerhin muss der COmpiler ja auch bei
1
lcd.print(F("PCF8574 @: "));
damit klar kommen, dass er einen Pointer auf einen String im Flash
kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine
print Methode geben, die auf Pointer ins Flash 'reagiert'.
>> dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press> " dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den> String aus dem Flash für die Ausgabe in's SRam zu kopieren.
Falsch. Alle Stringkonstanten werden von der StartUp-Routine ins RAM
kopiert. Sowohl bei Arduino als auch bei nackter Verwendung der
avr-libc.
Das hat auch nichts mit Arduino, sondern mit der Harvard-Struktur der
AVRs zu tun.
Karl Heinz schrieb:> Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.> Immerhin muss der COmpiler ja auch bei>
1
>lcd.print(F("PCF8574 @: "));
2
>
> damit klar kommen, dass er einen Pointer auf einen String im Flash> kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine> print Methode geben, die auf Pointer ins Flash 'reagiert'.
Ja, das scheint eine simple Überladung von print() zu sein.
Karl Heinz schrieb:> Verblüfft mich, dass es da am Arduino noch keine andere Lösung gibt.> Immerhin muss der COmpiler ja auch bei>
1
>lcd.print(F("PCF8574 @: "));
2
>
> damit klar kommen, dass er einen Pointer auf einen String im Flash> kriegt und die entsprechende print Methode raussuchen. Ergo muss es eine> print Methode geben, die auf Pointer ins Flash 'reagiert'.
Ahhh.
Die benutzen eine Zwischenklasse _FlashStringHelper um die korrekte
Methode anzusprechen. Ja, dann ist es klar wie das funktioniert.
Das F Makro legt den String mittels PSTR in den Flash und castet den
Pointer um auf einen _FlashStringHelper Pointer. Und dafür gibt es eine
print Methode.
Wenns für createChar keine entsprechende Methode gibt (und das bezweifle
ich mal), dann gehts momentan nur mit dem pgm_xxxx Funktionen.
Karl Heinz schrieb:> Wenns für createChar keine entsprechende Methode gibt (und das bezweifle> ich mal), dann gehts momentan nur mit dem pgm_xxxx Funktionen.
Die scheint es nicht zu geben. Wenn man im Netz nach "createChar
PROGMEM" sucht, machen die das alle mit den pgm_xxx()-Funktionen - oder
halt mit memcpy_P(). Das tuts auch.
@MWS
>dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press
Wenn es wirklich einen entsprechenden Algorithmus gibt, müsste ja der
Compiler einen Parser-Abschnitt enthalten, der nach dem Motto: "Wer hat
den Längsten" den Source-Code durchforstet, um dann, anhand dieses
Wertes, einen Speicherbereich vor dem Benutzer zu "verstecken".
Kann ich mir, auch wegen der vielen Nebeneffekte nicht vorstellen.
Zwei einfache Gleichungen bleiben aber erhalten:
1. Dein Code (+) die Bibliotheken (=) viel mehr Code.
2. Dein RAM (+) die Bibliotheken (=) viel mehr RAM.
MWS schrieb:> Nun, da täuscht Du Dich ein ganz klein wenig.>> Ein:>
1
lcd.print(" ready, press ");
>> dürfte auch in Arduinisch keine extra Variable mit Inhalt " ready, press> " dauerhaft im SRam anlegen. Da wird nur temporär SRam verwendet, um den> String aus dem Flash für die Ausgabe in's SRam zu kopieren.
Hier der Beweis, dass alle Stringkonstanten schon beim Boot im RAM
landen:
1
#include<avr/io.h>
2
3
// dieses print() ist ein disfunktionales Fake, dient nur dazu, dass der Compiler nichts wegoptimieren kann
4
voidprint(char*s)
5
{
6
while(*s)
7
{
8
PORTB=*s++;
9
}
10
}
11
12
intmain(void)
13
{
14
while(1)
15
{
16
print("Hello");
17
print("World");
18
}
19
}
Übersetzt mit avr-gcc und avr-libc:
Program: 198 bytes (1.2% Full)
(.text + .data + .bootloader)
Data: 12 bytes (1.2% Full)
(.data + .bss + .noinit)
Und hier ein Auszug der lss-Datei dazu:
1
00000074 <__do_copy_data>:
2
74: 11 e0 ldi r17, 0x01 ; 1
3
76: a0 e0 ldi r26, 0x00 ; 0
4
78: b1 e0 ldi r27, 0x01 ; 1
5
7a: ea eb ldi r30, 0xBA ; 186
6
7c: f0 e0 ldi r31, 0x00 ; 0
7
7e: 02 c0 rjmp .+4 ; 0x84 <__do_copy_data+0x10>
8
80: 05 90 lpm r0, Z+
9
82: 0d 92 st X+, r0
10
84: ac 30 cpi r26, 0x0C ; 12
11
86: b1 07 cpc r27, r17
12
88: d9 f7 brne .-10 ; 0x80 <__do_copy_data+0xc>
13
8a: 0e 94 4b 00 call 0x96 ; 0x96 <main>
14
8e: 0c 94 5b 00 jmp 0xb6 ; 0xb6 <_exit>
Bevor die main-Funktion angesprungen wird, werden 12 Bytes ins RAM
kopiert. Dreimal darfst Du raten, woher die 12 Bytes kommen und was
passiert, wenn ich eine weitere (abweichende) Stringkonstante hinzufüge.
P.S.
Strings, die den gleichen Inhalt haben, werden übrigens vom gcc auf
eine Stringkonstante reduziert. Wenn Du also 28 mal hintereinander
schreibst:
print ("Hello");
...
print ("Hello");
werden im RAM trotzdem nur 6 Bytes benutzt. Sobald die Stringkonstanten
abweichen, greift diese Optimierung natürlich nicht mehr.
Peter II schrieb:> Es gibt keine wirklichen Zusammenhang zwischen Flash und Ram verbrauch.> Man kann 8kb Flash nutzen und nur 10byte Ram, oder auch 10byte Flash und> 8kb RAM.
Natürlich gibt es keinen mathematisch im Sinne eine Funktion faßbaren
Zusammenhang.
Aber es gibt sehr wohl einen statistisch überaus signifikanten
tendenziellen Zusammenhang zwischen Codegröße und RAM-Nutzung und dies
quer über alle Programmiersprachen und CPU/µC-Architekturen.
Was meinst du wohl, wo z.B. der über alle AVR-Baureihen zu beobachtende
Fakt herkommt, dass bei Teilen mit größerem Flash i.d.R. auch mehr RAM
zur Verfügung gestellt wird. Das ist nichts anderes als die Konsequenz,
die die Atmel-Entwickler und Marketingstrategen aus diesem allgemeinen
statistisch gesicherten Zusammenhang gezogen haben.
Von diesem allgemeinen Zusdammenhang mal abgesehen: Der Füllgrad des
Flash an sich kann keine Probleme hervorrufen, wie sie der OP beobachtet
hat, das kann nur stärkere RAM-Nutzung durch den zusätzlichen Code.
Oder natürlich ein Fehler im hinzugefügten Code, das wäre genauso
möglich.
Frank M. schrieb:> Und hier ein Auszug der lss-Datei dazu:
Hab's mir selbst kompiliert, simuliert, bzw. das erzeugte ASM angesehen,
schönes Glump ;D (Ohne jetzt hier einen Flamewar lostreten zu wollen)
Frank M. schrieb:> Das hat auch nichts mit Arduino, sondern mit der Harvard-Struktur der> AVRs zu tun.
Es mag schon sein, dass die Beachtung der Architektur und strikte C'sche
Logik zu solchen Kapriolen führt, aber bezogen auf einen 8-Bit AVR ist
das völliger Krampf.
Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash
genauso zugegriffen werden, wie es über's SRam geschieht.
Auch ist der String konstant, eine Veränderung ist weder zulässig noch
möglich und damit ist dieses Verhalten doch eher peinlich. Hab' mir
solch dieses Verhalten des gcc tatsächlich nicht vorstellen können, aber
wieder etwas dazugelernt, danke dafür.
@MWS (Gast)
>Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash>genauso zugegriffen werden, wie es über's SRam geschieht.
Falsch! Dazu braucht der AVR verschiedene Befehle! Ein lds ist kein
lpm!
ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl
Flash-Konstanten und RAM Variablen über ein und die selbe Funktion
verarbeitet werden. Das könnte man auch in den Arduion einbauen.
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_flash_und_Embedded-C
Abschnitt Jenseits von __flash, man muss die Daten mit __memx
platzieren.
MWS schrieb:> Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash> genauso zugegriffen werden, wie es über's SRam geschieht.
Nein. Lies mal http://www.atmel.com/images/doc0856.pdf. Der Zugriff auf
SRAM (Data space) und der Zugriff auf Flash (Program memory)
unterscheiden sich auf Assembler-Ebene.
Der gcc-Compiler bildet das über progmem und die pgm_xxx-Routinen ab.
Siehe http://www.nongnu.org/avr-libc/user-manual/pgmspace.html.
LG, Sebastian
Hallo Helge,
Helge Schick schrieb:> die Meldung> Binäre Sketchgröße: 3.368 Bytes (von einem Maximum von 8.192 Bytes)> stammt aus der Arduino IDE nach dem upload.
Das ist nur der Flash-Speicherverbrauch. Es ist ein Ärgernis, dass die
Arduino-IDE nicht auch den statischen SRAM-Speicherverbrauch listet.
Aber der lässt sich wie folgt ermitteln: In der Arduino-IDE unter
Datei->Einstellungen ist unten der Speicheort der preferences.txt
angegeben. Kann man auch anklicken, öffnet den Speicherort. Nun die
Arduino-IDE beenden, dann die preferences.txt öffnen, und dort die Zeile
1
build.verbose=true
einfügen. Speichern. Nun die Arduino-IDE wieder öffnen. Jetzt sollten
alle avr-gcc,avr-g++, avr-ar, avr-objcopy etc. Befehle die die IDE
absetzt, sowie deren Fehlerausgaben, angezeigt. Die letzte Zeile beim
Verifizieren lautet zum Beispiel:
Jetzt ein Terminal öffnen, ins Verzeichnis
C:\Users\SEBAST~1\AppData\Local\Temp\build8114256259554875073.tmp
wechseln, und dort "C:\Program Files
(x86)\Arduino\hardware\tools\avr\bin\avr-size" porta_100khz.cpp.elf
eingeben.
Dann erhält man die Größen der .text, .data und .bss-Segmente. .data und
.bss zusammen sind der statisch belegte SRAM-Speicher.
LG, Sebastian
Hallo Sebastian,
habs noch nicht ausprobiert, klingt jedenfalls interessant. Für dieses
Problem habe ich ein paar Codezeilen aus der adafruit Doku übernommen,
die zeigen mir den noch vorhandenen Heap/Stack RAM auf dem Display an:
Übrigens hat der Tip von Frank wirklich Abhilfe geschaffen, der SRAM ist
mit dem F-Macro wie geputzt und wird kaum noch in Anspruch genommen. Nur
die Arrays bekomme ich nach PROGMEM noch nicht wieder ausgelesen. Meine
eigenen Character bleiben verschollen ...
Und über die Fragmentierung des Heap mache ich mir gerade einige
Gedanken, da ist wohl noch Optimierung nötig!
Gruss, Helge
Hallo Sebastian,
da bekomme ich:
C:\DOKUME~1\Helge\LOKALE~1\Temp\build5088002893342191290.tmp>(x86)\Ardui
no\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf
"\Arduino\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf"
ist syntaktisch an dieser Stelle nicht verarbeitbar.
Gruss, Helge
> ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl> Flash-Konstanten und RAM Variablen über ein und die selbe Funktion> verarbeitet werden. Das könnte man auch in den Arduion einbauen.
Arduino ist doch C++, oder? Da gibt es leider _flash, usw. nicht.
Helge Schick schrieb:> C:\DOKUME~1\Helge\LOKALE~1\Temp\build5088002893342191290.tmp>> (x86)\Arduino\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf> "\Arduino\hardware\tools\avr\bin\avr-size" _04_tiny_computer.cpp.elf"> ist syntaktisch an dieser Stelle nicht verarbeitbar.
Da fehlt noch was an der Kommandozeile.
So sieht das bei mir als Beispiel aus:
Helge Schick schrieb:> Nur die Arrays bekomme ich nach PROGMEM noch nicht wieder ausgelesen. Meine> eigenen Character bleiben verschollen ...
Das sollte so gehen:
Falk Brunner schrieb:> @MWS (Gast)>>>Auf eine Stringkonstante wie "Hello" kann über Zeiger auf den Flash>>genauso zugegriffen werden, wie es über's SRam geschieht.>> Falsch! Dazu braucht der AVR verschiedene Befehle! Ein lds ist kein> lpm!
LOL, Du darfst schon voraussetzen, dass mir der Unterschied bekannt ist,
die Betonung lag auf "Zeiger".
Dass aufgrund von irgendwelchen Kontinuitätsgründen von C dieser
Superkrampf passiert, ist mir mittlerweile schon klar.
Dennoch, lass mal diese ganzen Zwänge von C beiseite, es wäre logisch,
wenn konstante Strings, die sich im Flash befinden, auch aus diesem
bedient werden und nicht das SRam sinnlos vollgemüllt wird.
Das ist etwas, das ich von einem modernen Compiler erwarte und deswegen
war ich auch baff, als ich das Gegenteil erkennen musste.
Und wenn Du mir schon mit LDS und LPM kommst, dann muss ich Dir sagen,
dass das Äquivalent zu LPM der Opcode LD und nicht LDS ist ;-)
MWS schrieb:> Das ist etwas, das ich von einem modernen Compiler erwarte und deswegen> war ich auch baff, als ich das Gegenteil erkennen musste.
Wenn der Flash-Speicher nicht durch die Hardware auf SRAM-Adressen
gemappt wird ist das gar nicht so einfach.
Ein Beispiel: Du speicherst die Adresse eines Flash-Strings in einer
Variablen. Diese Variable (ein "Zeiger") muss dann aber einen anderen
Typ haben als eine andere Variable, die eine Adresse im SRAM enthält.
Aber welchen?
Dann brauchst du für die Stringprozeduren in der Standard-Bibliothek
jeweils mehrere Versionen, solche mit normalen SRAM-Zeigerparametern,
und solche mit Flash-Zeigerparametern.
Man kommt da vom Hölzchen aufs Stöckchen.
LG, Sebastian
Sebastian Wangnick schrieb:> Wenn der Flash-Speicher nicht durch die Hardware auf SRAM-Adressen> gemappt wird ist das gar nicht so einfach.>> Ein Beispiel: Du speicherst die Adresse eines Flash-Strings in einer> Variablen. Diese Variable (ein "Zeiger") muss dann aber einen anderen> Typ haben als eine andere Variable, die eine Adresse im SRAM enthält.
Es behauptet niemand, dass es einfach sein muss.
Dem Compiler ist der Typ, ob Variable oder Konstante zur Compilezit
bekannt, der muss dann halt die Zugriffe in entsprechenden Routinen
kapseln. Schafft er ja auch dann, wenn er mit Progmem dazu gezwungen
wird.
Dieses Interface zum Flash über Progmem wirkt drangepfriemelt, dennoch
wohl so notwendig, weil der Compiler offenbar aufgrund seiner Herkunft
aus anderer Architektur, diejenige des 8-Bit AVR nur mit solchen Krücken
verarbeiten kann. Und dann passiert solcher Unsinn, wie das SRam mit
Konstanten aus dem Flash vollzukleistern.
MWS schrieb:> Dieses Interface zum Flash über Progmem wirkt drangepfriemelt, dennoch> wohl so notwendig, weil der Compiler offenbar aufgrund seiner Herkunft> aus anderer Architektur, diejenige des 8-Bit AVR nur mit solchen Krücken> verarbeiten kann. Und dann passiert solcher Unsinn, wie das SRam mit> Konstanten aus dem Flash vollzukleistern.
Deutlich eleganter wirken __flash und __memx, zeigen aber auch wo der
Hase im Pfeffer liegt: AVRs haben hardwareseitig mehrere Adressräume.
Das hat Folgen.
Entweder beschränkt man sich bei Datenadressierung auf jeweils einen
davon. Dann kann man mit solchen Adressen/Pointern nur Daten in diesem
Adressraum erreichen. Muss sich also entscheiden, ob der Pointer auf RAM
zeigt (normal) und auf ROM (__flash). Eine Funktion, die eine
RAM-Adresse erwartet, kann man dann nicht mit einer ROM-Adresse füttern.
Und umgekehrt.
Oder man lässt das offen und verlangt, dass Pointer auf alles zeigen
können (__memx). Dann aber findet jeder Zugriff über einen solchen
Pointer in einer Laufzeitfunktion statt, in der erst der Adressbereich
festgestellt werden muss. Das ist viel langsamer.
Dieses Problem ist ziemlich wenig von der Programmiersprache abhängig,
solange es sich um eine kompilierte Sprache handelt. Es muss dazu auch
keine expliziten Pointer in der Sprache geben, Referenz-Parameter
reichen schon (Fortran).
Einen anderen - besseren - Weg ist Microchip bei den PIC24 gegangen. Die
blenden in der oberen 32KB Hälfte des Datenadressraumes ROM aus dem
Programmadressraum ein. Wodurch trotz formal getrennter Daten- und
Programmadressräume genug Flash-ROM im Datenadressraum liegt, um die
üblichen Strings dort lassen zu können.
Hallo Sebastian,
hatte ich so schon probiert, allerdings mit sizeof(quelle) statt
sizeof(ziel), also sizeof(ch_up) statt sizeof(create). Warum macht das
einen Unterschied? Sind doch beide gleich gross.
Gruss, Helge
@ Bastler (Gast)
>> ALLERDINGs kann man mittlerweile das so "hintricksen", dass man sowohl>> Flash-Konstanten und RAM Variablen über ein und die selbe Funktion>> verarbeitet werden. Das könnte man auch in den Arduion einbauen.>Arduino ist doch C++, oder?
Naja, ein Leichtgewicht C++.
> Da gibt es leider _flash, usw. nicht.
AFAIK schon, denn der Compiler unten drunter ist auch der avr gcc.
Der GCC läuft aber schon beim leichtesten Hauch von C++ mit eben diesem
Parser und der, dazu gab es schon diverse Diskussionen, wird in
absehbarer Zeit keine getrennten Adressräume unterstützen. Schade um
_flash & co, aber so ist es eben.