mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 CUBEMX und Printf() über UART


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Schorsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Printf() Funktion ist ja wohl sehr begehrt aber irgendwie finde ich 
keine brauchbare lib dazu.

Weiß wer von euch ne gute Quelle?

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Printf ist in der Standard C Library <stdio.h> enthalten.

Damit sie Funktioniert, musst du die folgende C Funktion implementieren. 
Das folgende Beispiel leitet die Ausgaben auf den USB Port. Für serielle 
Ports musst du sie entsprechend umschreiben.
// Redirect standard output to the USB port
int _write(int file, char *ptr, int len)
{
    CDC_Transmit_FS( (uint8_t*) ptr, len);
    return len;
}

: Bearbeitet durch User
Autor: M. H. (bambel2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Damit sie Funktioniert, musst du die folgende C Funktion implementieren.

Das ist aber jetzt schon ein sehr konkretes Beispiel. Der TO hat 
überhaupt nicht geschrieben, wo der Output (stdout) hingehen soll. 
Außerdem muss man dazusagen, dass nicht nur _write, sonder auch andere 
Syscalls benötigt werden. Zum Beispiel _sbrk für den Heap. Das braucht 
dann wiederum den notwendigen Speicherbereich, ggf. Im Linkerskript 
anlegen...

Kenne mich mit CubeMX nicht aus. Bei den einzigen beiden Projekten, die 
ich damit gemacht, äh versucht, habe, musste ich im generierten Code von 
CubeMX Fehler beseitigen. Hätte jetzt gedacht, dass CubeMX eine 
Einstellung hat, wie es den Standardoutput legen soll und dir das dann 
alles richtig hinbastelt.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
M. H. schrieb:
> Das ist aber jetzt schon ein sehr konkretes Beispiel

Darauf habe ich hingewiesen. Unkonkrete Beispiele sind hier unbeliebt.

Entscheidend ist, dass der TO einen kleinen Schubser in die richtige 
Richtung bekommt. Wer AVR kennt, weiß man es dort ganz anders machen 
muss.

> Außerdem muss man dazusagen, dass nicht nur _write, sonder auch andere
> Syscalls benötigt werden. Zum Beispiel _sbrk für den Heap. Das braucht
> dann wiederum den notwendigen Speicherbereich, ggf. Im Linkerskript
> anlegen...

Die werden üblicherweise vom Projektassistenten der IDE angelegt, bzw 
von Cube MX.

> Kenne mich mit CubeMX nicht aus.

Dann laber doch nicht dumm herum. Ich habe das vorher ausprobiert, es 
funktioniert genau so, wie ich es geschrieben habe.

> Hätte jetzt gedacht, dass CubeMX eine Einstellung hat,
> wie es den Standardoutput legen soll und dir das dann
> alles richtig hinbastelt.

Leider nicht.

: Bearbeitet durch User
Autor: pegel (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Mein Liebling ist die sprintf Funktion.
  char Tx_Buffer[64];
  uint8_t Tx_len;

  uint8_t mytext[]="Bereit\r\n";
  
  sprintf(Tx_Buffer,"%s",mytext);
  Tx_len=strlen(Tx_Buffer);

  HAL_UART_Transmit_IT(&huart3,(uint8_t *)Tx_Buffer,Tx_len);

Mit sprintf kann man alles schön formatieren und dann an eine beliebige 
Schnittstelle senden.

z.B. HAL_I2C_Master_Transmit_IT();

oder an cdc, spi, can ....

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
pegel schrieb:
> Mein Liebling ist die sprintf Funktion.

Weil sie so schöne Buffer Overflows produziert? Wenn schon dann bitte 
snprintf ...

Autor: pegel (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Niklas G. schrieb:
> Weil sie so schöne Buffer Overflows produziert?

Ist mir noch nicht passiert.
Aber snprintf geht vermutlich auch.

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
pegel schrieb:
> Ist mir noch nicht passiert.

sprintf ist eine geradezu sprichwörtliche Sicherheitslücke :-) Es gibt 
bestimmt genug IoT-Geräte, welche sich darüber übernehmen lassen...

Autor: jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pegel schrieb:
> Ist mir noch nicht passiert.

Dann hast du damit noch nicht viel gearbeitet.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Wenn ich sprintf benutze, dass weiß ich meistens vorher, wie lang der 
String maximal werden kann. Entsprechend groß lege ich den Buffer aus.

Wenn die Größe nicht vorher festlegen kann, benutze ich snprintf.

Das Einzige Risiko besteht in schlampiger Programmierung.

Autor: pegel (Gast)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
@  Stefanus F.

So sehe ich das auch.

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Das Einzige Risiko besteht in schlampiger Programmierung.

Leider besteht hier ein großes Fehlerpotenzial. Man schätzt die maximale 
Größe schnell mal falsch ein. Da ist es doch viel einfacher, immer 
snprintf+sizeof zu nutzen. Das funktioniert dann auch nach Änderung der 
Puffer-Größe, Format-String oder Eingaben noch. Als schlampige 
Programmierung würde ich es sehen, wenn die Sicherheit der Anwendung 
davon abhängt, ob 3 Faktoren (Array-Größe, Format-String, Eingabe-Daten) 
genau richtig zueinander passen.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
-4 lesenswert
nicht lesenswert
Niklas G. schrieb:
> Man schätzt die maximale Größe schnell mal falsch ein.

Du vielleicht.
Ich schätze nicht, ich weiß genau, wie viel Puffer ich benötige. Wenn 
nicht, benutze ich snprintf und riskiere unvollständige Ergebnisse. Ist 
auch suboptimal.

Niklas G. schrieb:
> Als schlampige Programmierung würde ich es sehen,
> wenn die Sicherheit der Anwendung
> davon abhängt, ob ... Faktoren
> genau richtig zueinander passen.

Ich unterscheide hier zwischen Programmen, die ich voll im Griff habe, 
und andere. Für die anderen Programme ist C ohnehin die falsche Sprache.

: Bearbeitet durch User
Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Ich schätze nicht, ich weiß genau, wie viel Puffer ich benötige.

Ah, wie viel braucht man denn hierfür?
sprintf (buffer, "Hallo %s, deine Note ist %f. Du hast %zu Bytes Speicher verbraucht.\n", userName, mark, memsize);

Wenn das Ergebnis immer vollständig sein muss, nimmt man std::string 
o.ä. sprintf ist hier absolut keine Lösung.

snprintf hat keinerlei Nachteil, ich verstehe nicht warum man auf 
sprintf bestehen würde, selbst wenn es in speziellen Sonderfällen 
korrekt wäre...

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
> Ah, wie viel braucht man denn hierfür?

Dein Code ist unvollständig, daher kann ich Dir diese Frage nicht 
beantworten. Das ist so ein Fall von "wo ich den Code nicht voll im 
Griff habe". Da würde im Zweifelsfall snprintf verwenden.

Strings in String einzufügen ist allerdings ohnehin fragwürdig. 
Wesentlich effizienter wäre die Ausgabe der Teilstrings, insbesondere 
wenn ich extrem lange userNamen erwarte.

"Hallo "
userName
", deine Note ist %f. Du hast %zu Bytes Speicher verbraucht.\n"

> snprintf hat keinerlei Nachteil

Doch, es ist langsamer.

Müssen wir überhaupt über so eine Pillepalle diskutieren? Ich komme mir 
langsam blöd vor, ich habe wichtigere Sorgen.

: Bearbeitet durch User
Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Dein Code ist unvollständig, daher kann ich Dir diese Frage nicht
> beantworten.

Okay, die maximale Länge von userName sei MaxUsernameLength. Mehr muss 
man nicht wissen.

Stefanus F. schrieb:
> Doch, es ist langsamer.

Um wieviel, dass das Risiko akzeptabel ist? Welche printf-Ausgabe ist so 
zeitkritisch, dass es auf das Bisschen ankommt?

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Niklas G. schrieb:
> Um wieviel, dass das Risiko akzeptabel ist?

Es gibt kein Risiko, wenn ich genau weiß, wie lang der String maximal 
werden kann. Ansonsten nutze ich wie gesagt snprintf oder gleich Java.

Du verbeißt Dich da in ein "Problem" das gar nicht existiert, wenn man 
konzentriert arbeitet. Und wenn nicht, dann kann Dich die 
Programmiersprache und solche Konstrukte ohnehin nicht retten. Früher 
oder später baust du irgendwo einen Buffer, Stack oder Heap Überlauf - 
auch mit snprintf.

: Bearbeitet durch User
Autor: Johannes S. (jojos)
Datum:

Bewertung
5 lesenswert
nicht lesenswert
Ja, so stürzten früher ständig die Programme ab weil die Programmierer 
alles im Griff hatten und Schuld war Windows... MS hat extra eine 
Warnung in den Compiler eingebaut um darauf hinzuweisen das diese 
Funktionen unsicher sind. Und Fehler aus überschriebenen Stackvariablen 
sind die schönsten.

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Es gibt kein Risiko, wenn ich genau weiß, wie lang der String maximal
> werden kann.

Wie lang ist er denn jetzt? :-) Steht doch da, ist doch leicht 
erkennbar.

Stefanus F. schrieb:
> Früher
> oder später baust du irgendwo einen Buffer, Stack oder Heap Überlauf -
> auch mit snprintf.

Mit der Einstellung braucht man sich dann auch nicht mehr über 
Sicherheitslücken und instabile Software beschweren.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Mit deinem snprintf tauschst du nur einen potentiellen Fehler gegen 
einen anderen aus. Jetzt bekommst du zwar garantiert an dieser Stelle 
keinen Pufferüberlauf, dafür bekommst du eine unvollständige Ausgabe. 
Auch das ist ein Fehler, der nicht vorkommen darf.

Wenn schon, dann begrenzt du bei der Ausgabe die Länge des Namens, dann 
hast du wieder eine berechenbare Puffergröße. Oder du splittest es wie 
bereits empfohlen auf drei Teilstrings auf.

Oder du machst den Puffer einfach groß genug:

char buffer[n+MaxUsernameLength];

n darfst Du Dir selber ausrechnen.

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> n darfst Du Dir selber ausrechnen.

Du gibst also auf. War wohl doch nicht so einfach. Noch eine 
Einschränkung habe ich tatsächlich vergessen: mark liege zwischen 1.0 
und 5.0.

Stefanus F. schrieb:
> der nicht vorkommen darf.

Dieser Fehler kann nur verärgerte Nutzer, aber kein übernommenes und für 
illegale Aktivitäten genutztes System zur Folge haben.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du gibst also auf.
Ich habe anderes zu tun als diese bescheute Diskussion. Jetzt mach ich 
wirklich Schluss.

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Jetzt mach ich
> wirklich Schluss.

Ok. Dann gebe ich für die Zuschauer zuhause selbst die Lösung:

Die Länge des Puffers muss man korrekterweise so berechnen:
char buffer [62 + MaxUsernameLength + 8 + (CHAR_BIT * sizeof (size_t) * 10 + 32) / 33]];
sprintf (buffer, "Hallo %s, deine Note ist %f. Du hast %zu Bytes Speicher verbraucht.\n", userName, mark, memsize);

