Überwachung von Embedded-Systemen Mehr Transparenz beim Debuggen

Nicht das Schreiben des Codes, sondern das Debuggen kostet beim Programmieren von Embedded-Systemen die meiste Zeit.

18.10.2016

Beim Programmieren von Embedded-Systemen ist der größte Zeitfresser nicht das Schreiben des Codes, sondern das Debuggen. Reduzieren lässt sich die Entwicklungszeit mithilfe einer grafischen Live-Überwachung.

Die Entwicklung eingebetteter Systeme ist, wie die meisten in diesem Bereich belegen können, keine besonders leichte Arbeit. Es ist jedoch selten der Fall, dass der scheinbar primäre Fokus der Arbeit eines Entwicklers, die tatsächliche Entwicklung, die schwierigste und zeitaufwändigste Komponente ist. Scheinbar liegt jedoch die primäre Herausforderung für einen großen Teil derjenigen, die sich mit dem Schreiben des Codes abgeben, stattdessen im Debuggen dieses Codes, im Verfeinern des Rohmaterials in ein fertiges Produkt.

Die Schwierigkeiten, denen Entwickler beim Debuggen neu geschriebener Software gegenüberstehen, sind teilweise in einem Mangel an Transparenz verwurzelt. In den meisten eingebetteten Entwicklungsumgebungen sind die Einrichtungen für die Anzeige und sogar das Ändern der großen Mengen der in einem modernen eingebetteten System beteiligten Daten ziemlich begrenzt. Die Entwickler sind daher oft nicht nur in ihren Debug-Bemühungen eingeschränkt, sondern auch bei ihren Versuchen anderen zu zeigen, wie ihr Code arbeitet, einschließlich den neuen Mitgliedern in ihren Entwicklungsteams und interessierten Managern, die bestrebt sind, greifbare Fortschritte bei wichtigen Codierungsanstrengungen zu sehen.

Zuflucht in printf()

Entwickler, die mit der Visualisierung des von ihnen geschriebenen Codes kämpfen, finden häufig Zuflucht in printf(). Aus Mangel an Tools für Anzeige der Daten eines eingebetteten Systems – und manchmal selbst, wenn solche Tools zur Verfügung stehen – wird printf() häufig als ein wesentliches Instrument zum Berichten eines Programmstatus angesehen. Natürlich ist es nicht so, als käme die Ausgabefunktion betriebsbereit für jede Entwicklungsumgebung. Projektoptionen müssen möglicherweise eingestellt werden und in einigen Fällen können Peripherietreiber, zum Beispiel für die Manipulation von UARTs (Universal Asynchronous Receiver Transmitter), erforderlich sein. Viele Entwickler sind jedoch mit printf() vertraut und vertrauen auf die Aufrufe in dieser Funktion als Feedback für ihren Code.

Entwickler, die sich auf printf() verlassen, schreiben schließlich einen Code, der grob dem ähnelt, wie er in der ersten Abbildung dargestellt ist. Nach der Ausführung einiger wichtigen Aktionen von diesem Code werden printf()-Aufrufe erstellt, um den Benutzer, oder genauer gesagt Debugger, über die sich ergebenden Variablenwerte zu informieren. Solche Aufrufe müssen auf zahlreiche Stellen im Anwendungscode verteilt sein, damit printf() als Debugging-Tool etwas bewirken kann.

Obwohl die Ausgabefunktion sicherlich eine praktikable Option für das Berichten des Programmstatus ist, so kommt es nicht ohne Kosten. Darüber hinaus wird der Entwickler gezwungen, da die Art der oben erwähnten Aufbauarbeiten dies häufig fordert, seinen Code zu instrumentieren. Immer wenn der Status gemeldet werden soll, muss ein printf()-Aufruf vorgenommen werden. Letztlich sind printf()-Aufrufe eine Code-Verunreinigung, und sie können die Quelle einer Reihe von Problemen sein, insbesondere in einem sehr komplexen System. Die Aufrufe müssen in der Regel vor der Freigabe eines Produkts aus dem Code entfernt werden. Wird das Eliminieren von nur einem der Aufrufe versäumt, so kann dies zu einem unerwarteten Verhalten oder Abstürzen führen.

