Mein Code ist in Bootloader & Application unterteilt, in der Application
funktioniert diese Ausgabe auch ohne Problem, beim Compilieren des
Bootloader erscheint jedoch folgende Fehlermeldung:
Bootloader.elf section `.text' will not fit in region `rom'
region `rom' overflowed by 6932 bytes
Wenn ich nun vprintf(buffer,args) auskommentiere, erscheint dieser
Fehler nicht mehr; jedoch habe ich dann natürlich auch keine Ausgabe
mehr...
Die Größe des Bootloader ist leider im Maximum, somit kann ich diesen
nicht mehr erweitern.
Die Frage lautet also:
Wie bekomme ich eine Print-Ausgabe im Bootloader Teil hin?
Warum ergibt sich ein so großer Overflow von 6932 bytes bei einfügen der
vprintf-Funktion, ist diese so speicherintensiv?
Vielleicht will mir jemand helfen bei dem Thema ;)
Danke & Grüße
Alexander M. schrieb:> Warum ergibt sich ein so großer Overflow von 6932 bytes bei einfügen der> vprintf-Funktion, ist diese so speicherintensiv?
Wäre natürlich gut, du würdest die Architektur und vielleicht auch deine
Bootloader-Größe mal dazu schreiben.
Generell: printf muss Vorkehrungen für alle möglichen Konvertierungen
stets vollständig mitschleppen. Schließlich entscheidet sich erst zur
Laufzeit anhand der Format-Strings, welche davon wirklich benötigt
werden.
In größenlimitierten Umgebungen (AVR, aber auch kleine ARMs) gibt es
daher zuweilen mehrere Varianten von printf & Co., bei denen man vorab
unterschiedliche Formatierungsmöglichkeiten (bspw. Gleitkomma)
weggelassen hat. Für eine solche Variante kann man sich entscheiden,
wenn man die entsprechenden Datentypen nicht braucht, aber trotzdem
printf benutzen will.
Ansonsten: halt die Ausgaben auf irgendwas ohne printf umbauen. Weniger
komfortabel, aber meist braucht ein Bootloader ja auch nicht unbedingt
so viel davon.
Alexander M. schrieb:> Was meinst du denn mit "es gibt mehrere Varianten"?
Habe nur noch mit so großen ARMs zu tun, dass mich das dann irgendwann
nicht mehr richtig interessiert hat … ;-)
Ich glaube mich zu erinnern, dass es "i"-Varianten gibt, iprintf und
dergleichen, die habe keine Gleitkommakonvertierungen. Versuch mal,
danach zu gugeln.
Deine Benutzung von snprintf und danach vprintf ist aber etwas seltsam.
Du solltest nur eins brauchen.
Du hast's schön ;)...
Interessant mit dem iprintf, das werde ich mir mal genauer anschauen,
ansonsten gibt's einfach Ausgaben ohne variable Argumente...
- snprintf hab ich verwendet, um einen Buffer-Overflow abzufangen
- vprintf für die Ausgabe
Wie wäre denn dein Vorschlag?
Grüße
Ich will lediglich einen Wrapper bauen für eine printf-Ausgabe.
Dazu soll der das Argument fmt mein String sein, und anschließend eben
die variablen Argumente. Alles andere Parameter werden "im Hintergrund"
bereits eingefügt.
Beispiel:
vprintf benötigt aber auch einen eigenen fmt & Argumente, deshalb muss
ich m.M.n. im snprintf diesen neuen fmt "neu konfigurieren". Das 2.
Argument sind dann eben die variablen Argumente vom 1. fmt.
Die Zeichenketten kannst du einzeln ausgeben, dann brauchst du keinen so
großen Buffer.
Die Integer Zahl kannst du mit atoi() in eine Zeichenkette umwandeln.
atoi() ist wesentlich schlanker, als printf().
Du hast da auch noch einen beträchtlichen Overhead durch die Verwendung
der File/Stream Funktionen. Kannst du nicht direkt (z.B. auf einen
seriellen port) ausgeben?
stdio puffert ja sowieso alles bis zum \n.
Die Frage ist halt, was deine Aufrufer alles an tatsächlichen Argumenten
übergeben können müssen. Ggf. lässt es sich ja ohne printf erledigen.
ps: die Umwandlung von _LINE_ in einen String sollte sich mit
Präprozessormitteln erledigen lassen.
Stefan ⛄ F. schrieb:> Die Integer Zahl kannst du mit atoi() in eine Zeichenkette umwandeln.> atoi() ist wesentlich schlanker, als printf().>
Nee, ist klar...
John Doe schrieb:> Stefan ⛄ F. schrieb:>> Die Integer Zahl kannst du mit atoi() in eine Zeichenkette umwandeln.>> atoi() ist wesentlich schlanker, als printf().> Nee, ist klar...
Ach Scheiße. Ich meinte natürlich itoa().
Was meintet ihr mit itoa / Umwandlung von _LINE_, das hab ich ehrlich
gesagt noch nicht verstanden..
Warum sollte ich das machen? Verringert sich dadurch die Laufzeit?
Wie soll das dann gehen? Bei mir klappt's aktuell noch nicht wirklich
Dein numerisches Argument "Nummer der Zeile in der Datei" wurde also
schon durch den Präprozessor in einen String umgewandelt, und alles, was
du als Backend zur UART noch brauchst, ist eine Funktion, die einen
String ausgibt.
Jörg W. schrieb:> Beispiel: ...
Eben.
Ist mein Reden seit Ewigkeit:
printf sollte man beim µC durch aufgelöste Funktionen ersetzen - und
zwar bereits zur Quellcode-Schreibzeit. Soviel Fleiß sollte sein. Genau
deshalb gibt's bei mir Char_Out, String_Out, Dezi_Out, FF_Out, LongToStr
usw. Spart nicht nur Platz, sondern ist auch schneller, als wenn erstmal
irgend ein Textinterpreter werkeln muß.
Da haste ja tatsächlich was aus der L..... gelernt.
W.S.
Irgendwas stimmt nicht. Die vararg-Versionen (printf, sprintf, etc)
basieren üblicherweise auf den stdarg-Versionen (vprintf, vsprintf,
etc). In anderen Worten: wenn du printf benutzt, benutzt du eh vprintf.
Einige Platformen haben für die String-Varianten (sprintf, vsprintf,
etc) eigene Implementation; die sparsameren aber nicht (z.B. AVR-libc,
da wird ein temporärer "String-Stream" erstellt und dann vfprintf etc
aufgerufen).
Schau dir mal an, was alles dazugelinkt wird - evtl ist es ja auch das
Stream-handling von stdio (Buffering, Ausgabegerätabstraktion, etc) das
durch irgendwas getriggert und dann dazugelinkt wird. In einem
Bootloader braucht man üblicherweise nicht das gesamte Spektrum von
stdio-Features...
[leicht OT und wohl schon oft diskutiert, aber mir fällt es schwer, so
etwas unkommentiert stehen zu lassen ;-)]
> printf sollte man beim µC durch aufgelöste Funktionen ersetzen
Jain. In der Tat gibt es extrem aufgeblähte stdio-Routinen, bei denen
sich die Nutzung auf einem Mikrocontroller so gut wie verbietet. Aber
wenn du z.B. mal einen Blick in die AVR-libc-Implementation wirfst,
wirst du feststellen, dass es auch ziemlich gute und sehr kompakte
Implementation gibt, die man ziemlich bedenkenlos nutzen kann.
> Genau deshalb gibt's bei mir Char_Out, String_Out, Dezi_Out, FF_Out,> LongToStr usw. Spart nicht nur Platz, sondern ist auch schneller,
Sobald man mehr als nur String-Konstanten ausgibt (also etwas wie
Dezi_Out, FF_Out, LongToStr braucht), sollte man sich das mal genauer
anschauen. Evtl stellst du dann sogar fest, dass du mehr Platz brauchst
als printf & Co, insb wenn du die für mehrere Ausgabegeräte brauchst[1].
Was den Platz angeht: bei den Leuten, die um printf herumprogrammieren,
seh ich ständig irgendwelche buffer[200] in denen erstmal alles (mit
viel Kode) zusammengebastelt wird. Was meinst du da zu sparen? RAM
bestimmt nicht und beim ROM hat sich das nach ein paar Ausgaben auch
erledigt - die String-Representation der Ausgabe (z.B. "%d/%x") ist
kompakter als der vergleichbare Maschinenkode.
Geschwindigkeit ist meist eh irrelevant - schnell in dem Buffer
schreiben und dann per Busy-Loop auf die UART schieben?!?
[1] Um die UART beim AVR-libc stdio-fähig zu machen, braucht es gerade
mal dieses bisschen Kode:
Und schon hat man einen Stream namens "uart" den man wie stdin/stdout
benutzen kann. Wenn gewünscht reicht ein weiteres "stdin = stdout =
uart;" aus, um diese UART als Standardein- und ausgabe zu setzen. Kein
Gehampel mit uart_puts, uart_DeziOut, lcd_puts, lcd_DeziOut, LongToStr,
LongToHexStr, IntToHexStr, UShortToStr, ...
W.S. schrieb:> printf sollte man beim µC
Nein.
Nicht mit dieser Absolutheit: „sollte man“.
Hier in diesem ganz konkreten Fall mag das Sinn haben – wenngleich mir
immer noch nicht ganz klar ist, warum das bisschen printf ihm den
vergleichsweise großzügigen Bootloaderbereich des SAMG55 überlaufen
lässt. Aber wenn es gerade mal grenzwertig ist, und ansonsten nicht
viel Funktionalität gebraucht wird, dann ist das eine aufwandsarme
Ausweichvariante.
Wenn auf unseren 2 MiB großen ARMs der Speicher mal überläuft, dann ganz
bestimmt nicht, weil wir printf benutzen. Wenn wir dein „sollte man“
dort dagegen von vornherein verwirklicht hätten, dann hätten wir wohl
zahllose Entwicklerstunden zusätzlich verplempert – in
Alternativimplementierungen einschließlich der Reparatur der dabei
entstandenen neuen Bugs.
Und wenn man nur ein minimal printf ohne Formatierungen möchte, dann
baut man das mal kurz selber.
Diese Formatierungen verbrauchen den Platz.
Sowie die floatlib, daher gibts in zB der nanolibc ein printf ohne
float.
Aber rumgehampel mit einzelnen Ausgabefunktionen ist einfach nur
krebsig.
Sowas hab ich mit 14 noch gemacht, aber ab dann wird man schlauer.
... aber von sowas hat W.S. natürlich mal wieder keinen Ansatz von
Ahnung.
W.S. schrieb:> Da haste ja tatsächlich was aus der L..... gelernt.
Kommt dein Alzheimer wieder durch?
Jörg W. hat doch nun schon mehrfach geschrieben, dass er sich den Code
nicht angesehen hat und es auch nie ansehen wird.
Jörg W. schrieb:> W.S. schrieb:>> printf sollte man beim µC>> Nein.>> Nicht mit dieser Absolutheit: „sollte man“.
Sehe ich genauso. Man sollte wirklich keine Angst vor printf() haben -
schon gar nicht auf 32-Bit-Prozessoren.
Thema: Speicherplatz
Es ist Quatsch, mit Speicherplatz zu argumentieren. Wenn man printf()
nur einmal aufruft, sind die weiteren 999 Aufrufe absolut kostenlos. Und
man spart sich eine ganze Menge Drumherum-Programmiererei. Warum meinen
immer bestimmte Leute, man müsse sich selbst drangsalieren? Und nein:
Mit Speicherplatzverschwendung hat das nichts zu tun.
Thema: Geschwindigkeit
Formatierte Ausgaben sind meist für den Menschen gedacht - auch hier in
diesem Thread. Der Mensch kann sowieso nicht schnell lesen. Von daher
sind diese Argumente "printf() ist lahm" vollkommen am Thema vorbei.
Wenn man effeziente Kommunikation mit anderen Geräten machen will,
braucht man in den seltensten Fällen dafür printf, denn dann ist eine
Formatierung der Ausgabe - wie sie printf() bietet - meist gar nicht
gefragt.
und printf ist einfach Standard. Wenn man mehrere Libraries benutzt und
jeder seine eigene Ausgabe bastelt nervt das auch. Aber gut, unser Chuck
Norris der Programmierer benutzt keine Libs.
Da muss ich nochmal Mbed loben, da zieht gerade eine minimal_printf
Version ein die konfigurierbar ist und bis zu ca. 15 kB flash spart. Die
wird per Linker option gewrappt und alle Funktionen benutzen automatisch
die Sparversion. Atmel SAM benutze ich nicht, wird aber auch von Mbed
unterstützt.
Wobei, das minimal_printf nutzt nix Mbed spezifisches und kann
vielleicht auch in das Projekt vom TO eingebaut werden:
https://github.com/ARMmbed/mbed-os/tree/master/platform/source/minimal-printf
Jörg W. schrieb:> Ansonsten: halt die Ausgaben auf irgendwas ohne printf umbauen.
Oder man baut sich ein entsprechend schlankeres printf-Äquivalent. Hier
fliegt eins in AVR-Assembler rum, was ich für meinen i8080-Emulator
gebaut habe. Kann 8- und 16-bittige Hexadezimalzahlen auf der UART
ausgeben und besteht aus sagenhaften 37 Befehlen für printf, 16 für die
Hexformatierung und 22 für die UART-Ausgabe inklusive \n nach
\r\n-Konvertierung. Lässt sich sicherlich auch noch weiter optimieren.
Ist zwar unglaublich primitiv, aber trotzdem wesentlich komfortabler
als der Vorschlag von W.S.