Home |
Beschränkung auf das WesentlicheCross-Entwicklungsumgebung und Echtzeit-Kernel mit Win32-API vermeiden unnötigen Ballastvon Peter Petersen und Thomas E. Schotland Viele Echtzeit- und Embedded-Systeme haben keine oder nur eine sehr eingeschränkte Benutzeroberfläche. Trotzdem möchten Kunden und Anwendungsentwickler ein Windows-kompatibles Betriebssystem, weil die Hardware-Preise stetig sinken und Entwicklungswerkzeuge und Know-How weit verbreitet sind. Eine interessante Alternative zu Windows NT und 95 sind Entwicklungswerkzeuge, die eine mit dem Win32-Standard kompatible Umgebung auf dem Zielsystem schaffen, ohne durch Ballast und Echtzeit-Mängel von NT oder 95 eingeschränkt zu sein. Windows NT und 95 setzen sich auch in Embedded-Systemen immer mehr durch. Die Preise für PC-Hardware und -Software sind durch die Massenproduktion stetig gefallen. Beide Systeme unterstützen echte 32-bit-Programme mit linearer Adressierung und nutzen moderne 32-bit-Prozessoren voll aus. Software-Entwicklungswerkzeuge (Compiler, Linker, Debugger, etc.) sind allgemein verfügbar und durch unzählige Entwickler getestet worden. Die Hersteller von Prozessoren haben sich auf die Marktentwicklung eingestellt und bieten inzwischen eine Reihe von 386-kompatiblen Microcontrollern an - etwa Intel den 386EX, National Semiconductor den NS486SXF oder AMD die Elan-Serie. Der hohe Komfort hat aber auch seinen Preis: Windows stellt hohe Anforderungen an die Computer-Ressourcen. Windows 95 benötigt mindestens 16 Mbyte Hauptspeicher, um "rund" zu laufen, während Windows NT 32 Mbyte braucht, um eine akzeptable Leistung zu erreichen. Dabei ist noch nicht einmal der Bedarf der Anwendungssoftware berücksichtigt. Beide Systeme belegen etwa 100 bis 150 Mbyte an Plattenspeicher. Für kleine, in großen Stückzahlen gebaute Systeme sind diese zusätzlichen Hardware-Kosten oft nicht tragbar. Ein weiterer wichtiger Gesichtspunkt für Embedded Systems ist die Echtzeit-Fähigkeit der Software. Windows wurde für Heim- und Büroanwendungen konzipiert, die keine oder nur schwache Echtzeit-Anforderungen stellen - abgesehen von einigen wenigen Ausnahmen wie z.B. Spielen oder Multmedia-Anwendungen. Auf den ersten Blick könnte man durch die Windows-Fähigkeit, Echtzeit-Prioritäten für einen Prozeß zu vergeben, glauben, daß Windows 95 und NT echtzeit-fähig sind. Das ist aber nicht der Fall. Windows ändert Prioritäten dynamisch zur Laufzeit, um eine "gerechtere" Verteilung der verfügbaren Prozessorzeit zu erreichen. Die Win32-Prioritäts-Verwaltung kann Prioritätsumkehr nicht ausschließen, sowohl für Anwendungs-Threads als auch für verzögerte Prozeduraufrufe ("deferred procedure calls") aus Interrupt-Service-Routinen von Hardware-Treibern. Außerdem ist der Zeitbedarf von nicht unterbrechbaren Systemaufrufen nicht deterministisch. Die interne Timer-Auflösung ist bei 10ms festgelegt, was für viele Systeme zu grob ist. Darüber hinaus kann Windows nicht garantieren, daß "timer callbacks" innerhalb einer garantierten Zeit bedient werden. Die Geschwindigkeit, mit der Anwendungsprogramme ausgeführt werden, wird durch die Verwaltung von virtuellem Speicher und von Systemdiensten gebremst. Hintergrundprozesse, die verschiedene Betriebssystem-Dienste implementieren, können einer zeitkritischen Anwendung CPU-Zeit entziehen. Außerdem ist das Multitasking von Windows NT und 95 nicht so effizient wie das von speziellen Echtzeit-Systemen. So liefert zum Beispiel ein einfacher Semaphoren-Benchmark unter Windows NT, Windows 95 und einem Echzeit-Betriebssystem die in Bild 1 dargestellten Ergebnisse. Schließlich sind auch die Lizenzkosten ein kritischer Faktor bei der Entwicklung von Embedded-Systems. Die Kosten einer Windows-Lizenz für jedes produzierte Gerät können signifikant sein. Echtzeit-Erweiterungen für NT: eine Lösung?Einige kürzlich vorgestellte Produkte versprechen Echtzeit-Fähigkeiten für Windows NT. Dabei werden verschiedene Ansätze verwendet:
Jede der hier beschriebenen Lösungen hat ihre Probleme. Der große Ressourcen-Bedarf von NT bleibt bestehen oder wird sogar noch vergrößert. Die erreichte Leistung genügt nur "weichen" Echtzeit-Anforderungen oder wird durch allgemeine Performance-Engpässe eingeschränkt. Für alle diese kommerziellen Lösungen werden Laufzeit-Lizenzgebühren erhoben, die die Kosten des Betriebssystems erhöhen. Produkte, die tief im NT-Kernel integriert sein müssen (z.B. auf der HAL-Ebene), werden stets erst mit einer gewissen Verzögerung für die jeweils aktuelle Betriebssystem-Version verfügbar sein. Auch werden solche Komponenten natürlich nie durch eine so große Anwenderbasis getestet werden können wie die Standardversion von Windows NT, so daß es zumindest fraglich ist, ob solche Systeme im gleichen Maße kompatibel und stabil sein können. Das beste aus beiden Welten: ein Win32-kompatibles Echtzeit-SystemDa Windows NT und Windows 95 nicht für Embedded-Systeme konzipiert wurden und daher für diesen Einsatzbereich nicht geeignet sind, bietet es sich an, stattdessen ein System zu verwenden, das für solche Anwendungen ausgelegt wurde und ein Win32-kompatibles API (Application Program Interface) hat. Eine solche Lösung vereint die Vorteile von Windows NT mit denen eines Echtzeit-Systems. Darüber hinaus schränkt die Win32-Kompatibilität die Echtzeit-Leistung nicht ein. Als Beispiel sei hier das Echtzeit-System RTTarget-32 mit RTKernel-32 der Fa. On Time Informatik vorgestellt. RTTarget-32 ist Cross-Entwicklungssystem, das Win32-"Console Mode Applications" auf beliebigen Rechnern mit einer 386- oder höheren CPU ausführen kann. "Console Mode Applications" sind Programme, die printf() oder ähnliche Mechanismen für die Ein-/Ausgabe verwenden. Die Win32-Kompatibilität von RTTarget-32 ist ausreichend, um die komplexen Laufzeit-Systeme von gebräuchlichen C++-Compilern für Win32 zu unterstützen, einschließlich der jüngsten C++-Erweiterungen, wie z.B. Exception Handling, globale und lokale "Object Construction/Destruction", "Name Spaces", RTTI, etc. RTTarget-32 unterstützt außerdem viele fortgeschrittene Win32-spezifische Merkmale, wie z.B. "Uncommitted Memory", "Structured Exception Handling", "Thread Variables", DLLs, etc. Trotzdem erlaubt RTTarget-32 durch seine Skalierbarkeit, eine komplette 32-bit-Anwendung in 16 Kbyte Speicher zu starten und auszuführen. Der Echtzeit-Kernel RTKernel-32 erweitert die Funktionsmerkmale von RTTarget-32 um "Multithread Functions", mit deren Hilfe Threads, Semaphoren, "Critical Sections", etc. erzeugt und verwaltet werden können. RTTarget-32 verändert den Entwicklungszyklus mit einem Standard-Win32-Compiler nicht. Der Compiler wird in Verbindung mit dem zugehörigen Linker und den Laufzeit-Systembibliotheken genauso verwendet wie zur Entwicklung von "normalen" Windows-Applikationen. Sowohl die Kommandozeilen-Werkzeuge des Compilers als auch die integrierte Entwicklungsumgebung können verwendet werden. Eine mitgelieferte Bibliothek stellt das erweiterte (non-Win32-)API von RTTarget-32 der Anwendung zur Verfügung. Der Locator von RTTarget-32 verarbeitet eine Standard-Win32-EXE-Datei und eine Konfigurationsdatei. Die verschiedenen Teile der EXE-Datei werden auf die Ziel-Hardware abgebildet und eventuell in RAM- und ROM-Bereiche getrennt. Der Locator kopiert "Boot Code" und eventuell benötigte DLLs in das Programmabbild und erzeugt eine einzige Programmdatei, die in ein EPROM gebrannt oder auf eine Startdiskette geschrieben werden kann. Während der Entwicklungsphase wird die Anwendung über eine serielle Verbindung auf das Zielsystem geladen und kann dort unter der Kontrolle eines Cross-Debuggers ablaufen. Einsatz der gewohnten CompilerRTTarget-32 unterstützt die am weitesten verbreiteten Compiler für Win32: Borland C/C++, Borland C++ Builder, Borland Delphi, Microsoft Visual C++ und Watcom C/C++. Der mitgelieferte Cross-Debugger basiert auf einem der führenden Debugger für Win32, Borlands TD32. Er unterstützt "Source Level Remote Debugging" für Borland-, Microsoft- und Watcom-Programme. Darüber hinaus ist der Debugger mit einigen Funktionen erweitert worden, die bei der Entwicklung von Embedded-Systemen benötigt werden, z.B. Unterstützung von Interrupt Handling, Port I/O, etc. Um den Entwicklungszyklus so kurz wie möglich zu halten, wird für eine möglichst effiziente Übertragung zum Zielsystem Datenkompression und Caching verwendet. Eine der Stärken von RTTarget-32 ist, daß er sich der leistungsfähigen Funktionen zur Speicherverwaltung und Fehlersuche des Intel 80386 und seiner Nachfolger bedient. RTTarget-32 kann optional Speicherschutz, "RAM remapping" und "Uncommitted Memory" Paging verwenden. Wenn der Speicherschutz aktiviert ist, sind wichtige System-Datenstrukturen - wie z.B. "Descriptor Tables" - für die Anwendung nicht zugänglich. Das Schreiben in geschützte Speicherbereiche, z.B. in den Programmcode, ist nicht gestattet und löst eine Exception aus. "RAM Remapping" kann verwendet werden, um fragmentierte Speicherbereiche zu einem größeren, zusammenhängenden Bereich zusammenzufassen (z.B. konventioneller und erweiterter Speicher in PC-kompatiblen Systemen), oder es können zusammenhängende virtuelle Bereiche erzeugt werden, die aus einer Kombination von RAM und ROM bestehen. "Uncommitted Memory" ist ein wichtiges Konzept in der Speicherverwaltung von Windows NT. Es ermöglicht einer Applikation, Speicher zu reservieren, ohne ihn tatsächlich zu verwenden ("commit"). Die meisten C/C++-Laufzeitsysteme verwenden uncommitted memory; daher muß das zugrundeliegende Betriebssystem diese Funktion unterstützen, um eine effiziente Speicherverwaltung zu gewährleisten. Der direkte Zugriff auf den physischen Speicher für "Direct Memory Access" oder "Memory-mapped Devices" wird unterstützt, indem die entsprechenden Zugriffsrechte für diese Speicherbereiche eingerichtet werden - entweder statisch während des Locate-Prozesses oder dynamisch zur Laufzeit. Die Kombination der Debug-Register des Prozessors mit Paging erlaubt die Implementierung von sehr leistungsfähigen Debug-Möglichkeiten, wodurch die Verwendung von In-Circuit Emulatoren entbehrlich wird. Jeder ungültige Speicherzugriff löst eine Exception aus. Innerhalb des Debuggers wird die fehlerhafte Instruktion angezeigt und die Ursache des Problems kann untersucht werden. Die Debug-Register werden verwendet, um "Hardware Breakpoints" zu implementieren (z.B. Anhalten bei einem Schreibzugriff auf eine bestimmte Speicheradresse). Hardware Breakpoints können im ROM oder RAM gesetzt werden und verändern nicht das Laufzeitverhalten des Programms. Eingebunden wird nur, was gebraucht wirdRTTarget-32 stellt die zur Entwicklung von 32-bit Anwendungen für 386-kompatible Systeme erforderlichen Werkzeuge zur Verfügung. Da nur die tatsächlich von der Anwendung benötigten Module der Win32-Emulations-Bibliothek zur Anwendung gebunden werden, wird kein Speicherplatz auf dem Zielsystem durch nicht benutzte Teile der Bibliothek verschwendet. Daneben sind noch andere Erweiterungen für RTTarget-32 erhältlich wie z.B. RTEmu, ein 387 Floating Point Emulator. Er ist für die Anwender von RTTarget-32 kostenlos. RTFiles ist ein FAT12/FAT16-kompatibles Dateisystem für IDE und Flash-Geräte. Sollen externe DLL-Dateien dynamisch zur Laufzeit anstatt aus der Programmdatei heraus geladen werden, so ist dies mit RTDLL möglich. Das bereits beschriebene RTKernel-32 ist ein Echtzeit-Multitasking-Kernel mit einem eigenen und einem Win32-kompatiblen API für Echtzeit-Multitasking-Anwendungen. Ein minimales RTTarget-32 Programm kann in etwa 12 Kbyte ROM und 4 Kbyte RAM laufen bzw. in Systemen mit 16 Kbyte RAM, die vom Massenspeicher gestartet werden. Eine Anwendung, die alle oben aufgeführten Komponenten enthält, benötigt etwa 128 Kbyte ROM und 128 Kbyte RAM. Selbstverständlich versucht RTTarget-32 nicht, ein Windows NT-"Clone" zu sein. Es wird nur eine Untermenge des NT-API unterstützt. So werden etwa z.Zt. nur "console mode"-Programme ohne eine grafische Oberfläche unterstützt, um den Ressourcen-Bedarf gering zu halten. Auch unterstützt RTTarget-32 keine Windows-NT- oder Windows-95-Gerätetreiber. Da jedoch viele Echtzeit- und Embedded-Systeme mit spezieller Hardware arbeiten, sind die unter RTTarget-32 gegebenen Möglichkeiten für Port I/O, Interrrupt-Handling und Zugriff auf den physikalischen Speicher aus der Anwendung heraus eine unschätzbare Hilfe für den Anwendungsentwickler. Literatur
Listings und Beispiele#include <windows.h> #include <stdio.h> #include <stdlib.h> #define LOOPS 100000 HANDLE S1, S2; /*-----------------------------------*/ DWORD WINAPI ThreadA(LPVOID lpdwParam) { while (1) { WaitForSingleObject(S1, INFINITE); ReleaseSemaphore(S2, 1, NULL); } return 0; } /*-----------------------------------*/ DWORD main(void) { HANDLE H; DWORD ThreadID, T, i; S1 = CreateSemaphore(NULL, 0, 1, "BenchSema1"); S2 = CreateSemaphore(NULL, 0, 1, "BenchSema2"); H = CreateThread(NULL, 0, ThreadA, NULL, 0, &ThreadID); Sleep(100); printf("switching between two tasks %i times...\n", LOOPS); T = GetTickCount(); for (i=0; i<LOOPS; i++) { ReleaseSemaphore(S1, 1, NULL); WaitForSingleObject(S2, INFINITE); } T = GetTickCount() - T; printf("Time for %i loops: %i milliseconds\n", LOOPS, T); TerminateThread(H, 0); CloseHandle(H); CloseHandle(S1); CloseHandle(S2); printf("Hit return to terminate...\n"); getc(stdin); return 0; } Quelltext des Benchmark-Programms. Das Programm läuft ohne Änderungen des Quellcodes unter Windows 95, Windows NT und RTTarget-32/RTKernel-32. Hello, RTTarget-32!Nehmen wir an, Sie haben zwei PCs: einen Host, der unter DOS oder Windows läuft und ein Target, das ohne Betriebssystem laufen soll. Wir wollen ein mit Borland C++ compiliertes Testprogramm auf dem Target ausführen. Wir schreiben das folgende Testprogramm in Datei HELLO.C: #include <stdio.h> int main(void) { printf("Hello, RTTarget-32!\n"); return 0; } Jetzt können wir das Programm mit der folgenden Befehlszeile compilieren und binden: bcc32 hello.c rtt32.lib Damit das Programm auf dem Target laufen kann, müssen wir es "locaten". Zu diesem Zweck wird eine kleine Konfigurationsdatei (HELLO.CFG) angelegt: // Define memory layout Region NullPage 0 4k RAM Region LowMem 4k 636k RAM Region HighMem 1M 1M RAM // Locate boot code and associated data Locate BootCode DISKBOOT.EXE LowMem Locate BootData SystemData LowMem Locate DiskBuffer DiskBuffer LowMem Locate Header Hello LowMem // Locate program entities Locate Section CODE HighMem Locate Section DATA HighMem Locate Stack Stack HighMem 16k Locate Heap Heap HighMem Jetzt können wir mit folgender Befehlszeile "locaten": RTLoc hello Dadurch werden die Dateien HELLO.RTB (die Datei mit dem "relocated program image") und HELLO.LOC (eine detaillierte "Map"-Datei) erzeugt. Jetzt legen wir eine Startdiskette mit unserem Programm an. Legen Sie eine leere, formatierte Diskette in Laufwerk A: ein und führen Sie folgenden Befehl aus: bootdisk hello a: Legen Sie die Diskette im Laufwerk des Target-Rechners ein und starten Sie das Target neu. Der Boot Code von RTTarget-32 wird den PC initialisieren, das Programm von Diskette lesen, in 32-bit Protected Mode umschalten und das Programm ausführen.
|