Dieser Artikel beschreibt die Entwicklung eines Board Support Package (BSP) und eines Anwendungsprogramms zur Unterstützung von PCI2040 für x86-CPU-Zielsysteme unter dem Echtzeitbetriebssystem VxWorks. Außerdem wird die Inkompatibilität von Tornado mit der gängigen Netzwerkkarte rtl81x9 während des Debuggings behandelt. VxWorks ist ein von Wind River Systems entwickeltes, leistungsstarkes Echtzeitbetriebssystem (RTOS). Aufgrund seiner hohen Zuverlässigkeit, überlegenen Echtzeitleistung und einfachen Anpassbarkeit findet VxWorks breite Anwendung in Hightech-Bereichen wie Kommunikation, Militär und Luft- und Raumfahrt sowie in Bereichen mit hohen Echtzeitanforderungen. Tornado ist die Entwicklungs- und Debugging-Umgebung von Wind River für das Betriebssystem VxWorks und bildet den Host-Teil der Cross-Entwicklungsumgebung. Die Entwicklung des BSP erfolgt primär in der Tornado-Entwicklungs- und Debugging-Umgebung. Der von TI entwickelte PCI2040 ist ein dedizierter Chip, der eine nahtlose Verbindung zwischen dem lokalen PCI-Bus und dem DSP ermöglicht. Um die Kommunikation zwischen PC und DSP unter der Echtzeitbetriebssystemumgebung von VxWorks zu ermöglichen, ist die Entwicklung eines Board Support Package (BSP) für die x86-Zielmaschine erforderlich. 1. Grundlagen des BSP: Ein BSP ist ein Software-Support-Package, das zwischen der Hardware des Motherboards und dem Betriebssystem fungiert und somit Bestandteil des Betriebssystems ist. Seine Hauptfunktion besteht darin, die Hardware abzuschirmen und Treiber sowohl für das Betriebssystem als auch für die Hardware bereitzustellen. Sein Hauptzweck ist die Unterstützung des Betriebssystems, um dessen optimale Ausführung auf dem Motherboard zu gewährleisten. VxWorks verwendet unterschiedliche BSPs für verschiedene Ziel-CPUs. Selbst bei gleicher CPU variiert die Position des BSP je nach Peripheriegeräten (z. B. Größe und Typ des externen DRAM). Die Position des BSP im VxWorks-Betriebssystem ist in Abbildung 1 dargestellt. Abbildung 1: Position des BSP in VxWorks. Das BSP unterscheidet sich deutlich vom BIOS eines PCs. Das BIOS ist primär für die Erkennung und Initialisierung von Systemgeräten (Setzen von Stackpointern, Interruptzuweisung, Speicherinitialisierung usw.) beim Systemstart, das Laden des Betriebssystems und die Planung von Systemvorgängen zuständig. Das System sendet Anweisungen an die Hardware, lädt das Betriebssystem von der Festplatte in den Arbeitsspeicher und übergibt Hardware-Schnittstelleneinstellungen. Sobald das Betriebssystem ordnungsgemäß läuft, ist die Funktion des BIOS im Wesentlichen abgeschlossen. Die Rolle des PC-BIOS ähnelt der des Bootloaders in einem eingebetteten System (der Boot-Software auf der untersten Ebene, die die Grundeinstellungen des Motherboards initialisiert und die Hardware für den Empfang externer Programme vorbereitet). Im Gegensatz zum Bootloader, der lediglich das System lädt, lädt das BIOS das Betriebssystem und übergibt zusätzlich Parametereinstellungen (Interrupt-Port-Definitionen usw.). Das BSP (Background Software Package) läuft zusammen mit dem Betriebssystem auf dem Motherboard. Der Beginn des BSP ähnelt der Arbeit des BIOS, das BSP enthält jedoch zusätzlich grundlegende systembezogene Treiber (serielle Schnittstelle, Netzwerkschnittstelle usw.). Darüber hinaus können Programmierer das BSP programmatisch modifizieren, beliebige Treiber oder systemfremde Programme hinzufügen und sogar die gesamte Entwicklung auf höherer Ebene in das BSP verlagern. 2 VxWorks-Image und Bootvorgang2.1 VxWorks-Image Das VxWorks-Image ist ein Bootprogramm und ein VxWorks-Betriebssystem, das in der Tornado-Entwicklungsumgebung kompiliert wurde. Abbildung 2: Bootsequenz des VxWorks-BSP. Abbildung 3: Headerbereich des PCI2040-Konfigurationsraums. VxWorks-Images lassen sich grob in zwei Kategorien unterteilen: bootfähige und ladbare Images. Bootfähige Images werden in ROM-basierte und ROM-residente Images unterteilt. ROM-basierte Images werden weiter in komprimierte und unkomprimierte Typen unterteilt. Für x86-Zielsysteme werden in der Regel herunterladbare Images verwendet, die über ein VxWorks-BootROM-Image in den RAM des Zielsystems geladen und ausgeführt werden. In diesem Artikel wird das VxWorks-System von einer Diskette gebootet, und das BootROM wird üblicherweise im Format bootrom_uncmp ausgewählt. Legen Sie eine leere Diskette in den Host-Rechner ein, kopieren Sie die kompilierte Datei bootrom_uncmp.bin aus dem BSP-Verzeichnis in das Verzeichnis host\x86-win32\bin und erstellen Sie in der DOS-Umgebung mit dem Befehl „mkboot a:bootrom_uncmp“ in diesem Verzeichnis eine Bootdiskette. Konfigurieren Sie den Zielrechner so, dass er von der Diskette bootet. Diese Bootdiskette lädt das VxWorks-Image vom Host-Rechner auf den Zielrechner herunter und führt es dort über eine vordefinierte Kopplungsmethode (serielle Schnittstelle oder Netzwerk) aus. Während des Downloads muss der Zielserver auf Tornado 2.2 konfiguriert und der FTP-Server aktiviert sein. Bei der Erstellung eines Standalone-Systems muss die Festplatte in einem Format unterhalb von FAT16 formatiert sein. Erstellen Sie eine DOS-Bootdiskette, die die zum Ausführen des Befehls „mkboot c:“ benötigten Dateien und die Datei boot.hex enthält. Führen Sie in der DOS-Umgebung auf dem Zielrechner „mkboot c:“ aus, um VxWorks Boot von der Festplatte zu starten. Ändern Sie die Datei config.h im BSP-Paket, indem Sie die Boot-Methode auf Festplattenstart (ata(0,0)) umstellen und #undef include_ATA durch #define include_ATA ersetzen. Nach der Neukompilierung starten Sie den Zielrechner. Das VxWorks-Image wird auf die Festplatte heruntergeladen und erstellt so ein eigenständiges System. Sowohl das BootROM-Image als auch das VxWorks-Image initialisieren die Hardware, unterscheiden sich jedoch inhaltlich. Das BootROM-Image dient hauptsächlich dem Herunterladen des VxWorks-Systems über Netzwerk oder serielle Schnittstelle und initialisiert daher nur wenige Hardwarekomponenten wie Netzwerkschnittstellen und serielle Schnittstellen, um die Anforderungen für den Download zu erfüllen. Nach Abschluss des VxWorks-System-Downloads sind die Funktionen der initialisierten Hardware beendet. Beim Start von VxWorks werden nahezu alle Hardwaregeräte vollständig neu initialisiert, um den Anforderungen des VxWorks-Betriebssystems gerecht zu werden. 2.2 VxWorks-Startprozess: Das VxWorks-Image kann im ROM oder RAM ausgeführt werden. Der Unterschied in der Startreihenfolge besteht darin, dass VxWorks im RAM die Funktion `sysInit()` aufruft, im ROM hingegen nicht. Wie in Abbildung 2 dargestellt, dient `sysInit()` hauptsächlich der Initialisierung des RAMs. Im RAM-Modus springt das System direkt zur ersten RAM-Adresse, um VxWorks zu starten. Läuft VxWorks im ROM, ist das erzeugte Image ein ROM-residentes Image. Dies spart RAM-Speicherplatz, ist aber langsamer. Im RAM-Modus ist das erzeugte Image entweder ein ROM-basiertes oder ein ladbares Image. Auf x86-Systemen läuft VxWorks im Speicher. 3. Einführung in den PCI2040-Chip3.1 Merkmale des PCI2040-Chips Der PCI2040 entspricht der PCI Local Bus 2.2-Spezifikation und ermöglicht so eine nahtlose Verbindung zwischen dem PCI Local Bus und dem HPI (Host Port Interface) des TMS320C54X (oder TMS320C6X). Ein PCI2040 kann gleichzeitig mit den HPI-Schnittstellen von vier DSPs verbunden werden. Der PCI2040 bietet außerdem eine 16-Bit-Universal-Bus-Schnittstelle (für eine nahtlose Integration mit JATG), die mit 3,3-V- und 5-V-Signalumgebungen kompatibel ist. 3.2 Verbindung zwischen PCI2040 und TMS320VC5409: Das System nutzt den PCI2040 zur Kommunikation zwischen dem TMS320VC5409 und dem PC. Da es sich beim PCI2040 um einen dedizierten Chip von TI handelt, ist die Hardware-Verbindung relativ einfach; es müssen lediglich die entsprechenden Pins verbunden werden. Nicht verwendete Eingangssignalleitungen müssen mithilfe von Pull-up-Widerständen auf den gültigen Logikpegel gezogen werden. Der TMS320VC5409 verarbeitet die empfangenen Daten und überträgt sie über den PCI2040 an den lokalen PCI-Bus des PCs. Die Daten werden auf dem PC weiterverarbeitet und auf dem Bildschirm angezeigt. 3.3 PCI2040-Konfigurationsraum Die Definition eines PCI-Bus-Konfigurationsraums dient dazu, geeignete Konfigurationsmaßnahmen für eine vollständige Geräteverschiebung bereitzustellen. Dies geschieht ohne Benutzereingriff bei Installation, Konfiguration und Systemstart. Die Systemadresszuordnung erfolgt durch geräteunabhängige Software. Beim Einschalten des Systems lädt das Betriebssystem den PCI-Konfigurationsraum in den Arbeitsspeicher des PCs. Der Zugriff auf den PCI-Konfigurationsraum erfolgt durch Lesen und Schreiben der entsprechenden Speicheradressen. Ein physisches Gerät am PCI-Bus kann ein oder mehrere PCI-Funktionsgeräte (auch logische Geräte genannt) enthalten. Jedes PCI-Funktionsgerät verfügt über 64 Konfigurations-Doppelwörter zur Implementierung von Konfigurationsregistern. Das PCI-Protokoll definiert Format und Zweck der ersten 16 Doppelwörter, den sogenannten Konfigurationsheaderbereich des Geräts. Der Zweck der übrigen 48 Doppelwörter ist gerätespezifisch. Abbildung 3 zeigt die Struktur des Konfigurationsheaderbereichs des PCI2040-Konfigurationsraums. Im Basisadressregister repräsentiert die HPI-CSR-Speicherbasisadresse die Basisadresse des vom HPI-CSR-Register im PCI2040 abgebildeten Speicherbereichs, und die Kontrollbereichsbasisadresse repräsentiert die Basisadresse des vom 32 KB großen Kontrollbereich im PCI2040 abgebildeten Speicherbereichs. Der Datentransfer findet innerhalb des letztgenannten Bereichs statt. 4. PCI2040-basierte BSP-Entwicklung: Ein BSP muss gemäß der BSP-Definition einer bestimmten CPU geschrieben werden und ist in den meisten Fällen eine Modifikation einer bestehenden BSP-Vorlage. Die in diesem Artikel verwendete Entwicklungs- und Kompilierungsumgebung ist Tornado 2.2/VxWorks 5.5, und die Ziel-CPU ist ein Pentium 3 in einem x86-System. In Tornado 2.2 befindet sich das entsprechende BSP im Ordner Tornado 2.2\target\config\pcPentium3. 4.1 Konfiguration des Realtek 81x9 Netzwerkkartentreibers im BSP Dieses System verwendet eine Netzwerkschnittstelle, um das VxWorks-System vom Host auf den Zielrechner herunterzuladen. Tornado 2.2 selbst unterstützt keine gängigen Realtek-Netzwerkkarten. Die Unterstützung für den Realtek 81x9 Netzwerkkartentreiber muss dem entsprechenden BSP-Paket hinzugefügt werden, damit das VxWorks-System auf die Realtek 81x9 Netzwerkkarte des Zielrechners heruntergeladen werden kann. Realtek stellt einen Realtek 81x9 Netzwerkkartentreiber für Tornado 2.2 bereit, der sechs Dateien umfasst. Kopieren Sie die vier Dateien sysNet.c, sysRtl91x9End.c, config.h und configNet.h in das Verzeichnis Tornado2.2\target\config\pcPentium3, ersetzen Sie die Originaldateien durch gleichnamige Dateien und fügen Sie die erforderlichen Dateien hinzu. Kopieren Sie die Datei rtl81x9.c in das Verzeichnis Tornado2.2\target\src\drv\end\unsupported. Kopieren Sie die Datei rtl81x9.h in das Verzeichnis Tornado2.0\ta-rget\h\drv\end\unsupported. Erstellen Sie eine herunterladbare Projektdatei, wählen Sie den Parameter pcPentium3 aus, fügen Sie die in das Verzeichnis unsupported kopierte Datei rtl81x9.c zum Projekt hinzu und legen Sie die Kompilierungsparameter fest. Dadurch kann das kompilierte BootROM-Image das Herunterladen des VxWorks-Systems vom Host-Rechner auf den Zielrechner mithilfe der Realtek 81x9-Netzwerkkarte unterstützen. 4.2 Hinzufügen der PCI2040-Treiberunterstützung zum BSP: Erstellen Sie im Verzeichnis Tornado2.0\target\configpcPentium3BSP zwei Dateien: pci2040Drv.c und sysPci2040.c. Erstere ist für das Auffinden und Initialisieren von PCI-Geräten zuständig, letztere ordnet Speicherplatz im VxWorks-Betriebssystem anhand der Werte der Basisadressregister im PCI-Konfigurationsbereich zu und allokiert diesen. Definieren Sie in der Datei `pci2040Drv.c` zunächst eine Struktur, um die gefundenen PCI2040-Informationen zu speichern. Verwenden Sie dazu die folgende Definition: `typedef struct pci2040Dev { DEV_HDR devHdr; int BusNo; int DeviceNo; int FuncNo; ULONG membase0; ULONG membase1; unsigned char irq; int irqvec; } PCI2040_DEV;`. Suchen Sie anschließend mit der Funktion `pciFindDevice()` das Gerät anhand der angegebenen PCI2040-Hersteller-ID (0x104C) und Geräte-ID (0xAC60). Verwenden Sie dann die Funktion `pciConfig-InLong()`, um den Konfigurationsbereich des PCI2040 anzuzeigen. Es empfiehlt sich, die angezeigten Werte mit der Funktion `pciHeaderShow()` auszugeben, um zu überprüfen, ob das Gerät gefunden wurde. Rufen Sie abschließend die Funktion `iosDrvInstall()` auf, um verschiedene E/A-Dienste mit den geschriebenen Treiber-Serviceroutinen zu verbinden, den Treibern Werte zuzuweisen und sie der Treiberliste hinzuzufügen. Anschließend schreiben wir die Serviceroutine `pci2040DevCreate()`, um den PCI2040-Treiber zu erstellen. Hier können wir die verschiedenen Register des PCI2040 lokalisieren und initialisieren. Beispielsweise lokalisiert die folgende Anweisung das HPD-Register auf dem DSP: `pDspHpiDatawaRegister=pci2040Dev[0].membase1 + 0x800;`. Lese-, Schreib- und Interrupt-Serviceroutinen können in dieser Datei oder in der Anwendung selbst implementiert werden. In der Funktion `sysPci2040.c` wird die Funktion `sysMmuMapAdd()` verwendet, um die Adresszuordnung durchzuführen. Dabei wird der vom VxWorks-Betriebssystem verwaltbare Speicher den Registern des PCI2040 und des DSP zugeordnet und eine PCI-Brückenstruktur definiert, um die PCI2040-Informationen zur Systemidentifizierung zu speichern. Zusätzlich zum Schreiben dieser beiden Funktionen müssen einige Dateieinstellungen im BSP angepasst werden. Fügen Sie beispielsweise die Anweisung `#define INCLUDE_PCI` zur Datei `config.h` hinzu (um ein PCI-Modul hinzuzufügen) und die Anweisung `#include "sysBrdg.c"` zur Datei `sysLib.c` (um PCI-Bridge-Geräte zu unterstützen). 4.2 Anwendung schreiben und Betriebssystem kompilieren Schreiben Sie die Anwendung `usrAppInit.c` in die erstellte, herunterladbare Projektdatei. Sie ruft hauptsächlich Funktionen aus dem BSP auf, um Datenübertragung, -verarbeitung und Interrupt-Antworten durchzuführen. Die Interrupt-Service-Routine sieht beispielsweise wie folgt aus: `void pci2040Isr() { ... }` tempChar = *(pRegister + 0x4); if ((tempChar & 0x1) != 0) { *(pRegister + 0x4) = 0x1; tempV = *(pDspRegister); *(pDspRegister) = tempV | 0x0808; Printf("Interrupt aufgetreten!!!\n"); semGive(semForInt); } } Die Anweisung if((tempChar & 0x1) != 0) prüft, ob das Interrupt-Bit im HPI-CSR-Register auf 1 gesetzt ist. Ist dies der Fall, wurde ein Interrupt ausgelöst. Der Interrupt wird durch die Anweisung *(pRegister + 0x4) = 0x1 gelöscht, und das PC-Bit im HPIC wird durch die Anweisung *(pDspRegister) = tempV | 0x0808 gelöscht. Anschließend wird das Flag semForInt gesetzt, um den Interrupt für die Datenübertragung und -verarbeitung aufzurufen. Das Projekt wird in der Tornado-Umgebung kompiliert. Nach der Kompilierung wird im BSP-Verzeichnis eine VxWorks-Datei (ohne Dateiendung) generiert. Diese Datei ist das VxWorks-Image, das heruntergeladen und auf dem Zielrechner ausgeführt werden muss. 5. Zusammenfassung: Das Echtzeitbetriebssystem VxWorks verwendet offene Standards, wodurch Entwickler Systeme effizienter optimieren können. Es führt außerdem eine MMU-basierte Speicherschutztechnologie ein, die die Systemzuverlässigkeit deutlich verbessert. Der PCI-Local-Bus ist aktuell der Busstandard für PCs und industrielle Steuerungsrechner und bietet ausreichend Bandbreite für die Anforderungen an Hochgeschwindigkeits-Datenübertragung. Die Entwicklung von PCI-Treibern für das VxWorks-System kann den steigenden Anforderungen an die Datenübertragungsgeschwindigkeit in verschiedenen Systemen gerecht werden. Durch die Anpassung der entsprechenden Abschnitte dieses Artikels können BSP-Pakete für verschiedene PCI-Bridge-Chips entwickelt werden.