Mittwoch, 21. Mai 2014

printf(...) ganz einfach per Semihosting auf dem STM32F4

Lieber Entwickler,

bei einer Konsolenanwendung auf dem PC ist es (schlechte) gängige Praxis, permanent Debug-Ausgaben per System.out.println("") oder Console.Writeln("") oder printf("") auszugeben. Bei einfachen oder experimentellen Anwendungen entwickelt man insbesondere auch in Verbindung mit einem Debugger schnell ein Gefühl dafür, wo im Falle eines Fehlers nochmals Hand anzulegen ist.

Bei Entwicklungen mit dem Microcontroller ist man meist auf LEDs oder einfache LCD-Displays angewiesen, um Text auszugeben. Profis schreiben über über die serielle Schnittstelle raus und hängen sich mit einem Terminal-Programm an den Prozessor. Alle Lösungen haben jedoch Nachteile:

  • LEDs können nur seeehr einfache Informationen ausgeben. Einen komplexen Morsecode will wohl keiner entwickeln...
  • Ein LCD verlangt nach einigem Code, verbraucht rare IOs und kostet Geld
  • Die serielle Schnittstelle verbraucht einen UART und macht eine zusätzliche Kabelverbindung
Mit der Technik "Semihosting" bietet die STM32-Familie glücklicherweise eine sehr einfache Möglichkeit, Informationen vom Microcontroller über die Debug-Verbindung an den Host zu senden. Meine Toolchain ist bereits für Semihosting vorbereitet. Ein Beispielprojekt habe ich in hier abgelegt

Zur Aktivierung sind die folgenden Schritte notwendig.
  • Hole Dir mein Semihosting-Testprojekt
  • Du kannst dieses Projekt 1:1 verwenden. Es misst einfach nur die Spannung am PA1-Eingang und gibt diese jeder Sekunde aus. Bei mir ist dort ein Sharp-Infrarot-Entfernungsmesser angeschlossen. Wenn bei Dir nichts dort angschlossen ist, funktioniert die Anwendung trotzdem. Wesentlich sind die Dateien:
    • Inc/printf.h
    • Inc/semihosting.h
    • Src/printf.c
    • Src/semihosting.c
    • Src/sh_cmd.asm
  • Füge die asm- und die c-Dateien Deinem Src-Verzeichnis hinzu
  • Füge die h- Datei Deinem Inc-Verzeichnis hinzu
  • Aktiviere Semihosting in den Debugger-Settings (siehe Screenshot)
  • Füge #include "printf.h" in den User-Code-Bereich 0 der main.c hinzu
  • Füge in der while-Schleife jetzt einen printf-Befehl und eine Verzögerung hinzu, beispielsweise: "printf("Der Prozessor ist jetzt %u msec gelaufen, HAL_GetTick()); HAL_Delay(1000);"

Ein wenig seltsam mag erscheinen, dass ich hier eine eigene printf-Funktion verwende und nicht auf die integrierte Funktionalität der STM-Firmware-Library ("newlib") zurück greife. Grund hierfür ist, dass die newlib wirklich jedes Feature von printf unterstützt und sowohl viel Speicher im Flash als auch auf dem Heap verbraucht. Meine Implementierung (die ich natürlich 1:1 abkekupfert habe) realisiert eine mehr als ausreichende Teilmenge der Gesamtfunktionalität und bleibt herrlich kompakt.

Happy Coding

1 Kommentar:

  1. Hallo Klaus!

    Das Überschreiben der Funktionen für eine beschränkte Anzahl an Parametern ist eine gute Idee, habe ich jetzt schon öfter gelesen.
    Mich würde interessieren ob Semihosting auch mit std::cout anstatt printf funktioniert?
    Wenn ich std::cout in einer Schleife verwende, bekomme ich die Ausgabe nur das erste Mal, alle weiteren Male scheint es, als würde die Ausgabe übersprungen. Mit printf gibts keine Probleme. Hast du damit zufällig Erfahrung?

    Stammt die Datei "407sharpdistance/ Src/ sh_cmd.asm" vollständig von CooCox oder wurde daran etwas geändert?

    Danke, Thomas

    AntwortenLöschen