Hallo zusammen,
ich beschäftige mich aktuell mit uart Ausgaben und benutze für meine AVR
Controller die Lib von Peter Fleury.
Jetzt habe ich eine Frage zu dem Unterschied zwischen folgenden
Ausgaben:
1
uart_puts
vs
1
uart1_puts_P
Der Unterschied hat irgendetwas mit SRAM und Flash zu tun.
Kann mir jemand erklären was die Vor-und Nachteile sind?
Speicherverbrauch?
Gefahr durch Aufhängen? z.B. je größer der String, desto...
Ich habe bis jetzt noch keine Erklärung gefunden, die mir den
Unterschied erläutert.
Wann benutzt man welche Form?
Ohne nachgeschaut zu haben:
uart_puts gibt einen String im RAM aus,
uart1_puts_P gibt einen String aus dem Flash aus (_P für Program
memory)
Gruß, Stefan
Stefan K. schrieb:> uart_puts gibt einen String im RAM aus,> uart1_puts_P gibt einen String aus dem Flash aus (_P für Program> memory)
Das habe ich auch gelesen, steht auch zur Erklärung in der uart.h
Aber damit kann ich nicht wirklich etwas anfangen. Ich stecke nicht so
im Detail. Welche Auswirkungen hat was?
Der Unterschied ist, auf welchen Speicher der Pointer zeigt.
Man kann mit einer Funktion nicht beide Speicher abdecken, weil siech
deren Adressen überlappen und sie außerdem mit unterschiedlichen
Assembler-Befehlen angesprochen werden müssen.
Mike schrieb:> Kann mir jemand erklären was die Vor-und Nachteile sind?
Normale Zeichenketten (Strings) werden - zur Startzeit ins RAM geladen.
Wenn Du viele Ausgaben machst, wie z.B.
1
uart_puts("Bitte geben Sie einen String in Kleinbuchstaben, mindestens aber siebenhundertvierundachtzig Millionen Zeichen ein!");
... dann ist ruckzuck Dein RAM verbraucht.
Wenn Du aber das Macro PSTR(s) verwendest, dann verbleibt der String als
Konstante im Flash.
Dann musst Du aber schreiben:
1
uart_puts_P(PSTR("Bitte geben Sie einen String in Kleinbuchstaben, mindestens aber siebenhundertvierundachtzig Millionen Zeichen ein!"));
... da der Übergabeparameter hier ein anderer ist. uart_puts_P()
erwartet einen String mit der Adresse im Flash statt im RAM. Das normale
uart_puts() erwartet jedoch eine Pointer, der auf die Adresse im RAM
zeigt.
Und schon sparst Du viele Bytes des doch immer knapp bemessenen RAMs.
Frank M. schrieb:> Und schon sparst Du viele Bytes des doch immer knapp bemessenen RAMs.
Die Erklärung ist doch schon mal gut.
Vielen Dank dafür.
Gibt es da auch unterschiede im Ablauf?
Besteht die Gefahr, dass sich bei langen Zeichenketten die eine Version
aufhängt, während die andere Version stabiler läuft?
Für mich klingt es im Moment so, dass die Flash Variante die bessere
ist.
- Es wird kein SRAm "verbraucht"
- solch ein unveränderlicher String im Flash ist doch als konstante
prima aufgehoben :)
Georg G. schrieb:> blicherweise ist uart_puts_P ein Macro und setzt das PSTR selbst ein.> Du meinst vermutlich uart_puts_p().
Wie gesagt, ich benutze die lib von Peter. Darin gibt es folgendes
Macro:
Mike schrieb:> Frank M. schrieb:>> Und schon sparst Du viele Bytes des doch immer knapp bemessenen RAMs.>> Die Erklärung ist doch schon mal gut.> Vielen Dank dafür.>> Gibt es da auch unterschiede im Ablauf?> Besteht die Gefahr, dass sich bei langen Zeichenketten die eine Version> aufhängt, während die andere Version stabiler läuft?
Du immer mit deinem "aufhängen". Wo soll sich das was aufhängen? Bitte
überlege dir erst mal was du eigentlich damit meinst. Überlege dir die
Mechanismen. "Aufhängen" kann sich ein Controller auch nicht wirklich.
Was häufig passiert ist, der Stack und der Heap laufen ineinander. Dann
knallts, weil der Stack Variabeln überschreibt und der Heap sämtliche
Rücksprungadressen und gesicherte Register des Stacks. Aber auch hier
hängt nix, da läuft alles weiter.
Findet aber alles im RAM statt und passiert wenn der Heap zu voll
geballert wird, oder man zuviel schachtelt.
Den Flash kannst du vollknallen bis oben hin.
Also bitte, keine so Allgemeinplätze von denen du selber gar nicht weißt
was gemeint ist.
Der Zugriff aus den Flash Speicher ist deutlich langsamer, als auf's
RAM.
Wenn du schnell ein kurzes "Ok" ausgeben willst, würde ich den Umweg
über PSTR() nicht gehen. Bei längeren Strings aber schon, um RAM zu
sparen.
Cyblord -. schrieb:> Du immer mit deinem "aufhängen". Wo soll sich das was aufhängen? Bitte> überlege dir erst mal was du eigentlich damit meinst. Überlege dir die> Mechanismen. "Aufhängen" kann sich ein Controller auch nicht wirklich.
Sorry, habe mich falsch ausgedrückt.
Habe mal vor geraumer Zeit ein Projekt mit viel uart Ausgaben gehabt.
Ist schon ne Weile her, aber da passierte es oft, dass bei häufigen
Ausgaben mit großen Strings, der Controller neu gestartet ist.
Vermutlich weil es zu Überschreibungen im Speicher gab. Habe immer nur
mit "uart_puts" gearbeitet.
Habe mir damals nichts dabei gedacht und meine strings gekürzt.
Das "aufhängen" habe ich umgangssprachlich benutzt und damit diesen
Neustart gemeint.
Nach diesen Antworten macht es für mich nun mehr Sinn, in Zukunft immer
den Flash Speicher zu nutzen. Da sehe ich erst mal weniger Nachteile.
Sollte es welche geben (außer das der Platz für den code weniger wird),
würde ich das gerne auch noch wissen.
Im Moment nutze ich den uart als debugging Unterstützung.
Mein Verständnis ist auf jeden Fall gewachsen. Soll nicht heißen, dass
ich alles bis auf's kleinste verstanden habe.
Stefan U. schrieb:> Wenn du schnell ein kurzes "Ok" ausgeben willst, würde ich den Umweg> über PSTR() nicht gehen. Bei längeren Strings aber schon, um RAM zu> sparen.
Das ist auch eine nützlicher Hinweis!
Danke
Stefan U. schrieb:> Der Zugriff aus den Flash Speicher ist deutlich langsamer, als auf's> RAM.>> Wenn du schnell ein kurzes "Ok" ausgeben willst, würde ich den Umweg> über PSTR() nicht gehen. Bei längeren Strings aber schon, um RAM zu> sparen.
bei der Ausgabe über UART spielt das fast keine Rolle. Die ist eh noch
viel langsamer.
Flash ist nur 30% langsamer 3 statt 2 Takte zum lesen. Reste müsste
gleich sein.
>Habe mal vor geraumer Zeit ein Projekt mit viel uart Ausgaben gehabt.>Ist schon ne Weile her, aber da passierte es oft, dass bei häufigen>Ausgaben mit großen Strings, der Controller neu gestartet ist.>Vermutlich weil es zu Überschreibungen im Speicher gab. Habe immer nur>mit "uart_puts" gearbeitet.
Da wird Dir wohl der RAM-Speicher ausgegangen sein. Die Abstürze waren
wahrscheinlich weniger auf uart_puts sondern vielmehr auf
Stack-Überläufe zurückzuführen.
Mit Strings im Flash vermeidest Du diese Probleme. Erstens gibt es davon
viel mehr und zweitens kann Flash-Mangel zur Laufzeit nicht zu Abstürzen
führen.
Happy programming, Stefan
> Soll/kann ich beides über Progmem ausgeben oder Variablen lieber über> den SRAM laufen lassen?
Da der Inhalt von Variablen bzw. Funktionsrückgabewerten im RAM liegt,
musst Du hier uart_puts() nehmen.
Frank M. schrieb:> Da der Inhalt von Variablen bzw. Funktionsrückgabewerten im RAM liegt,> musst Du hier uart_puts() nehmen.
Das habe ich mir fast gedacht, war mir aber nicht sicher.
Vielen Dank
Mike schrieb:> Nach diesen Antworten macht es für mich nun mehr Sinn, in Zukunft immer> den Flash Speicher zu nutzen. Da sehe ich erst mal weniger Nachteile.> Sollte es welche geben (außer das der Platz für den code weniger wird),> würde ich das gerne auch noch wissen.
Der String belegt immer Platz im Code (Flash/Program Memmory). Wo soll
er den auch sonst her kommen.
Der Unterschied ist der, das er nicht am Anfang (Vom GCC generierte
Startupcode der vor der Main ausgeführt wird) in den RAM kopiert wird.
Wenn du eine identische Ausgabe mehrmals im Code hast, solltest du sie
als Konstanten anlegen:
1
#include<avr/pgmspace.h>
2
3
charmyFlashString[]__attribute__((progmem))="Der String bleibt im Flash";
4
charmyRAMString[]="Der wird am Anfang in den RAM kopiert";