Auch wenn die Aufnahme und der Ausschluss von printf() effizient verwaltet wird, können beispielsweise durch bedingte Kompilierung aufgrund der schieren Größe dieser Funktion Probleme entstehen. So kann printf() einen wichtigen Einfluss auf die Leistung und die Speicherplatzkapazität des Systems haben.

Viele der häufig verwendeten Alternativen zu printf() sind für Entwickler, die Feedback für ihre eingebetteten Systemen möchten und deren Tool-Ketten über keine einfach zu bedienende Quelle für solche Informationen verfügen, leider nicht wirklich mehr als Variationen des gleichen Motivs. Sowohl LEDs als auch grafische Darstellungen liefern beispielsweise ein berechtigtes Instrument für das Berichten von Statusinformationen. Noch einmal, obwohl Ausgabefunktionen eine Code-Instrumentierung erfordern und das Zielsystem ein Display zur graphischen Anzeige hat, ist der Aufwand, um den notwendigen Code dafür zu erstellen so hoch, dass die Vorteile und der Nutzen den die Information bringt sich aufheben.

IDE-Überwachungsfenster

Es wäre ein Fehler zu glauben, dass Entwickler, die versuchen solche Probleme zu vermeiden, keine Hilfe von Entwicklungs-Tools erwarten könnten. Zumindest integrieren die meisten IDEs (integrierte Entwicklungsumgebung) für eingebettete Systeme ein Überwachungsfenster, welches bei der Transparenz beim Debuggen hilft. Die Idee hinter dem Überwachungsfenster ist einfach und inzwischen den meisten Entwicklern bekannt: Benutzer geben die Variablen ein und können die Werte dieser Variablen häufig in einer Tabelle sehen. Ein Überwachungsfenster gibt jedoch eher eine ziemlich eingeschränkte Sicht der inneren Abläufe eines eingebetteten Systems an. Obwohl es einen Vorteil gegenüber einigen der zuvor genannten Techniken für mehr Systemtransparenz bietet, nämlich dass keine Code-Instrumentierung erforderlich ist, stellt es eher keine praktikable Lösung für Entwickler dar, die regelmäßige Updates für den Status ihres Programms
benötigen.

Das liegt daran, dass gewöhnlich Überwachungsfenster so implementiert wurden, dass die angezeigten Werte nur dann aktualisiert werden, wenn die Ausführung des Codes anhält. Mit anderen Worten, die meisten Überwachungsfenster sind bis der Code anhält statisch und verwenden beispielsweise einen Haltepunkt, sodass die Entwickler, während das Programm ausgeführt wird, im Dunkeln bleiben. In Anbetracht dieser schmerzhaften Einschränkung haben Tool-Anbieter vor Kurzem versucht, die herkömmlichen Überwachungsfenster zu verbessern. Die Ergebnisse ihrer Bemühungen können in IDE-Funktionen wie dem Live-Überwachungsfenster, das jetzt in der Embedded Workbench von IAR verfügbar ist, beobachtet werden. Live-Überwachung hilft Entwicklern, die Lücken der standardmäßigen Überwachungsfenster zu füllen. Ein Live-Überwachungsfenster präsentiert Daten im gleichen Format, das Debugging-Tools seit Jahren verwenden. Mit der Live-Überwachung werden allerdings Variablenwerte während der Ausführung des Codes aktualisiert, nicht nur, wenn die Ausführung anhält.

Für Entwickler, deren Tools Live-Überwachung oder eine ähnliche Fähigkeit anbieten, kann ein eingebettetes System zweifellos weniger ein Rätsel aufgeben, als es sonst der Fall wäre. Es ist jedoch immer noch nicht der Fall, dass die heutigen Entwickler den Zugriff auf ein vollständiges Bild vom Geschehen ihres Codes genießen. Einer der Gründe für diesen Mangel ist die Tool-Verfügbarkeit: Live-Überwachung ist eine hardwarespezifische Funktion, die nur auf Geräten mit ziemlich fortschrittlicher Debugging-Hardware verfügbar ist. Selbst bei Projekten, welche die neusten MCUs einschließen, sowie eine mit Funktionen zur Unterstützung solcher MCUs ausgestattete IDE können Entwickler Probleme haben, die wichtigsten Informationsstücke von ihrem ausgeführten Code zu erhalten.

