Hallo
Gibt es Nachteile wenn man xxx.print(F("test")); benutzt?
Hallo
Gibt es Nachteile wenn man xxx.print(F("test")); benutzt?
Es dauert etwas länger, da die Zeichen erst aus dem Flash ins RAM kopiert werden müssen. Bei Serial macht das nichts, da das sowieso zigmal langsamer ist, aber bei Webseiten habe Leute schon geschrieben, dass die Seiten spürbar langsamer aufbauen.
Danke!
Ich wollte das für eine Webseite benutzen weil da Flash drauf geht.
Flash geht immer drauf. Das F() Makro verhindert aber, dass die Strings bei Booten ins RAM kopiert werden.
Muss man ausprobieren. Vielleicht fällt es bei dir auch nicht so auf, oder ist vertretbar.
Serenifly:
Es dauert etwas länger, da die Zeichen erst aus dem Flash ins RAM kopiert werden müssen. Bei Serial macht das nichts, da das sowieso zigmal langsamer ist, aber bei Webseiten habe Leute schon geschrieben, dass die Seiten spürbar langsamer aufbauen.
Bist Du sicher daß die Zeichen zwischenzeitlich ins RAM kommen. F() soll ja genau bei xx.print("text"); den Verbrauch von RAM verhindern.
@Ingo79
Der Text ist immer mit dem Sketch im Flasch Speicher des Controllers abgespeichert. Es gibt beim Arduino keinen anderen Speicher (außer dem von Arduino nicht verwendeten EEPROM) der in Stromlosen Zustand nicht den Speicherinhalt verliert.
Grüße Uwe
Kommt darauf an was da genau gemacht wird. Ich habe mir das noch nicht genau angesehen. Aber bei anderen Progmem Implementierungen wird i.d.R. mindestens ein Zeichen ins RAM kopiert (mit pgm_read_byte). Das heißt ein Zeichen ins RAM kopieren. Das Zeichen ausgeben, und dann das nächste aus dem Flash kopieren. Man muss nicht den ganzen String auf einmal in einen Puffer kopieren (was aber auch praktisch sein kann und je nach Länge der Strings nur vielleicht 20-30 Bytes kostet), aber ich denke mindestens ein Zeichen. Und das kostet natürlich auch Zeit.
Siehe auch die AVR Assembler Op Codes:
Da gibt es nur drei Befehle für lesenden Flash Zugriff, wenn man die Unterscheidung von LMP und ELMP weglässt. Laden in R0. Laden in beliebiges Register. Und Laden in ein Register mit Post-Inkrement. Alle brauchen 3 Taktzyklen.
Wobei da auch das steht:
LD:
Loads one byte indirect from the data space to a register.For parts with SRAM, the data space consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space consists of the Register File only. In some parts the Flash Memory has been mapped to the data space and can be read using this command.
Das impliziert das Teile von RAM und Flash einen gemeinsamen Adress-Raum haben. So genau kenne ich mich da aber nicht aus.
Aber bei der AVR libc steht auch dabei dass Progmem generell Overhead durch die Makros hat:
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
The macros and functions used to retrieve data from the Program Space have to generate some extra code in order to actually load the data from the Program Space. This incurs some extra overhead in terms of code space (extra opcodes) and execution time. Usually, both the space and time overhead is minimal compared to the space savings of putting data in Program Space. But you should be aware of this so you can minimize the number of calls within a single function that gets the same piece of data from Program Space. It is always instructive to look at the resulting disassembly from the compiler.
Den String zeichenweise kopieren und ausgeben ist ja vertretbar solange nicht der ganze String abgespeichert wird und darum Probleme mit dem Speicherbelegung wegen verschieden langer Strings auftreten.
Ich habe mich auch nicht eingelesen aber laut Logik könnte ein kopieren Flash -> Register -> Ausgabe mögliche sein ohne einen Variable im Ram zu benutzen. Ein Buffer ist sicher weniger RAM-fressend als anfangs alle Strings in das RAM zu kopieren.
Grüße Uwe
Wenn man viele Strings hat ist ein größerer Puffer in RAM super. Das ist immer noch weit weniger als wenn man alle Strings im RAM hat.
Ich habe bei mir 31 Byte für einen Puffer reserviert (21 würden vielleicht auch reichen). Dann arbeitete ich mit PSTR() und strcpy_P(), bzw. strncpy_P(). Man kann schon viel machen wenn man weiß wie. Es gibt z.B. auch eine _P Version von sprintf(), was bei längeren Format-Strings nicht schlecht ist.
Das hier geht wie F(), aber mit allen Funktionen, nicht nur dem Arduino print():
const int STRING_BUFFER_SIZE = 31;
char stringBuffer[STRING_BUFFER_SIZE];
#define P(str) strcpy_P(stringBuffer, PSTR(str))
Geht leider nicht mit strncpy_P(), da die n Version die Anzahl der kopierten Bytes zurück gibt und nicht einen Zeiger auf den Puffer. Außerdem garantiert strncpy() keinen Null-terminierten String wenn man die Grenze erreicht hat, also führt das so oder so zu Problemen.
Aber es ist auch nicht schwer einfach bei der Länge aufzupassen. Gerade bei Displays hat man sowieso eine natürliche Grenze nach oben.