Forum: Mikrocontroller und Digitale Elektronik uart ausgabe: Speicherverständnis


von Mike (Gast)


Lesenswert?

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?

von Stefan K. (stefan64)


Lesenswert?

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

von Mike (Gast)


Lesenswert?

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?

von Stefan F. (Gast)


Lesenswert?

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.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Georg G. (df2au)


Lesenswert?

Frank M. schrieb:
> uart_puts_P (PSTR("B

üblicherweise ist uart_puts_P ein Macro und setzt das PSTR selbst ein. 
Du meinst vermutlich uart_puts_p().

von Mike (Gast)


Lesenswert?

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 :)

von Mike (Gast)


Lesenswert?

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:
1
#define uart1_puts_P(__s)       uart1_puts_p(PSTR(__s))

von Cyblord -. (cyblord)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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.

von Mike (Gast)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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.

von Stefan K. (stefan64)


Lesenswert?

>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

von Mike (Gast)


Lesenswert?

Eine Frage habe ich noch:
Macht es einen Unterschied ob ich Variablen ausgebe oder strings?:
1
uart_puts_P("\nStatus: ");
2
uart_puts(utoa(_STATUS_,buffer,10));
Soll/kann ich beides über Progmem ausgeben oder Variablen lieber über 
den SRAM laufen lassen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Mike schrieb:
>
1
uart_puts_P("\nStatus: ");
2
> uart_puts(utoa(_STATUS_,buffer,10));
> 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.

: Bearbeitet durch Moderator
von Mike (Gast)


Lesenswert?

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

von Kirsch (Gast)


Lesenswert?

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
char myFlashString[] __attribute__((progmem)) = "Der String bleibt im Flash";
4
char myRAMString[] = "Der wird am Anfang in den RAM kopiert";
5
.
6
.
7
.
8
uart_puts_p(myFlashString);
9
uart_puts(myRAMString);

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.