Grafische Live-Überwachung

Ein wichtiger Durchbruch für Entwickler, die ein detaillierteres Bild ihrer eingebetteten Systeme suchen, steht jetzt mit einer neuen Art von Tool von Micrium zur Verfügung: µC/Probe. µC/Probe bietet aufbauend auf dem Konzept der Live-Überwachung während der Ausführung des Codes ein grafisches Instrument zum Lesen und Schreiben der Variablenwerte an – in anderen Worten: ein Tool für grafische Live-Überwachung. Während die Fähigkeiten der Live-Überwachung nur verfügbar sind, wenn sie von der Debugging-Hardware unterstützt werden, sollte µC/Probe von Anfang an ein universales Tool sein. Es läuft auf einem PC und kann über eine Vielfalt von Kommunikationsschnittstellen mit einem eingebetteten System verbunden werden. Zusätzlich zur Unterstützung mehrerer beliebter Debug-Hardware-Schnittstellen kann es durch Protokolle, die in eingebetteten Systemen wie RS232, USB und TCP/IP fast allgegenwärtig sind, mit einem Ziel verbunden werden. Darüber hinaus ist µC/Probe keine vollständige IDE, sondern soll mit praktisch jeder Entwicklungsumgebung kompatibel sein. Es ist daher also für die überwiegende Mehrheit der Entwickler möglich, unabhängig von MCU oder Tool-Kette von der grafischen Live-Überwachung zu profitieren.

Während zu komplexe Debugging-Tools eine sehr steile Lernkurve präsentieren können, sodass die Entwickler vor ihrem Einsatz zurückschrecken, können die Fähigkeiten der grafischen Live-Überwachung in µC/Probe mit wenig mehr als Ziehen und Ablegen der grafischen Komponenten genutzt werden. Das Hauptprogrammfenster von µC/Probe enthält eine mit diesen Komponenten gefüllte Toolbox und der Entwickler muss nur die Auswahl aus der Toolbox ziehen und auf dem Datenfenster ablegen. Die Komponenten sollen den Variablen eines eingebetteten Systems zugeordnet und dann zum Lesen und Schreiben dieser Variablenwerte verwendet werden. Wobei die Zuordnung ebenfalls durch Ziehen und Ablegen erfolgt, in diesem Fall über den Symbolbrowser von µC/Probe.

Die Implementierung der grafischen Überwachung von µC/Probe ist eigentlich einfach. Das Tool kann seinem Benutzer eine Liste der verfügbaren Variablen präsentieren, die in einem bestimmten Körper eines Anwendungscodes verfügbar sind, indem die beim Aufbau dieses Codes erstellte Ausgabedatei analysiert wird. Diese Datei sollte im standardmäßigen ELF(Executable and Linkable Format)-Format sein; µC/Probe liefert außer der Bereitstellung der Variablennamen zusätzlich die Adresse der einzelnen Variablen. Nachdem eine Variable einer grafischen Komponente zugeordnet und µC/Probe mit einem eingebetteten System verbunden wurde, welches den Code ausführt, in welchem die Variable gemeldet wird, liefert das Tool Zugriff zu der Variable, indem Zielsystemanfragen zum Lesen und Schreiben der entsprechenden Adressen gesendet werden. Diese Anfragen können über eines der oben genannten Kommunikationsprotokolle gesendet werden.