Das ist allerdings aufgerundet, in Randfällen ist es ggf. ein Byte zu 
viel. Exakt muss man es mit dem Taschenrechner machen.
Wem das zu umständlich ist, nimmt snprintf:
char buffer [100];
snprintf (buffer, sizeof(buffer), "Hallo %s, deine Note ist %f. Du hast %zu Bytes Speicher verbraucht.\n", userName, mark, memsize);
Hier kann zwar Text abgeschnitten werden, das ist aber keine 
Sicherheitslücke und daher deutlich weniger schlimm.

Falsch hingegen ist:
char buffer [80 + MaxUsernameLength];
sprintf (buffer, "Hallo %s, deine Note ist %f. Du hast %zu Bytes Speicher verbraucht.\n", userName, mark, memsize);
Dies wird spätestens bei der Portierung auf eine 64bit-Plattform zu 
Problemen führen.

: Bearbeitet durch User
Autor: Johnny B. (johnnyb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M. H. schrieb:
> Kenne mich mit CubeMX nicht aus. Bei den einzigen beiden Projekten, die
> ich damit gemacht, äh versucht, habe, musste ich im generierten Code von
> CubeMX Fehler beseitigen.

War das eine Aspach-Uralt Version?
Ich bekam von CubeMX bis jetzt immer lauffähigen Code, sogar mit 
umfangreicheren Sachen wie FreeRTOS und USB.
Man muss darauf achten, dass man eine möglichst aktuelle Version 
verwendet und wenn möglich eine direkt unterstützte Entwicklungsumgebung 
wie z.B. TrueSTUDIO, SW4STM32, IAR, ...

> Hätte jetzt gedacht, dass CubeMX eine
> Einstellung hat, wie es den Standardoutput legen soll und dir das dann
> alles richtig hinbastelt.

Bei der riesigen Anzahl an Kommunikationsmöglichkeiten, die ein STM32 
hat, wäre das dann vielleicht doch ein wenig zuviel verlangt.

Autor: M. H. (bambel2)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Johnny B. schrieb:
> War das eine Aspach-Uralt Version?
> Ich bekam von CubeMX bis jetzt immer lauffähigen Code, sogar mit
> umfangreicheren Sachen wie FreeRTOS und USB.

War vor ca. einem Jahr. Habe versucht etwas mit I2S und USB zu basteln. 
CubeMX hat in der Clock Initialisierung ein ODER (|) in der Zuweisung 
vergessen. Also statt clock->register |= mask nur ein = gehabt. Habe ca. 
ne Stunde den Code gedebuggt, um das zu finden. Habe den Fehler 
gemeldet, genauso wie die fehlerhaften Linkerskripte. Kann sein, dass 
sie es repariert haben. Habe seitdem nichts mehr versucht. Die 
Linkerskripte sind glaube ich immernoch fehlerhaft und funktionieren 
nur, weil der STM auch Speicher hat, der im Datenblatt als "reserved 
area" gelistet ist.

Das ist der Thread: Beitrag "SRAM Lücke STM32Fxxx, Linkerskripte falsch"
Vorallem schön, wenn man das produktiv für sichere Sachen nutzt :D


Johnny B. schrieb:
> Bei der riesigen Anzahl an Kommunikationsmöglichkeiten, die ein STM32
> hat, wäre das dann vielleicht doch ein wenig zuviel verlangt.

Keineswegs. Das Tool kann mir nen Heap automatisch basteln und tut auch 
sonst so als wäre es die ultimative Lösung, dann wird es mir auch 
generieren können, dass ich stdout auf eine aktivierte streamingfähige 
Schnittstelle lege.

Stefanus F. schrieb:
> Dann laber doch nicht dumm herum. Ich habe das vorher ausprobiert, es
> funktioniert genau so, wie ich es geschrieben habe.

Ich wollte nur darauf hinweisen, dass das einfügen der von dir 
geposteten Funktion nicht magisch dazu führt, dass es geht.

: Bearbeitet durch User
Autor: Schorsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hatte die printf funktion erfolgreich zum laufen gebracht, jedoch bei 
einem neuen Projekt werden Bytes Verschluckt.

Uart1 auf printf:

int _write(int file, char *ptr, int len)
{
  HAL_UART_Transmit_IT(&huart1, (uint8_t*) ptr, len);
        return len;
}

Hauptprogramm:

while (1)
  {
    printf("STM32 Glump Test mit UART \r\n");
    printf("ABCDEF1234567890 \r\n");
    HAL_Delay(50);

  }

Kommt nur noch das raus am Terminal:

SBCDEF1234567890
t UART
SBCDEF1234567890
t UART
STCDEF1234567890
t UART
STCDEF1234567890
t UART

Beim vorherrigen Projekt war es kein Problem zweimal direckt 
hintereinander Print zu machen. Was kann das sein?

Autor: Bauform B. (bauformb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schorsch schrieb:
> Was kann das sein?

Ein Hardware Abstraction Layer, programmiert von der Marketing Abteilung 
von ST? HAL_UART_Transmit_IT() funktioniert offenbar nicht (na gut: 
nicht so, wie man es erwartet).

Das erste printf() kopiert den Text in einen Puffer und ruft HAL... auf. 
Das kehrt zurück während das UART das erste 'S' ausgibt. Das erste 
printf() hat nichts weiter zu tun und kehrt auch zurück. Jetzt kopiert 
das zweite printf() seinen Text in den gleichen Puffer und überschreibt 
damit den ersten Text von 'S' bis zum 'i' vom "mit".

Irgendwann wird das UART mit dem 'S' fertig und gibt das nächste Zeichen 
aus. Das ist inzwischen nicht mehr das 'T' vom ersten Text sondern das 
'B' vom zweiten.

Normal wäre jetzt "man HAL_UART_Transmit_IT" angesagt...

Beitrag #5692423 wurde vom Autor gelöscht.
Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vor dem Senden eines neuen Strings musst du daher warten, bis der 
vorherige Sendevorgang abgeschlossen ist. Ausserdem kannst du keine 
Strings senden, die länger sind, als der Puffer.

Manchmal ist es doch besser, solche Dinge selbst zu programmieren. In 
diesem Fall mit einem Ringpuffer und ggf. einer Warteschleife, falls der 
Puffer nicht ausreicht (so wie Arduino es macht).

: Bearbeitet durch User
Autor: Schorsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So in der art hab ich mir das Problem auch vorgestellt.
Allerdings hätte ich gedacht/erwartet dass erst nach dem fertig 
Raussenden wieder ins Programm zurückgekert wird.

Zum Lösungsansatz:

Wie mache ich dass am einfachsten mit einem Ringpuffer?

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schorsch schrieb:
> Allerdings hätte ich gedacht/erwartet dass erst nach dem fertig
> Raussenden wieder ins Programm zurückgekert wird.

Du hast aber die Interrupt-gesteuerte Variante (mit "IT") verwendet. 
Wenn diese Funktion den Programmablauf blockieren würde, wäre sie im 
Verglich zu Version ohne "IT" sinnlos.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie mache ich dass am einfachsten mit einem Ringpuffer?

Schau erst einmal in der HAL Doku ob die etwas dazu hergibt.

Der Punkt ist, dass der Ringpuffer in der ISR entsprechend programmiert 
werden muss. Wenn die HAL das nicht drin hat, musst du zumindest an 
dieser Stelle auf die HAL verzichten. Willst du das? Wohl kaum.

Wenn du warten willst, solltest du am besten einfach die andere Variante 
ohne "IT" verwenden.

Wenn du nicht warten willst, kopiere den String in einen Puffer und 
beauftrage die HAL, diesen zu senden. So ungefähr stelle ich mir das 
vor:
volatile int txComplete=1;
volatile uint8_t txBuffer[200];

void HAL_UART_TxCpltCallback (UART_HandleTypeDef *huart)
{
  txComplete=1;
}

int _write(int file, char *ptr, int len)
{
  // wait until the buffer is free
  while (!txComplete); 
  
  // mark the buffer as "in use"
  txComplete=0;

  // copy the string into the buffer (with size limit)
  if (len>sizeof(buffer)) { 
    len=sizeof(buffer)
  }
  memcpy(buffer,ptr,len);

  // send the buffer
  HAL_UART_Transmit_IT(&huart1, buffer, len);

  return len;
}

Bei diesem Code dürfen die Strings nicht grösser sein, als der Puffer. 
Du könntest zu grosse Strings in mehrere Teilstücke zerlegen.

Mit ein bisschen Nachdenken kannst du diesen Ansatz auf zwei Puffer 
ausbauen, die wechselweise verwendet werden. Dadurch reduzieren sich die 
Wartezeiten weiter so dass es einem Ringpuffer kaum noch nach steht.

: Bearbeitet durch User
Autor: W.S. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Schorsch schrieb:
> Hatte die printf funktion erfolgreich zum laufen gebracht, jedoch bei
> einem neuen Projekt werden Bytes Verschluckt.

Jaja.

Auf dem PC kann man sich dank riesigen RAM's so ziemlich alles erlauben, 
auch printf und Konsorten.

Aber auf einem µC, wo man nur einen recht begrenzten RAM hat, ebenso 
einen im Vergleich zum PC recht kleinen Stack und Heap, da sind 
eigentlich andere Methoden als printf gefragt.

Der ewige Denkfehler beim Benutzen von printf ist, daß man eben immer zu 
allererst RAM für das Aufbauen eines Ausgabe-Blockes benötigt und dann 
einen fetten und oftmals in seiner Größe schwer abschätzbaren Block hat, 
der dann ausgegeben werden soll. Entweder man macht das dann blockierend 
per Polling, oder man braucht nochmals eine noch größere Portion an RAM 
als Zwischenpuffer für den Lowlevel-Treiber.

Das Ganze ist eben sehr RAM-hungrig.. und den RAM hat man hier nicht im 
Überfluß.

Die Lösung wäre, einfach auf printf und all die daran hängenden Dinge zu 
verzichten und die Ausgaben ohne Aufbauen eines Zwischen-Strings zu 
erledigen. Aber das wäre natürlich eine Umgewöhnung beim Programmierer 
und das scheint hier immerzu nur schlecht anzukommen.

Naja - und was man von ST's HAL zu halten hat, da ist meine Ansicht: 
garnix.

W.S.

Autor: W.S. (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Mit ein bisschen Nachdenken kannst du diesen Ansatz auf zwei Puffer
> ausbauen

Hmm.. noch mehr RAM reservieren? Wo du ja in jedem Falle ohnehin warten 
mußt?

W.S.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Hmm.. noch mehr RAM reservieren? Wo du ja in jedem Falle ohnehin warten
> mußt?

Der erste String wird gesendet.
Den zweiten String kann man in den zweiten Puffer legen, ohne zu warten.
Bis der dritte String gesendet werden muss, ist der erste Puffer 
hoffentlich wieder frei.

Das war zumindest die Idee dahinter. Kann man beliebig weiter spinnen - 
bis zum Out of Memory.

Ganz mutige legen unendlich viele Puffer on-demand mit malloc an - ich 
rate davon ab.

Oder man programmiert es mit Ringpuffer, so sparsam wie üblich. Aber die 
HAL hat ihre Prioritäten woanders, wie wir beide wissen.

: Bearbeitet durch User
Autor: Bauform B. (bauformb)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Der ewige Denkfehler beim Benutzen von printf ist, daß man eben immer zu
> allererst RAM für das Aufbauen eines Ausgabe-Blockes benötigt und dann
> einen fetten und oftmals in seiner Größe schwer abschätzbaren Block hat,
> der dann ausgegeben werden soll. Entweder man macht das dann blockierend
> per Polling, oder man braucht nochmals eine noch größere Portion an RAM
> als Zwischenpuffer für den Lowlevel-Treiber.

Ob per Interrupt oder per Polling ausgegeben wird, hat doch nichts mit 
printf zu tun. Für den Interrupt-Luxus muss ich halt RAM spendieren, 
aber printf selbst braucht wenig. Mein printf (von ChibiOS geklaut) 
verwendet einen 12 Byte Puffer auf dem Stack und wahrscheinlich könnte 
man den auch noch sparen.

> Die Lösung wäre, einfach auf printf und all die daran hängenden Dinge zu
> verzichten und die Ausgaben ohne Aufbauen eines Zwischen-Strings zu
> erledigen.

Ich hab es lange Zeit so gemacht. Jetzt mit printf finde ich es 
wesentlich angenehmer. Deine Lösung würde aber auf jeden Fall 
blockieren? Wobei mich das nicht stört, mein printf blockiert auch.

> Aber das wäre natürlich eine Umgewöhnung beim Programmierer
> und das scheint hier immerzu nur schlecht anzukommen.

Natürlich, weil es nur bei extremem Speichermangel nötig ist. Außerdem 
brauchst du wahrscheinlich mehr Flash für viele kleine Funktionsaufrufe.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bauform B. schrieb:
> aber printf selbst braucht wenig

Die printf() Funktion aus der newlib-nano Library belegt 1468 Bytes RAM.

Autor: Bauform B. (bauformb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefanus F. schrieb:
> Bauform B. schrieb:
>> aber printf selbst braucht wenig
>
> Die printf() Funktion aus der newlib-nano Library belegt 1468 Bytes RAM.

Nichts ist so unnütz, dass es nicht als schlechtes Beispiel dienen 
könnte ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.