Im einfachen Fall verwendet der Entwickler durch Ziehen und Ablegen von Messgeräten, Diagrammen, Schaltern und anderen grafischen Komponenten ein grafisches Live-Überwachungstool, um eine PC-basierte Benutzerschnittstelle für eingebettete Systeme zu erstellen. Das grafische Live-Überwachungskonzept ist jedoch sehr leistungsfähig und gibt dem Entwickler scheinbar unbegrenzte Möglichkeiten. Dieses Potenzial ist in den erweiterten Funktionen von µC/Probe ersichtlich. Sie schließen Datenerfassung, Tabellen (damit der Benutzer die volle Funktionalität von Microsoft Excel für die Manipulation seiner Systemvariablen nutzen kann), Scripting und die Oszilloskopsteuerung ein, die dem Entwickler ermöglichen, eine Vielzahl von Variablen abzutasten und den Wert in einem Format anzuzeigen, welches einem fortschrittlichen Oszilloskop ähnelt.

Der Mangel an Transparenz in eingebetteten Systemen ist nichts Neues und die Notwendigkeit der Fähigkeiten eines Tools zur Live-Überwachung existiert schon lange. Mit dem Fortschritt der Technik im Bereich von Embedded-Systemen ist die Motivation für einen verbesserten Zugang zu Systemdaten während des Debuggens nur gewachsen. Einfach ausgedrückt, es scheint mehr Daten als je zuvor für die Visualisierung in den typischen eingebetteten Systemen zu geben, mehr vom Benutzer bereitgestellte Werte, mehr speicherzugeordnete Register, die den peripheren Status berichten und weitere Paketdaten von eingehenden Kommunikationen. Zudem erfordert die Komplexität moderner Hardwareplattformen oft die Verwendung von RTOS(Real-Time Operating System)-Komponenten, einschließlich einem Echtzeit-Kernel und diese Komponenten haben ihre eigenen Variablen und Datenstrukturen, die unweigerlich für den Entwickler interessant sind.

Während die verbesserte, von einem Tool für grafische Live-Überwachung bereitgestellte Transparenz während des Debuggens zu begrüßen ist, kann es sich auch in anderen Phasen eines eingebetteten Projekts als nützlich erweisen. Wie die MCUs, welche die Grundlage der Hardwareplattformen der Entwickler bilden, zunehmend komplexer wurden, scheint es manchmal, dass es einen entgegengesetzten Trend für Auswertebaugruppen gibt. Viele Entwickler beginnen jetzt ihre Projekte auf abgespeckten Baugruppen, die nur begrenztes Potenzial für Benutzer-Interaktion bieten. Aus Kostengründen bieten solche Baugruppen einen offensichtlichen Reiz, aber sie können eine Quelle endloser Frustration sein, wenn die Notwendigkeit entsteht, eine überzeugende Demonstration eines Wirksamkeitsnachweises für das Management oder Investoren vorzubereiten.

Projekte vorzeitig beenden

Strikt auf Trends in der Hardware basierend, hätten die Entwickler Recht, wenn sie meinen, dass das moderne eingebettete System zu einem großen Teil eine Black Box bleibt. Die zur Verfügung stehenden Optionen für die Preisgabe der Inhalt der Box gehen weit über einfache printf()-Aufrufe hinaus. Mit den vielfältigen Fähigkeiten eines Tools für grafische Live-Überwachung können Entwickler ein eingebettetes System zum Leben erwecken, das Debuggen beschleunigen sowie Demonstrationen erstellen und dazu beizutragen, dass Projekte vorzeitig beendet werden.

Bildergalerie

  • Grafische Komponenten der Toolbox von µC/Probe werden auf Datenfenster gezogen und abgelegt.

    Grafische Komponenten der Toolbox von µC/Probe werden auf Datenfenster gezogen und abgelegt.

    Bild: Micrium

  • Mit einer grafischen Live-Überwachung sind Oszilloskop-ähnliche Darstellungen von Daten möglich.

    Mit einer grafischen Live-Überwachung sind Oszilloskop-ähnliche Darstellungen von Daten möglich.

    Bild: Micrium

  • Aufrufe auf printf() sind ein Instrument zum Berichten von Variablenwerten.

    Aufrufe auf printf() sind ein Instrument zum Berichten von Variablenwerten.

    Bild: Micrium

Firmen zu diesem Artikel
Verwandte Artikel