Sie sind auf Seite 1von 76

Diplomarbeit zum Thema

Transport von I/QSignaldaten über USB 2.0

und Verteilung zwischen Anwendungen

zur Erlangung des akademischen Grades

Diplom-Informatiker (FH)

vorgelegt der Fakultät


Elektrotechnik und Informatik
der
Fachhochschule Ingolstadt

Diplomand: Georg Hofstetter


Studiengang: Informatik
Ausgabedatum: 04.03.2009
Abgabedatum: 05.03.2009
Erstprüfer: Prof. Dr. Andreas Hagerer
Zweitprüfer: Prof. Dr. WolfDieter Tiedemann
Abstract

Um den Funkverkehr in einem drahtlosen Kommunikationsnetzwerk abzuhören, werden

heute moderne Rechnersysteme gepaart mit Spezialhardware verwendet, durch die bisher

aufwändige Analogschaltungen kostengünstig in Software implementiert werden können.

Im Rahmen dieser Diplomarbeit werden sowohl eine Firmware als auch ein Treiber für

eine solche Spezialhardware auf USBBasis entwickelt. Zudem wird eine Verteilungsschicht

entwickelt, mit der die gewonnenen Daten in Echtzeit parallel an verschiedene Programme

zur Weiterverarbeitung geleitet werden können. Dabei wird vor allem darauf geachtet,

bei möglichst hohen Übertragungsraten und geringen Verzögerungen Datenkonsistenz zu

gewährleisten.

In dieser Arbeit nden Techniken wie Semaphoren, Signalisierung, Mutex und Shared

Memory Anwendung. Auÿerdem befassen sich Teile der Arbeit mit der Programmierung

eines Mikrocontrollers und der Übertragung von Daten über den USBBus.

i
Danksagung

Zunächst möchte mich bei Herrn Berthold Graÿ dafür bedanken, dass ich meine Arbeit

an seinem Projekt als Diplomarbeit ausarbeiten durfte.

Ich möchte mich ebenfalls bei meinem Betreuer Herrn Prof. Dr. Andreas Hagerer und

dem Zweitkorrektor Herrn Prof. Dr. WolfDieter Tiedemann für das Lesen und Bewerten

dieser Arbeit bedanken.

Mein Dank gilt weiterhin Herrn Joachim Rosskopf, welcher mich mit Herrn Graÿ in Kon-

takt gebracht hat und mir damit diese Arbeit erst ermöglicht hat.

ii
Inhaltsverzeichnis

Abstract i

Danksagung ii

1 Einleitung 1
1.1 Beschreibung der Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . 3

1.2 Anforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2.1 Anwendungsszenarien . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2.2 Anforderungen an die Teilprojekte . . . . . . . . . . . . . . . . . . 5

1.3 Gliederung dieser Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Grundlagen 11
2.1 Aufbau der Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.1.1 HF-Teil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.1.2 Digitalisierungsteil . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.1.3 Digital Down Conversion . . . . . . . . . . . . . . . . . . . . . . . . 13

2.1.4 Datentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.1.5 Steuerung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.2 Das I/QFormat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Firmware 20

iii
3.1 Was sie leistet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.1.1 Initialisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

3.1.2 InterruptHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

3.1.3 Kommandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.1.4 Nutzdatentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.2 Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

4 Treiber 37
4.1 Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.1.1 Nachbildung der API der USB2.DLL . . . . . . . . . . . . . . . . . 38

4.1.2 Initialisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

4.1.3 Gerätefunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.1.4 Datentransfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

4.2 Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

4.3 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

4.3.1 Testsystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

4.3.2 Kritische Fehler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

4.3.3 Unkritische Fehler . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

5 Verteilungsschicht 53
5.1 Konzept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5.1.1 Weitere Designziele . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

5.1.2 Logischer Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

5.1.3 Shared Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5.2 Realisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.2.1 Shared Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.2.2 Synchronisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

iv
5.2.3 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

5.3 Performanceanalyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

Literaturverzeichnis vi

Eidesstattliche Erklärung ix

v
Kapitel 1

Einleitung

In der heutigen Zeit ist die drahtlose Kommunikation über elektromagnetische Wellen

nicht mehr aus dem Alltag wegzudenken. Menschen kommunizieren über Mobiltelefone,

verwenden schnurlose Babyphone, um das Schreien des Nachwuchs nicht zu überhören und

synchronisieren über Bluetooth die Kontakteinträge von PDA und Handy. Aber nicht nur

im zivilen Bereich ist man auf die dadurch nahezu uneingeschränkte Mobilität angewiesen,

sondern auch im Militärumfeld, da drahtgebundene Kommunikation oft gar unmöglich

und ein drahtloser Informationsaustausch demnach unausweichlich ist.

Die Verwendung elektromagnetischer Wellen hat jedoch auch zur Folge, dass jeder im

Empfangsbereich dieser Wellen und dem notwendigen Wissen über die Kodierung der

Nutzdaten in der Lage ist, diese unbemerkt zu dekodieren. Die Voraussetzung ist jedoch,

dass eine Einrichtung vorhanden ist, welche diese Wellen empfängt, sie entsprechend der

Kodierungsvorschrift dieser Übermittlung dekodiert und die daraus gewonnenen Nutzda-

ten ihrem Ursprung gemäÿ (Sprache, Bild, Text, . . . ) darstellt.

Gerade in den politischen Krisengebieten dieser Welt ist es wichtig, den dortigen Funk-

verkehr mitzuverfolgen. Nicht nur der Inhalt der Nachrichten ist in diesem Fall von Be-

deutung, sondern auch die Häugkeit und die Regelmäÿigkeit von Funksendungen spielen

eine Rolle. Dies sind Merkmale für die Aktivität militärischer Gruppen und Bewegungen

und lassen Rückschlüsse auf bevorstehende Einsätze zu.

Die Bundeswehrsoldaten im Bereich der Fernmeldeaufklärung überwachen dazu mit spezi-

ell dafür programmierten Anwendungen militärisch genutzte Frequenzbänder. Abbildung

1.1 zeigt eine solche Anwendung im Betrieb. Beim Auftreten einer Aktivität in einem

dieser Frequenzbereiche dekodieren, speichern und archivieren sie diese Daten in eigens

dafür programmierten Datenbanken. Diese Daten werden daraufhin je nach Inhalt sofort

1
Abbildung 1.1: Spektrogrammdarstellung durch die Bedienanwendung HyperFFT. Dieser

Ausschnitt zeigt den Frequenzbereich zwischen 9.350 MHz und 9.700 MHz, in dem sich

zwischen zwei AMRadiosendern ein DRMSender bendet (Digital Radio Mondiale [26]).

oder gesammelt an höhere Instanzen innerhalb der Bundeswehr weitergegeben. Mit Hilfe

dieser Informationen kann daraufhin eine Art Barometer für die militärische Stimmung

in diesem Gebiet erstellt werden; somit ist es möglich, rechtzeitig entsprechende Sicher-

heitswarnungen auszugeben.

Aufgrund der Leistungsfähigkeit und der Multimediatauglichkeit portabler Rechnersyste-

me bietet es sich an, den kostenintensiven HardwareAnteil auf ein Minimum zu beschrän-

ken und die notwendigen Schritte zur Rückgewinnung der Nutzdaten aus dem Funksignal

durch spezielle Software erledigen zu lassen. Dadurch ergibt sich auch die Möglichkeit,

die gewonnenen Daten ohne Qualitätsverluste im Rohformat auf Massenspeichern zu si-

chern, um diese später zu einem beliebigen Zeitpunkt verlustfrei weiter zu übermitteln,

zu verarbeiten oder genauer auf ihren Inhalt hin zu untersuchen.

2
1.1 Beschreibung der Aufgabenstellung

1.1 Beschreibung der Aufgabenstellung

Das Ziel dieser Diplomarbeit ist es, für eine Neuentwicklung eines USBFunkempfängers

mit dem Namen USBRX für den eingangs erwähnten Einsatzbereich zwei Bibliotheken

zu entwickeln.

Die erste Bibliothek muss eine API zur Verfügung stellen, mit der ein Zugri auf den

USBFunkempfänger aus Programmen unkompliziert möglich ist. Im Weiteren wird die-

se Bibliothek nur noch als Treiber bezeichnet. Dieser Treiber muss binärkompatibel zu

einem ähnlichen Treiber eines Drittanbieters sein, aber speziell für die verwendete Hard-

ware ausgelegt werden. Das bedeutet, dass die API fest vorgegeben ist und es gilt, das

Verhalten des Originaltreibers nachzubilden. Zur Programmierung eines solchen Treibers

ist es erforderlich, auch eine passende Firmware für das vorliegende Gerät zu entwickeln,

die während der Initialisierung auf einen InterfaceBaustein im Gerät geladen wird. Diese

Firmware muss fest im Treiber verankert werden.

Die zweite Bibliothek muss eine Schnittstelle zum Austausch von digitalisierten Funk-

daten zwischen Anwendungen zur Verfügung stellen. Der Austausch der Daten soll über

Shared Memory stattnden und so exibel sein, dass auch während des Betriebs umkon-

guriert werden kann, welche Anwendung ihre Daten an welche weitergibt. Das Starten

und Beenden von Anwendungen während Daten übertragen werden, darf zu keiner Be-

einträchtigung führen. Sinn der Verteilung ist es, während des Betriebs die empfangenen

Daten beliebig durch Zusatzlter, Aufnahmeblöcke oder Visualisierungstools weiterverar-

beiten zu lassen. Diese Zusatzprogramme werden unabhängig von dieser Arbeit und mit

unterschiedlichen Programmiersprachen entwickelt.

Abbildung 1.2 zeigt in einem Blockschaltbild, wie die verschiedenen Komponenten zu-

sammenarbeiten. Die grau schraerten Blöcke entsprechen denen, die in dieser Arbeit

behandelt werden.

Beide Bibliotheken müssen zum Betriebssystem Microsoft Windows XP kompatibel und

als eine Dynamic Link Library (DLL) verfügbar sein.

1.2 Anforderungen

Dieser Abschnitt behandelt die Anforderungen an die zu erstellenden Bibliotheken. Da-

zu wurde zunächst geklärt, welche Anforderungen die Firmware, der Treiber und die

Bibliothek zur Datenverteilung erfüllen müssen, indem alle Anwendungsszenarien dieses

3
1.2 Anforderungen

Abbildung 1.2: Blockschaltbild des Gesamtaufbaus

Empfängers und deren Anforderungen an die einzelnen Teilprojekte durchgegangen wur-

den. Diese wurden festgehalten und sowohl während der Arbeit als auch nach Abschluss

des Projektes veriziert.

1.2.1 Anwendungsszenarien

Spektrumanalyser

1
In diesem Szenario wird der Empfänger USBRX dazu verwendet, ein breitbandiges

Spektrum in einer SpektrogrammAnsicht [10, S. 191] darzustellen, welche die Signalstär-

ke in den überwachten Frequenzbereichen über die Zeitachse hinweg visualisiert. In dieser

Ansicht werden die Frequenzbänder durch den Anwender über längere Zeiträume hinweg

nach sporadisch aktiven Sendern durchsucht.

Um aus dem digitalisierten Funksignal eine spektrale Ansicht zu berechnen, wendet die Be-
2
dienanwendung auf einen Datenblock kongurierbarer Gröÿe eine KurzzeitSpektralanalyse

an. Das Resultat dieser Transformation wird dann im Spektrogramm dargestellt. In diesem

Szenario liefert ein im Gerät verbauter Digital Down Converter Daten je nach ausgewähl-
3
ter Filterbreite mit bis zu 18 MSamples/s an einen FIFOBaustein mit 32 KiSamples

1 In der aktuellen Ausführung mit bis zu 18MHz Breite


2 Schnelle Fouriertransformation, siehe [10, S. 176 ]
3 Im Folgenden werden für Zahlen, die auf Zweierpotenzen basieren die in DIN EN 60027-2:2007-11
denierten Binärpräxe (Ki, Mi, Gi, . . . ) verwendet, wo dies erforderlich ist.

4
1.2 Anforderungen

Kapazität. Ausgewertet werden durch die Bedienanwendung des Gerätes aber je nach

FFTBlockgröÿe lediglich Blöcke im Bereich von 512 Samples bis 16 KiSamples in Inter-

vallen von ca. 100 ms.

Bei einem Betrieb in diesem Szenario muss sichergestellt sein, dass der neu eingelesene

Block möglichst aktuelle Daten enthält und somit die Verzögerung zwischen der Digitali-

sierung durch das Gerät und der Darstellung durch die Anwendung sehr gering gehalten

wird. Zahlenmäÿige Anforderungen werden keine gestellt, jedoch soll der Code durch ent-

sprechendes elegantes Design möglichst wenig Verzögerungen verursachen.

Datenaufzeichung

Wird, wie soeben beschrieben wurde, ein Sender auf einer überwachten Frequenz gefunden,

so wird der Datenverkehr mit einer geringeren Bandbreite als bei der Spektrumanalyse

aufgenommen. Die Bandbreite wird in dem Fall der Breite des Sendesignals angepasst und

bewegt sich meist im Bereich von 10 kHz bis 600 kHz. Die Datenrate ist demnach mit bis zu

2400 KiByte/s relativ gering und es werden keine Ansprüche hinsichtlich der Verzögerung

vom Sampling bis zur Verfügbarkeit der Daten gestellt. Jedoch muss sichergestellt sein,

dass keine Daten verloren gehen, da dies einen Synchronisationsverlust und demzufolge

fehlerhafte Demodulation bedeuten würde.

Um bei Bedarf auch mit hohen Datenraten aufzeichnen zu können, sollten die Teilprojekte

entsprechend ausgelegt werden. Als Referenz dient hierfür der bisher verwendete Treiber,

welcher eine maximale Übertragungsrate von 12 MiByte/s ermöglicht.

Die Bedienanwendung wechselt ohne weitere Signalisierung zwischen den beiden Anwen-

dungsszenarien. Es liegt an der Treiberschicht und der Firmware, anhand des Verhaltens

der Bedienanwendung festzustellen, ob mit möglichst kleiner Verzögerung oder hohem

Durchsatz gearbeitet werden muss. Eine Modikation der Bedienanwendung wäre zwar

erforderlich, ist jedoch aus Kompatibilitätsgründen vorerst nicht vorgesehen.

1.2.2 Anforderungen an die Teilprojekte

In diesem Abschnitt werden an bestimmte Teile des Projektes verschiedene Anforderungen

gestellt, die hauptsächlich diesen Teil betreen oder dessen Verhalten genauer spezizie-

ren.

5
1.2 Anforderungen

Firmware

Die Firmware muss Befehle über einen Kontrollkanal entgegennehmen und ausführen.

Dazu muss sie einen Kommandoparser implementieren, mit dem die in Tabelle 1.1 be-

schriebenen Funktionen realisiert werden können.

Wird das Kommando zum Start der Datenübertragung aus dem FIFOBaustein gege-

ben, müssen diese über einen Datenkanal an den HostRechner geschickt werden. Dazu

soll ein im USBController vorhandener GPIFBlock verwendet werden, der speziell für

solche Aufgaben ausgelegt wurde. Dabei wird zwischen einem Transfermodus und einem

Blocktransfermodus unterschieden.

• Beim Blocktransfermodus wird eine angegebene Anzahl an Samples aus dem FIFO

Baustein gelesen und über den Bus zum Host geschickt. Dies ist vor allem für den

Betrieb als Spektrumanalyser wichtig, da bei dieser Betriebsart nur sporadisch Da-

tenblöcke für die Spektralanzeige benötigt werden. Nach dem Transfer dieses Blockes

muss die Firmware selbständig wieder in den IdleModus wechseln.

• Der normale Transfermodus hingegen ist für den Betrieb zur Datenaufzeichnung

bestimmt und muss die im FIFOBaustein vorhandenen Daten kontinuierlich zum

Host schicken, bis dieser den Vorgang durch Anforderung des IdleModus unter-

bricht.

Abbildung 1.3 zeigt ein Zustandsdiagramm, in dem diese Zustände graphisch dargestellt

werden. Unabhängig vom aktuellen Modus müssen alle eingehenden Kommandos bear-

beitet werden. Zusätzlich zu den vorgeschriebenen Modi dürfen weitere implementiert

werden, solange diese die sonstige Funktion nicht beeinträchtigen.

Treiber

Der Zugri der Bedienanwendung auf die Hardware soll über eine Dynamische Bibliothek

(.DLL) stattnden, welche sich hinsichtlich der API nicht von der Bibliothek [3] des Her-

stellers eines Entwicklungsboards unterscheiden soll. Die DLL dieses Herstellers wird im

Folgenden mit USB2.DLL bezeichnet.

Die USB2.DLL stellt verschiedene Funktionen zur Verfügung, mit denen ein am USBBus

angestecktes Board mit einem Cypress FX2LP initialisiert und angesteuert werden kann.

Die in der Bedienanwendung verwendeten Funktionen beschränken sich auf einige wenige,

6
1.2 Anforderungen

Abbildung 1.3: Zustandsdiagramm Firmware

Funktion Beschreibung
UsbOpen Önet ein am USBBus vorhandenes Gerät

UsbInit Initialisiert ein geönetes Gerät und lädt Firmware

UsbClose Schlieÿt dieses Gerät wieder

UsbSetIOState Setzt den Zustand eines I/OPins

UsbGetIOState Liest den Zustand eines I/OPins

UsbSetIODir Setzt die Richtung eines I/OPins

UsbGetIODir Liest die Richtung eines I/OPins


2
UsbI2CWriteBytes Schreibt Daten über I CBus
2
UsbI2CReadBytes Liest Daten über I CBus

UsbSpiTransfer Überträgt Daten über SPIBus

UsbParIn Liest Daten aus dem angeschlossenen FIFOBaustein

Tabelle 1.1: APIFunktionen der USB2.DLL

die in Tabelle 1.1 beschrieben werden. Diese Funktionen müssen so nachgebildet werden,

dass ein Wechsel zwischen der in dieser Arbeit erstellten Bibliothek und der USB2.DLL

zu Testzwecken ohne Veränderung der Bedienanwendung möglich ist.

Wird durch den Aufruf der Bibliotheksfunktion UsbParIn() der Transfer von Daten vom
USBRX initialisiert, so muss der Treiber die gelesenen Daten dem Aufrufer über einen

übergebenen Puer zurückliefern und zugleich über eine Verteilungsschicht weiteren An-

wendungen zur Verfügung stellen. Es ist dem Treiber überlassen, anhand des Verhaltens

der Bedienanwendung zu entscheiden, ob weitere Daten gelesen und bis zum nächsten

Aufruf der Funktion gepuert werden oder ob es bei einem BlockTransfer bleibt.

7
1.2 Anforderungen

Verteilung

Eine Verteilungsschicht muss durch eine weitere Bibliothek in Form einer DLL zur Verfü-

gung gestellt werden. Ihre Aufgabe ist es, die durch den Treiber gelesenen Daten möglichst

exibel und dynamisch kongurierbar Anwendungen zur Weiterverarbeitung zugänglich

zu machen. Zudem soll es diese Bibliothek ermöglichen, diese verarbeiteten Daten unkom-

pliziert zwischen Anwendungen auszutauschen.

Durch die Verwendung von Shared Memory für die Konguration soll eine MultiMaster
4
Architektur realisiert werden. Jede Instanz dieser Bibliothek muss demnach allein lauf-

fähig sein und zugleich mit weiteren Instanzen zusammenarbeiten können.

Das erforderliche Locking muss die Bibliothek selbst verwalten. Aus der Sicht des Anwen-

ders soll lediglich eine API mit sprechenden Namen sichtbar sein. Eine Übertragung von

Daten zwischen Anwendungen muss mit nur einem Funktionsaufruf auf jeder Seite ein-

gerichtet werden und mit ebenfalls nur einem Funktionsaufruf ausgelöst werden. Um den

Anwendungen ein asynchrones Senden und Empfangen der Daten zu ermöglichen, ist ein

Zwischenpuer erforderlich. Die gewünschten Puergröÿen können beim Einrichten einer

Übertragung angegeben werden, dürfen aber nicht durch die Bibliothek limitiert werden.

Sowohl die Gröÿe der übertragenen Datenblöcke als auch die Puergröÿe werden jedoch

nur ein Vielfaches von 4 Byte betragen, was der Gröÿe eines I/QSamples entspricht. Das

Übertragen von anderen Block und Puergröÿen kann geduldet werden, ist aber nicht

zwingend erforderlich.

Abbildung 1.4 zeigt, wie in einem BeispielAufbau die vom Gerät USBRX gelieferten

Daten an verschiedene Anwendungen weitergeleitet werden. Der Knoten  Archivierung

bezieht in dieser Konstellation die Daten vom vorhergehenden Knoten  Demodulation .

Die Verteilungsbibliothek muss es erlauben, dass sich Knoten während des Betriebs an

anderer Stelle in diesem Verteilungsbaum einklinken, so wie es in Abbildung 1.5 dargestellt

ist. Optimalerweise kann dieses Umkongurieren einzelner Knoten aus jeder Anwendung

heraus stattnden.

4 Lädt eine Anwendung eine DLL nach, so wird diese in den Speicher der Anwendung eingeblendet
und dort initialisiert. Jede gestartete Anwendung erzeugt somit eine weitere Instanz dieser DLL.

8
1.2 Anforderungen

Abbildung 1.4: Eine Beispielkonstellation unter Verwendung der Verteilungsschicht: Die

durch den Treiber des USBRX gelesenen Daten werden an den Knoten  Analyse und

 Demodulation geleitet. Diese verarbeiten die Daten weiter. Der Knoten  Demodulation

leitet die verarbeiteten Daten an zwei nachfolgende Knoten weiter.

Abbildung 1.5: Die Beispielkonstellation in Abb. 1.4 wurde umkonguriert, so dass der

Knoten  Archivierung nun die Rohdaten direkt vom Treiber des USBRX bezieht.

9
1.3 Gliederung dieser Arbeit

1.3 Gliederung dieser Arbeit

Im ersten Teil (Kapitel 2) werden die Grundlagen, insbesondere der Aufbau des Funkemp-

fängers, behandelt. Die Erklärung des I/QFormats ist hauptsächlich als Hintergrundin-

formation zu verstehen, da dieses bei der Implementierung selbst keine Rolle spielt.

Kapitel 3 beschreibt die Realisierung der erforderlichen Firmware für das USBGerät. Da-

bei wird genauer auf die Arbeitsweise und den Aufbau eingegangen. Der mit der Firmware

eng verbundene Treiber wird in Kapitel 4 behandelt und wird zunächst in Funktionsweise

und Aufbau beschrieben. Abschlieÿend werden verschiedene Tests zur Verizierung der

Anforderungen behandelt.

Der letzte Teil dieser Arbeit (Kapitel 5) befasst sich mit der implementierten Verteilungs-

schicht, die zum Austausch der Daten zwischen Anwendungen entwickelt wurde. Darin

wird neben dem Aufbau auch die Performance der Implementierung beleuchtet und auf

mögliche Verbesserungen eingegangen.

10
Kapitel 2

Grundlagen

Dieser Abschnitt behandelt die Grundlagen, die im Zusammenhang mit der verwendeten

Hardware und dem Format der durch diese Hardware gewonnenen Daten stehen. Diese

Informationen sind zum Verständnis dieser Arbeit zwar nicht zwingend notwendig, jedoch

sehr hilfreich.

2.1 Aufbau der Hardware

Das Gerät USBRX, für das die Bibliotheken erstellt werden sollen, ist als EinPlatinen

Lösung in SMDTechnologie gefertigt, welche alles beinhaltet, was für eine direkte Di-

gitalisierung von Funksignalen an einer Antenne notwendig ist. Abbildung 2.1 zeigt die

fertig bestückte Platine in der Draufsicht. Dem Blockschaltbild in Abbildung 2.2 sind

die verschiedenen Funktionsblöcke des Gerätes zu entnehmen, die in diesem Abschnitt

beschrieben werden. Das Gerät ist eine Neuentwicklung und vergleichbar mit dem als

Open Source Hardware veröentlichten USBGerät USRP ( Universal Software Radio

Peripheral [9]).

2.1.1 HF-Teil

Der HFTeil besteht gröÿtenteils aus passiven Bauteilen. Hier wird das Eingangssignal

zunächst mit einem AntiAliasingFilter (AAF) vorgeltert, um die Frequenzbereiche,

die über der halben Samplefrequenz des AnalogDigitalConverters liegen, herauszul-

tern. Dieser AAF ist notwendig, da durch die im nächsten Teil folgende AnalogDigital

Konvertierung die eingehenden Frequenzbereiche sich sonst im digitalisierten Ausgangs-

11
2.1 Aufbau der Hardware

Abbildung 2.1: USBRX SMDPlatine

Abbildung 2.2: Blockschaltbild des USBRX

12
2.1 Aufbau der Hardware

signal überlappen würden und dadurch ein unbrauchbares oder sehr störbelastetes Signal

entstünde [11, S. 159].

Weiterhin benden sich in diesem Bereich HalbleiterAnalogschalter, mit denen durch die

Bedienanwendung das Quellsignal aus mehreren Eingängen gewählt werden kann. So ist

es möglich, ohne Umzustecken zwischen Signalen unterschiedlicher Antennen oder Emp-

fängerschaltungen auszuwählen. In künftigen Varianten dieses Boards wird es zusätzliche

Analogschalter geben, mit denen verschiedene AntiAliasingFilter vorgewählt werden

können, um bestimmte Bänder herauszultern.

2.1.2 Digitalisierungsteil

Das vorgelterte HFSignal wird durch einen AnalogDigitalConverter (ADC), der mit

bis zu 100 Mio. Abtastungen pro Sekunde arbeitet, in ein Digitalsignal konvertiert. Dazu

wird zu jedem Abtastzeitpunkt der Pegel des Eingangssignals erfasst und als vorzeichen-

behafteter, binär kodierter Wert auf den Ausgängen des ICs zur Verfügung gestellt.

Der auf dieser Platine verbaute ADC arbeitet je nach Bestückung fest auf den Frequenzen

48, 96 oder 100 MHz. Somit können im ankommenden TiefpassSignal je nach Taktfre-

quenz des ADC die Frequenzen von 0 Hz bis 24, 48 oder 50 MHz digitalisiert werden. Eine

Erklärung dazu bietet das Abtasttheorem von Shannon, welches in [1, S. 926] ausführlich

beschrieben wird.

Das Ausgangssignal des ADC ist ein 14 Bit breites Datum im Zweierkomplement und wird

direkt an den nachfolgenden Schaltkreis, den Digital Down Converter, weitergeleitet.

2.1.3 Digital Down Conversion

Das vom AnalogDigitalConverter kontinuierlich gelieferte 14 Bit breite Datensignal

beinhaltet alle Informationen über das Funksignal, die für eine Darstellung und Deko-

dierung am Rechner notwendig wären; jedoch ist es mit einer Datenrate von bis zu 1,4

GBit/s zu hochratig, um es in dieser Form über die USB 2.0 Schnittstelle zu übertragen.

Aus diesem Grund wurde ein Digital Down Converter (DDC) verbaut, der das digitalisier-
5
te Eingangssignal zunächst in das Basisband herabsetzt und danach in seiner Bandbreite

begrenzt. Zur Begrenzung der Bandbreite werden in diesem Baustein digitale FIRFilter

5 Ein Quellsignal, welches nicht durch Modulation in einen höheren Frequenzbereich verschoben vor-
liegt, bendet sich im Basisband.

13
2.1 Aufbau der Hardware

eingesetzt, die über ein SPIInterface frei kongurierbar sind. Somit kann auf der Bedie-

nerseite eingestellt werden, in welchem Frequenzbereich ein Signal mit welcher Bandbreite

herausgeltert werden soll. Die Ausgabe dieses Signals erfolgt im I/QFormat, welches ne-

ben der Amplitude des Signals zusätzlich die Phasenlage beinhaltet.

Das Funksignal im I/QFormat (siehe Abschnitt 2.2) benötigt 32 Bit je Sample, wovon

sowohl der IAnteil als auch der QAnteil jeweils 16 Bit belegen. Die Datenrate dieses

Signals ist von der Breite des Filters im Digital Down Converter abhängig. Eine nähere

Erläuterung den Aufbau dieses Formats betreend, ist in ebenfalls in Abschnitt 2.2 zu

nden.

2.1.4 Datentransfer

Das vom Digital Down Converter erzeugte, digitalisierte I/QSignal wird über den USB

Bus zur verarbeitenden Anwendung geleitet. Dazu schreibt dieser die Daten mit seiner

ArbeitsDatenrate in einen FIFO, der 64 KiWörter mit bis zu 18 Bit Breite fasst. Um

dennoch die 32 Bit des I/QSignals übertragen zu können, werden I und QAnteil ge-

trennt voneinander alternierend mit 16 Bit Breite in den FIFO geschrieben. Somit kann

der FIFO maximal 32 KiSamples puern.

Durch einen speziellen USB Interface Chip werden die Daten wieder aus dem FIFO gele-

sen. Bei diesem Interface Chip handelt es sich um einen Cypress EZUSB FX2LP, einem

USB 2.0 HighSpeed Interface Controller. Er unterstützt alle in der USBSpezikation [25,
2
Abschnitt 4.7, S. 20] denierten Transfermodi und bietet neben I C, SPI und frei program-

mierbaren Ein und Ausgängen ein GPIF ( General Purpose Interface ), welches Daten

selbständig und ohne Software-Interaktion aus dem FIFOBaustein lesen und direkt über

USBPakete an den Host weiterleiten kann. Die Konguration des FX2LP wird durch die

Firmware im integrierten, 8051kompatiblen Mikroprozessor vorgenommen, welche beim

Initialisieren des Gerätes über USB hochgeladen werden muss.

Die USBseitige Datenübertragung mit dem FX2LP wird durch das USB Interface über

sogenannte Endpoints (EP) abgewickelt. Während der Initialisierung durch die Firmware

können bis zu 5 benutzerdenierte Endpoints festgelegt werden, die Daten im Bulk, Inter-

rupt oder Isochronous Modus entweder senden oder empfangen können. So können neben

dem Endpoint, über den automatisiert die I/QDaten übertragen werden, auch weitere

eingerichtet werden, über die eine Anwendung Befehle an den FX2LP sendet und Antwor-

ten dazu empfängt. Der Eingang eines Datenpaketes über Endpoints wird der Firmware

über Interrupts mitgeteilt, die entsprechend abgehandelt werden müssen.

14
2.2 Das I/QFormat

2.1.5 Steuerung

Aufgrund der begrenzten Zahl an Ein/Ausgängen des FX2LP wurde zusätzlich ein Atmel
2
ATMega32 verbaut, der über I C angesprochen wird. Seine Aufgaben sind:

• Konguration des Digital Down Converters

• Reset des FIFOBausteins

• Ansteuern der Analogumschalter

• Ansteuern weiterer Ausgänge für LEDs etc.

Diese Aufgaben werden durch eine Firmware erledigt, die im FlashSpeicher des ATMega32

gespeichert ist. Diese Firmware wurde durch Herrn Graÿ erstellt und ist nicht Teil dieser
2
Arbeit. Die Ansteuerung des I CBusses soll durch den FX2LP vorgenommen werden, die

Kommandos dazu werden jedoch unverändert von dessen Firmware durchgereicht. Somit
2
ist im FX2LP neben der notwendigen Logik, um als I C Bus Master zu arbeiten, nichts

weiter erforderlich.

2.2 Das I/QFormat

Dieser Abschnitt geht genauer auf das Datenformat ein, welches ab der Digital Down

Conversion durchgängig zum Datenaustausch verwendet wird.

Mathematische Bedeutung

Die Modulation von Nutzdaten mit einer Trägerfrequenz kann allgemein mit folgender

Gleichung beschrieben werden [23, S. 565]:

s(t) = a(t) · cos(ω(t) · t + ϕ(t)) (2.1)

Das dabei entstehende Trägersignal s(t) besitzt die Amplitude a(t) und die Frequenz ω(t)
mit dem Phasenwinkel ϕ(t). Sowohl Frequenz und Phasenwinkel als auch die Amplitude

sind Zeitfunktionen und können in Abhängigkeit von der Modulationsart variieren. Da

eine sich ändernde Frequenz ω(t) auch durch einen sich kontinuierlich ändernden Phasen-
winkel ϕ(t) dargestellt werden kann, wird der Übersicht wegen ω(t) weiter nur noch als ω
bezeichnet. Die sich verändernde Frequenz wird daher durch ϕ(t) repräsentiert.

15
2.2 Das I/QFormat

Abbildung 2.3: Zusammenmischen des I und QAnteils zum Trägersignal

Betrachtet man die Erläuterung zur physikalischen Bedeutung in [4, S. 183], lässt sich

diese Gleichung auch darstellen als

s(t) = i(t) · cos(ωt) − q(t) · sin(ωt) (2.2)

i(t)
p
mit der Amplitude a(t) = i(t)2 + q(t)2 und dem Phasenwinkel tan(ϕ(t)) = − q(t) . Die

Variable i(t) wird weiterhin als  In Phase oder kurz IAnteil und q(t) als  Quadrature

Phase bzw. QAnteil bezeichnet. Beide Variablen sind unabhängig voneinander. Diese

Form der Darstellung ndet vor allem in der digitalen Signalverarbeitung ihre Anwendung.

Abbildung 2.3 veranschaulicht den Vorgang der Modulation. Die Multiplikation wird in

diesem Schaltbild durch einen Mischer repräsentiert, die Addition durch den Addierer.

Die Signale cos(ωt) und sin(ωt) dienen bei der Modulation als Träger.

Das durch die Modulation entstandene Trägersignal s(t) kann nun über ein geeignetes

Medium wie z. B. in Form elektromagnetischer Wellen durch die Luft übertragen und da-

nach einem Demodulator zur Rückgewinnung zugeführt werden. Bei der Rückgewinnung

der I und QAnteile wird das Trägersignal wie in Abbildung 2.4 skizziert mit den glei-

chen Trägern (frequenz und phasengleichen Sinus/KosinusSignalen) multipliziert wie

eingangs bei der Modulation.

i0 (t) = s(t) · 2 · cos(ωt)


(2.3)
q 0 (t) = s(t) · −2 · sin(ωt)

16
2.2 Das I/QFormat

Mit Hilfe der Produktgleichungen von trigonometrischen Funktionen [4, S. 182],

1

cos(a) · cos(b) = 2
cos(a − b) + cos(a + b)
1

cos(a) · sin(b) = 2
sin(a − b) + sin(a + b) (2.4)
1

sin(a) · sin(b) = 2
cos(a − b) − cos(a + b)

entstehen nach dem Einsetzen der Gleichung 2.2 in die Gleichungen 2.3 und Umformen

die Gleichungen:

0
i (t) = 2 · i(t) · 12 · cos(0) + cos(2 · ωt)


+q(t) · 12 · sin(0) + sin(2 · ωt)
 (2.5)
q 0 (t) = 2 · i(t) · 12 · sin(0) + sin(2 · ωt)


1

−q(t) · 2 · cos(0) − cos(2 · ωt)

Ersetzt man in diesen Gleichungen sin(0) durch den Wert 0 und cos(0) durch den Wert

1, ergeben sich nach dem Umstellen folgende Gleichungen:

i0 (t) = i(t) + i(t) · cos(2 · ωt) + q(t) · sin(2 · ωt)


(2.6)
q 0 (t) = q(t) + i(t) · sin(2 · ωt) + q(t) · cos(2 · ωt)

In Gleichung 2.6 ist zu erkennen, dass noch immer ein unerwünschter Anteil mit dem

Doppelten der Trägerfrequenz (cos(2 · ωt), sin(2 · ωt)) vorhanden ist. Dieser kann lediglich
mit Hilfe eines idealen Tiefpasses mit der Grenzfrequenz fGrenz < 2 · ω herausgeltert

werden. Nach der Tiefpasslterung fällt dieser Anteil weg und es gilt:

i0 (t) = i(t)
(2.7)
q 0 (t) = q(t)

Die Abbildung 2.4 stellt die Demodulation und die Tiefpasslterung noch einmal schema-

tisch dar.

Das bedeutet, obwohl sowohl i(t) als auch q(t) in dem Trägersignal s(t) übertragen wur-

den, können diese bei der Demodulation korrekt zurückgewonnen werden. Somit sind die

beiden zurückgewonnenen Anteile i0 (t) und q 0 (t) ebenso orthogonal zueinander. Da die I

und QAnteile orthogonal zueinander sind, können sie auch in einem sog. Konstellations-

diagramm wie in Abbildung 2.5 dargestellt werden.

Die Repräsentation eines Trägersignals durch die Komponenten I und Q ist die Basis für

viele digitale Modulationsverfahren. Aber auch analoge Modulationen wie die Amplitu-

17
2.2 Das I/QFormat

Abbildung 2.4: Rückgewinnung des I und QAnteils aus dem Trägersignal

Abbildung 2.5: Konstellationsdiagramm eines QPSKSignals (2-PSK, 4-PSK, 8-PSK) [23,

S. 573]

18
2.2 Das I/QFormat

Abbildung 2.6: Reihenfolge und Aufbau von Samples im FIFOPuer

denmodulation oder die Frequenz bzw. Phasenmodulation können durch dieses Format

einfach dargestellt und weiterverarbeitet werden.

Digitale Repräsentation

Wie bereits eingangs erwähnt wurde, liefert der DDC die I und QAnteile mit einer

Auösung von je 16 Bit, also mit einer Breite von 32 Bit je Sample. Im weiteren Ver-

arbeitungspfad (FIFO, FX2LP) ist es nicht möglich, die Samples mit der vollen Breite

von 32 Bit zu übertragen. Aus diesem Grund wurde eine Schaltung verbaut, welche die

16 BitAnteile eines Samples sequentiell in den nachgeschalteten FIFO schreibt. Abbil-

dung 2.6 illustriert, in welcher Reihenfolge die Samples bzw. deren Anteile in den FIFO

geschrieben werden. Eine weitere Hardwareschaltung stellt sicher, dass auch nach einem

Reset des FIFO die Reihenfolge I, Q, I, Q, . . . eingehalten wird. Ein Vertauschen von I und

Q (Q, I, Q, I, . . . ), oder das Verlieren eines I oder Q (I, Q, Q, . . . ) würde unbrauchbare

Daten liefern, da I und QAnteile nicht voneinander unterscheidbar sind.

Die Werte der beiden Komponenten werden im Zweierkomplement dargestellt und decken

demnach einen Wertebereich von -32768 bis +32767 ab. Diese Werte beziehen sich auf eine

Referenzspannung im Digitalisierungsteil des Gerätes, auf die hier nicht näher eingegangen

wird.

19
Kapitel 3

Firmware

Dieses Kapitel befasst sich mit den Aufgaben und dem Aufbau der Firmware für den

verwendeten HighSpeed USBPeripheral Controller FX2LP (CY7C68013A) der Firma

Cypress. Dieser Controller ist für die Kommunikation zwischen der Rechnerseite und der

Hardware zuständig und ist so kongurierbar, dass er die meisten Transfers autonom

durchführen kann. Dazu bietet der FX2LP mehrere Funktionsblöcke, die aufeinander ab-

gestimmt sind. Abbildung 3.1 zeigt den Aufbau des Controllers in einem Blockschaltbild.

Die im Controller integrierte SIE ( Serial Interface Engine ) und das USBInterface sind

in der Lage, USBPakete unabhängig vom 8051Prozessor entgegenzunehmen und zu ver-

senden. Sie müssen dazu jedoch zuerst konguriert werden - ohne vorherige Konguration

stellen sie nur den von der USBSpezikation geforderten Control Endpoint 0 (EP0) zur

Verfügung, über den automatisch nach dem Anstecken des Gerätes die USBKonguration

vorgenommen wird. Der Endpoint 0 bietet jedoch dem Treiber die Möglichkeit durch spe-

Abbildung 3.1: Blockschaltbild des Cypress FX2 [5]

20
3.1 Was sie leistet

6
zielle  Vendor Commands die Firmware in den Speicher des FX2LP zu laden und zur

Ausführung zu bringen. Die Firmware kann danach ihren Dienst verrichten.

3.1 Was sie leistet

Die Aufgaben der Firmware für diesen USBController sind:

• Initialisierung des FX2LP

• Befehle vom Host entgegennehmen und abarbeiten

2
• Zugri auf I C, SPI und I/Os über spezielle Befehle

• Signaldaten an den Host übertragen

3.1.1 Initialisierung

Während der Initialisierung müssen der Prozessor und die verwendeten Variablen und

Speicherbereiche in einen denierten Zustand gebracht werden. Dies muss von der Firm-

ware im ersten Schritt erledigt werden, um eine lauähige Umgebung für den weiteren

Code vorzubereiten. Weiter ist es die Aufgabe der Firmware, den FX2LP zunächst so

zu kongurieren, dass sich dieser in einem Leerlaufzustand bendet und auf weitere Be-

fehle vom Treiber wartet. Dieser Zustand wird im FirmwareZustandsdiagramm (siehe

Abbildung 1.3) als IdleModus bezeichnet.

Reset Vector

Der im FX2LP integrierte 8051kompatible Prozessorkern wird nach dem Anstecken der

Hardware an den USBBus und dem Download der Firmware in einen denierten Zu-

stand zurückgesetzt. Die Programmausführung beginnt beim Reset Vector an Adresse

0x0000(hex). Da sich an dieser Stelle nur Platz für einen 3 Byte groÿen Sprungbefehl

ndet [5, S. 4-1], muss dort ein Sprungbefehl zum eigentlichen Initialisierungscode stehen.

Der folgende Auszug aus der Datei 'interrupts.asm' zeigt den Code am Reset Vector:

6 Diese werden in [25, Abschnitt 9.3.1, S. 248] explizit erlaubt. Abbildung 3.4 listet die im Controller
vergebenen Vendor Commands auf.

21
3.1 Was sie leistet

Listing 3.1: ResetVector in interrupts.asm

. area interrupt_area ( ABS )


. org 0 x0000 ; Reset Vector Address
_entry ::
ljmp #0 x0380 ; Reset Vector - Jump to C entry point

Wie dem CodeBeispiel zu entnehmen ist, springt der 8051Kern durch die Ausführung

des LJMPBefehls zur Adresse 0x0380(hex), an welcher sich der Programmcode zur

weiteren Initialisierung bendet.

Speicherinitialisierung

Ab Adresse 0x0380(hex) bendet sich die __sdcc_gsinit_startupRoutine[22]. Diese

füllt den Speicherbereich statischer und globalen Variablen mit ihren Startwerten, initia-

lisiert den StackPointer und bereitet weitere Register der CPU auf die Ausführung der

eigentlichen Hauptroutine vor. Nachdem alle Speicherbereiche entsprechend ihrer Verwen-

dung initialisiert wurden, springt die Initialisierungsroutine zur mainRoutine, in der die

Initialisierung der Peripherie vorgenommen werden muss.

Der Code zur Speicherinitialisierung wird von der verwendeten Compilersuite automa-

tisch erzeugt und erfordert keine manuellen Änderungen. Die Speicherbereiche und deren

Inhalt werden während des LinkVorganges auf der Grundlage der durch den CCompiler

gelieferten Informationen erzeugt.

Peripherie

Zu Beginn der Hauptroutine main() muss zunächst die ausstehende Initialisierung der

Peripherie vorgenommen werden. Dies betrit hauptsächlich das USBInterface, in das

beim FX2LP sämtliche USBrelevanten Tätigkeiten ausgelagert wurden. So ist die 8051

CPU von sämtlichen Aktivitäten auf dem USBBus entkoppelt und übernimmt lediglich

steuernde Aufgaben. Über einen gemeinsam Speicherbereich, spezielle Register und In-

terrupts kann die Firmware jedoch auch auf eingehende Pakete reagieren und selbst das

Senden von solchen veranlassen.

USBInterface: Das USBInterface ist verantwortlich für die USBseitige Kommuni-

kation. Es hat bei der Anmeldung des Geräts am Bus dem HostRechner lediglich den

22
3.1 Was sie leistet

Endpoint 0 bekannt gemacht. Eine einfache Nachmeldung von weiteren Endpoints ist

zum Ausführungszeitpunkt der Firmware nicht mehr möglich. Jedoch bietet der Cypress

FX2LP eine Möglichkeit, das Gerät logisch vom Bus zu trennen und neu zu verbinden.
7
Cypress bezeichnet diesen Vorgang als ReNumeration . So ndet eine Neuanmeldung des

Gerätes am USBBus statt.

Um mit Hilfe dieser Möglichkeit weitere Endpoints zu registrieren, müssen die bei einer

Neuanmeldung auftretenden SetupPakete durch die Firmware beantwortet werden. Der

Cypress FX2LP bietet jedoch Hilfsmittel, die den FirmwareEntwicklern diesen Vorgang

erleichtern.

Empfängt das USBInterface während der Kongurationsphase ein SETUPPaket vom

USBHost, so legt es die SETUPDaten in einen dedizierten Speicherbereich und löst

einen SUDAVInterrupt aus. Abbildung 3.2 veranschaulicht dies. Das Format des Setup

Pakets ist in der USB 2.0 Spezikation festgelegt und der Abbildung 3.3 zu entnehmen.

Je nach RequestCode muss die Firmware nun die entsprechenden Aktionen durchführen

bzw. die erwarteten Deskriptoren zur Verfügung stellen. Abbildung 3.4 zeigt eine ausführ-

liche Liste der denierten Requests und den erwarteten Aktionen der Firmware.

Um SetupRequests zu beantworten, welche einen USBDeskriptor anfordern, bietet

das USBInterface mit den Registern SUDPTRH und SUDPTRL (Setup Data Pointer

High/Low) eine Schnittstelle, in die lediglich die Speicheradresse des zu sendenden De-

skriptors geschrieben werden müssen. Nachdem diese Register beschrieben wurden, schickt

das USBInterface die Deskriptoren automatisch im korrekten Format an den Host. Die
8
Anzahl der zu sendenden Bytes wird den Deskriptoren selbst entnommen .

Auf diese Art und Weise kann der komplette Enumerationsvorgang (SETUPPhase)

mit Hilfe eines einfachen switch/case Blockes innerhalb des Handlers für den SUDAV

Interrupt abgehandelt werden.

Deskriptoren: Die USBSpezikation ermöglicht es, dass einem USBGerät eine Viel-

zahl von logischen Kongurationen zugewiesen werden. Diese Informationen werden dem

Host bei der Anmeldung des Gerätes am Bus durch Deskriptoren mitgeteilt. Der Host kann

das Gerät dann während des Betriebs anweisen, zwischen den verschiedenen angebotenen

Kongurationen umzuschalten. Auf diese Weise ist es möglich, dass ein Treiber ein Gerät

7 ReNumeration, siehe [5, S. 1-10]


8 Zum Format der Deskriptoren siehe [25, Abschnitt 9.6]

23
3.1 Was sie leistet

Abbildung 3.2: Interrupts beim Empfang eines SETUPPaketes [5]

Abbildung 3.3: Format der SETUPDaten [5]

Abbildung 3.4: SETUP request codes [5]

24
3.1 Was sie leistet

Abbildung 3.5: Kongurationen, Interfaces und AlternativSetups eines logischen USB

Gerätes [5]

z. B. in einen SleepModus schickt, in dem es auÿer dem obligatorischen ControlEndpoint

0 keine weiteren Endpoints mehr anbietet.

Zusätzlich bieten Interfaces und AlternativSetups eine Möglichkeit, Gerätefunktionen

zu unterteilen und über unterschiedliche EndpointKonstellationen darauf zuzugreifen.

Abbildung 3.5 illustriert die Zusammenhänge zwischen Kongurationen, Interfaces und

AlternativSetups. Für dieses Projekt ist es jedoch ausreichend, eine einzige Konguration

mit nur einem Interface ohne AlternativSetups zu registrieren.

Weiter werden dem Host in den Deskriptoren durch spezielle  Vendor und  Product

IDs zudem mitgeteilt, von welchem Hersteller und welchem Typ das Gerät ist. Anhand

dieser Informationen kann ein Treiber feststellen, ob er für dieses Gerät zuständig ist.

Zum Zeitpunkt der Erstellung dieser Firmware wurden noch keine eigenen IDs für dieses

Gerät erworben. Deswegen wurden zunächst die Vendor ID des Hersteller Cypress und

eine unbelegte Product ID verwendet. Diese können und müssen im Nachhinein durch das

Abändern von symbolischen Denitionen im Quelltext angepasst werden.

25
3.1 Was sie leistet

Bezeichner Richtung
IN Transfer vom Gerät zum Host

OUT Transfer vom Host zum Gerät

Tabelle 3.1: Transferrichtung auf einem USBBus

Bei der Transferrichtung zwischen einem USBHost und einem Endgerät spricht die USB

Spezikation von IN und OUT Transfers (siehe Tabelle 3.1.1). Die Transferrichtung ist

immer aus der Sicht des HostRechners zu sehen und wurde daher unmissverständlich

deniert. Diese Nomenklatur wird in dieser Arbeit beibehalten.

Um eine logische Trennung zwischen den Kommandos an die Firmware bzw. Antworten

auf diese und den Signaldaten aus dem Digitalisierungsteil zu realisieren, werden zwei

unabhängige Kanäle benötigt:

• Kontrollkanal: Über diesen Endpoint werden Kommandos und Antworten dar-

auf abgewickelt. Sowohl die Rate als auch die Gröÿe der Pakete sind sehr gering,

die Daten werden aber in beide Richtungen ausgetauscht (Transferrichtung IN und

OUT).

• Datenkanal: Dieser Endpoint dient zur Übertragung der I/QSignaldaten an den

Host (Transferrichtung IN). Dieser Kanal ist unidirektional, da nur Daten vom Gerät

an den Host übertragen werden, muss aber mit sehr hohen Datenraten zurechtkom-

men.

Als geeigneter Kontrollkanal bietet sich der  lowbandwidth Endpoint 1 an. Dieser un-

terstützt zwar lediglich Transfers mit einer Gröÿe von maximal 64 Byte, was aber für die

Kommandos in Tabelle 1.1 auf Seite 7 vollkommen ausreicht. Von diesen zu implemen-
2
tierenden Kommandos besitzen lediglich die I C und SPIKommandos eine Payload mit

variabler Gröÿe. Die Bedienanwendung schickt diese Kommandos aber nur mit maximal
9
8 Byte Nutzdaten (zzgl. Overhead) und ist somit deutlich unter der 64ByteGrenze.

Dieser Endpoint ist speziell für Kontrollkanäle ausgelegt und teilt sich keine Ressourcen

mit den  highbandwidth Endpoints.

Beim Datenkanal ist die Wahl des korrekten Endpoints im Gerät ebenfalls sehr einfach.

Durch die externe Beschaltung des FX2LP ist vorgegeben, dass die aus dem externen FIFO

9 Dies wurde durch einen Blick auf den Quellcode der Anwendung ermittelt

26
3.1 Was sie leistet

gelesenen Daten in den Puer des Endpoint 6 geschrieben werden. Dies wird durch die

Pins FIFOADR0/1 festgelegt und wird aus Kompatibilitätsgründen zum Originaltreiber

auch bei neueren Layouts beibehalten. Deshalb ist der Endpoint 6 als Datenkanal zu

verwenden.

Für die Wahl der passenden PuerKonguration muss auf Abbildung 3.6 aus dem Tech-

nical Reference Manual [5] verwiesen werden. In dieser Abbildung sind die im FX2LP

verfügbaren Endpoints in allen möglichen Kombinationen aufgeführt. Verfügbare  high

bandwidth Endpoints sind zunächst die Endpoints 2, 4, 6 und 8 mit zwei Puern zu je

512 Byte (double buered). Werden die Endpoints 2 oder 6 so konguriert, dass sie vier

Puer (quad buered) zu je 512 Byte oder zwei zu je 1024 Byte besitzen, so sind EP4

bzw. EP8 nicht mehr verfügbar. Weiterhin ist es auch möglich, einem einzigen Endpoint

(EP2) vier Puer mit je 1024 Byte zuzuweisen, oder gemischte Kongurationen, bei de-

nen drei Puer (triple buered) zum Einsatz kommen. Die Endpoints 0 und 1 sind nicht

kongurierbar und besitzen eine fest kodierte Puergröÿe von 64 Bytes.

Bei diesem Projekt wurde sich für die QuadbuerVariante mit vier 512 Byte Puern

entschieden. Aus Performancegründen schied eine Variante mit zwei Puern aus, da erst

ab drei Puern eine Übertragung ohne Wartezyklen gewährleistet ist. Bei zwei Puern

muss gewartet werden, bis ein Puer voll und der andere Puer leer ist, bevor diese beiden

Puer getauscht werden können (Wechselpuertechnik). Dies könnte beim Transfer mit

höheren Datenraten zu unnötigen Verzögerungen führen. Demnach stehen für den EP6

nur die Kongurationen 4x512 und 3x512 zur Wahl. Da jedoch die letzte Variante das

Setup aller anderen Endpoints vorschreiben würde und lediglich die Variante 4x512 noch

genug Freiraum für zukünftige Erweiterungen bietet, wurde sich für diese entschieden.

Für beide Endpoints wird der BulkTransfermodus verwendet. Dieser Transfermodus ist

für groÿe Datenmengen ausgelegt und stellt sicher, dass keine Daten verloren gehen. Bei

einem Übertragungsfehler wird das fehlerhafte Paket bis zu drei mal wiederholt. Der

ebenfalls für groÿe Datenmengen ausgelegte Isochrone Modus dagegen stellt zwar eine

feste Bandbreite zur Verfügung die auch bei hoher Buslast garantiert wird, verwirft aber

fehlerhafte Pakete. Beide Modi erlauben es, mit Datenraten von 53.248.000 Byte/s (Bulk

Modus [25, S. 55]) beziehungsweise 49.152.000 Byte/s (Isochroner Modus [25, S. 46]) zu

übertragen, und sind deswegen hinsichtlich der Übertragungsrate nahezu gleichwertig.

Da jedoch bei beiden Endpoints die Datensicherheit im Vordergrund steht, ist der Bulk

Modus die bessere Wahl. Der InterruptTransfermodus scheidet grundsätzlich aus, da

dieser nur für sporadisch anfallende Daten wie z. B. bei Computermäusen oder Tastaturen

ausgelegt ist.

27
3.1 Was sie leistet

Abbildung 3.6: Endpoints und PuerGröÿen [5]

Kanal Endpoint Modus Richtung Puer


Kontrollkanal EP1 Bulk IN/OUT 1 x 64 Byte

Datenkanal EP6 Bulk IN 4 x 512 Byte

Tabelle 3.2: EndpointKonguration

Überlegt wurde, den Kontrollkanal über den Control Endpoint 0 abzuwickeln. Laut Ab-

bildung 3.4 stehen dafür frei belegbare Vendor Request Codes zur Verfügung. Jedoch

erschien es sinnvoll, diesen Kontrollkanal logisch von dem für das USBSetup wichtigen

ControlEndpoint zu trennen. Das Verpacken von eigenen Gerätekommandos in Vendor

Commands birgt zum einen ein zu groÿes Risiko hinsichtlich Konikte durch Änderungen

bzw. Erweiterung der Anforderungen und nutzt zum anderen nicht die durch den FX2LP

gegeben Möglichkeiten aus.

In Tabelle 3.1.1 ist die gewählte Konguration noch einmal übersichtlich dargestellt. Ent-

sprechend dieser Tabelle werden die Kongurationsregister des USBInterface und die

USBDeskriptoren gewählt.

28
3.1 Was sie leistet

3.1.2 InterruptHandling

Wie nahezu jedes MikrocontrollerSystem besitzt auch der Cypress FX2LP eine Vielzahl

an InterruptQuellen. Bei der Realisierung dieses Projektes werden nur die notwendig-

sten Arbeiten über Interrupts erledigt. Die folgenden Interrupts sind in dieser Arbeit zu

behandeln:

• USB SetupInterrupt

• KontrollkanalInterrupt

• GPIF Transfer Interrupt

• Timerinterrupt zur Überwachung (Watchdog)

USB SetupInterrupt: Wie in Abschnitt 3.1.1 angesprochen, treten bei der ReNume-

ration  also der Neuanmeldung des Geräts am USBBus  Interrupts auf. Der zugehörige

SUDAVInterrupthandler ist einfach zu realisieren, da dessen Hauptaufgabe darin besteht,

dem USBInterface je nach eingegangenem RequestCode die Adresse der zu antworten-

den Daten mitzuteilen. Bei der weiteren Verwendung des Gerätes treten keine Interrupts

dieser Art mehr auf.

KontrollkanalInterrupt: Sobald ein Paket auf dem KontrollkanalEndpoint eintrit,

löst das USBInterface einen EP1OUTInterrupt aus. Dieser muss durch eine geeignete In-

terrupt Service Routine bedient werden. Beim Auftreten eines solchen Interrupts durch ein

eingehendes Kommando, trägt der Handler dieses Kommando ungeprüft in einen Puer

zur asynchronen Weiterverarbeitung durch die Hauptschleife ein. Eine sofortige Verarbei-

tung des Kommandos im Handler würde die Ausführung der Hauptschleife u.U. zu einem

ungünstigen Zeitpunkt unterbrechen oder andere Interrupts verzögern, daher ist dieser

möglichst kurz zu halten. Eine Überprüfung der Gültigkeit der Kommandos wäre an die-

ser Stelle zwar möglich, würde aber bedeuten, dass neue Kommandos an mehreren Stellen

im Code eingepegt werden müssten, die zudem in unterschiedlichen Kontexten arbeiten.

Aus diesem Grund wird die Überprüfung und die Abarbeitung der eingegangenen Kom-

mandos asynchron durch die Hauptschleife erledigt. Dies birgt keine besonderen Risiken,

da der Handler im Fehlerfall nur ein Kommando unnötigerweise in den Kommandopuer

einträgt, das danach in der Hauptschleife verworfen wird.

29
3.1 Was sie leistet

GPIF Transfer Interrupt: Wird der GPIFBlock angewiesen, eine bestimmte An-

zahl von Transfers durchzuführen, erledigt er diese Arbeit unabhängig von der Firmware.

Nachdem dieser alle Transfers abgeschlossen hat, löst er einen GPIFDONEInterrupt aus,

um dies der Firmware mitzuteilen. An dieser Stelle muss der InterruptHandler die im

FirmwareZustandsdiagramm (siehe Abbildung 1.3) angegebenen Aktionen einleiten. In

der aktuellen Version dieser Arbeit wird dies jedoch noch durch Polling innerhalb der

Hauptschleife realisiert, was weniger ezient ist.

Timerinterrupt zur Überwachung: Als zusätzliche Sicherheitsfunktion bietet es sich

an, den Timer als sog. Watchdog zur Überwachung der Vorgänge zu verwenden. Tritt

ein erwartetes Ereignis nicht innerhalb einer dafür vorgesehenen Zeitspanne ein, kann

im Interrupthandler je nach Ereignis eine entsprechende Maÿnahme ergrien werden. So

könnte z. B. ein Ausbleiben von Kommandos durch die Bedienanwendung automatisch

eine ReNumeration auslösen, um das Gerät neu am Bus zu registrieren. Zu beachten wäre

allerdings, dass ein Problem dieser Art in der Regel auf Fehler in der Programmierung zu-

rückzuführen ist. Daher wurde sich bei dieser Arbeit mehr darauf konzentriert, Fehlerfälle

zu vermeiden, anstatt durch einen Watchdog eine Schadensbegrenzung durchzuführen.

3.1.3 Kommandos

Eine Aufgabe der Firmware ist es, Kommandos, die von der Bedienanwendung über den

Treiber abgesetzt werden, zu behandeln.

Wie im Abschnitt 3.1.2 erläutert, werden die Befehle durch den InterruptHandler in einen

Kommandopuer geschrieben. Die vom Treiber über ein USBPaket empfangenen Kom-

mandopakete bestehen aus einem Byte KommandoID gefolgt von einer variablen Anzahl

Datenbytes (siehe Abbildung 3.7). Um auch bei einem unbekannten oder fehlerhaften

Kommandopaket eine korrekte Abarbeitung zu gewährleisten, wird im Interrupthandler

zu jedem Kommandopaket auch dessen Länge mit in den Kommandopuer geschrieben.

Sollte bei der Weiterverarbeitung durch die Hauptschleife ein ungültiges Kommando er-

kannt werden, kann dieses so ignoriert und anhand dessen Längeneintrag weiter zum

nächsten Kommando gesprungen werden.

Auf aufwändige Sperrmechanismen oder einen umständlichen Ringpuer kann bei ge-

eigneter Wahl des Puerzugris verzichtet werden. Da nur die Hauptschleife durch den

Interrupthandler unterbrochen werden kann, muss nur sichergestellt werden, dass keine

nichtatomaren Vorgänge durch den InterruptHandler beeinusst werden. Dazu wird die

30
3.1 Was sie leistet

Abbildung 3.7: a) Kommandopaket, wie es über den USBBus empfangen wird b) Kom-

mando mit Längenfeld c) Platzierung im Kommandopuer

Position des Kommandos im Puer ähnlich wie bei einem Ringpuer mittels Start und

EndeZeiger angezeigt. Da jedoch beide Zeiger nach vollendeter Abarbeitung aller und vor

dem Eintragen eines neuen Kommandos auf den Anfang des Puers zurückgesetzt wer-

den, stehen die Daten immer am Anfang des Puers. Sollte der EndeZeiger beim Eingang

eines neuen Kommandos über das Ende des Puers hinausgehen, wird das Kommando

verworfen.

Der entscheidende Vorteil dieser Puerart gegenüber einem Ringpuer ist die Einsparung

eines zusätzlichen Puers für den Fall, dass das Kommando im Puer umgebrochen wurde.

Mit dieser Puerart kann der behandelnden Kommandoroutine direkt die Adresse der Da-

ten im Puer übergeben werden. Der Nachteil ist allerdings, dass bei einer groÿen Anzahl

an eingehenden Kommandos der Hauptschleife diese nicht mehr schnell genug abarbeiten

kann. Dieses Risiko ist leicht zu umgehen, indem der Treiber lediglich wenige Kommandos

schickt und dann auf eine Antwort wartet, dass diese Kommandos abgearbeitet wurden.

Auf den Kommandopuer wird demnach in folgender Weise zugegrien:

• InterruptHandler

1. setzt Anfangs und EndeZeiger auf Null, sollten sie gleich sein. So wird bei

einem leeren Puer das nächste Kommandopaket immer an den Anfang des

Puers geschrieben.

2. schreibt das empfangene Kommandopaket an der Position des EndeZeigers in

den Puer.

3. erhöht den EndeZeiger um die Gröÿe des Pakets.

31
3.1 Was sie leistet

Abbildung 3.8: Kommandopuer a) im Anfangszustand b) mit einem Kommando c) mit

zwei Kommandos d) erstes Kommando durch Hauptschleife abgearbeitet e) nach Abar-

beitung beider Kommandos f ) zurückgesetzt bei Empfang eines neuen Kommandos

• Hauptschleife

1. wartet bis Anfangs und EndeZeiger ungleich sind, als Indikator für ein vor-

handenes Kommando.

2. behandelt das im Paket enthaltene Kommando.

3. schickt eine Antwort an den Treiber.

4. erhöht den AnfangsZeiger um die Gröÿe des abgearbeiteten Kommandos.

Da der InterruptHandler beim Zufügen eines Kommandos nur den EndeZeiger des Puf-

fers verändert, nicht aber die bereits im Puer stehenden Kommandos und damit das

Längenbyte des momentan abgearbeiteten Kommandos, sind alle Operationen der Haupt-

schleife sicher. Der Sonderfall im InterruptHandler wenn Start und Ende gleich sind,

beide Zeiger auf Null gesetzt werden, setzt voraus, dass die Hauptschleife zu diesem Zeit-

punkt nichts abarbeitet. Diese wartet darauf, dass beide Zeiger ungleich sind bevor sie

mit dem Abarbeiten des Kommandos beginnt. Da die Ausführung des InterruptHandlers

nicht durch die Hauptschleife unterbrochen wird, sind dessen Operationen grundsätzlich

als atomar anzusehen.

Die Befüllung und Abarbeitung von Kommandos im Puer wird in Abbildung 3.8 noch

einmal graphisch dargestellt.

Nachdem ein Kommando abgearbeitet wurde, schickt die Firmware ein Paket mit der

KommandoID zurück. So kann auf der Treiberseite sichergestellt werden, dass dieses

32
3.1 Was sie leistet

Kommando Beschreibung
CMD_GET_MODE Lese aktuellen Betriebsmodus

CMD_IDLE_MODE Setze Leerlaufmodus

CMD_GPIF_MODE Setze GPIF Transfermodus

CMD_GPIF_BLK_MODE Setze GPIF Blocktransfermodus

CMD_SPI_TRANSFER Daten via SPIBus übertragen


2
CMD_I2C_WRITE Schreibe Daten über I CBus
2
CMD_I2C_READ Lese Daten über I CBus
2
CMD_I2C_SPEED Setze I CGeschwindigkeit

CMD_IO_STATE_SET Setzt den Zustand eines I/OPins

CMD_IO_DIR_SET Setzt die Richtung eines I/OPins

CMD_IO_STATE_GET Liest den Zustand eines I/OPins

CMD_IO_DIR_GET Liest die Richtung eines I/OPins

Tabelle 3.3: Vorgesehene FirmwareKommandos

Kommando auch abgearbeitet wurde. Handelt es sich um ein Kommando, das Antwort-

daten erforderlich macht, wie z. B. CMD_I2C_READ werden diese Daten zusammen

mit der KommandoID zurückgeschickt.

Auf diese Art und Weise kann der Treiber eine Kombination mehrerer Kommandos ge-

bündelt an die Firmware schicken und auf die Abarbeitung dieser warten.

Tabelle 3.3 listet die entsprechend Tabelle 1.1 implementierten Kommandos auf. Diese

liefern je nach Typ die entsprechenden Rückgabedaten.

3.1.4 Nutzdatentransfer

Der Transfer der Daten aus dem FIFOBaustein der Platine über den USBBus zum

Treiber ist die Hauptaufgabe dieses Gerätes. Diese Aufgabe wird im Wesentlichen autonom

durch die in Abbildung 3.1 dargestellten Blöcke GPIF ( General Purpose Interface ) und

dem USB Interface erledigt. An dieser Stelle muss jedoch der Begri FIFO noch einmal

genauer erläutert werden.

Der in Abschnitt 2.1.4 angesprochene FIFOBaustein wird im Weiteren als  externer

FIFO bezeichnet. Dessen Aufgabe ist es, die vom DDC eintreenden Daten zu puern

und in der korrekten Reihenfolge wieder an den FX2LP auszugeben.

33
3.1 Was sie leistet

Innerhalb des Cypress FX2LP gibt es aber noch eine weitere Art von FIFO. Das USB

Interface im FX2LP stellt dem GPIFBlock Puer zur Verfügung, in die dieser Daten

schreiben kann. Wie in Abschnitt 3.1.1 erklärt, werden mehrere dieser Puer  in dieser

Konguration 4 Puer zu je 512 Byte  zusammengeschalten und als Puer für einen

Endpoint verwendet. Der GPIFBaustein kann zu einem Zeitpunkt nur immer auf den

Puer zugreifen, den das USBInterface zum Füllen markiert hat. Zu diesem Zweck imple-

mentiert das USBInterface eine Art FIFOBaustein, in den der GPIFBlock die Daten

schreibt. Dieser interne FIFO wird im Weiteren als  Endpoint FIFO (in [5] u. A. auch

als  Slave FIFO ) bezeichnet.

Dieser Endpoint FIFO ist vom Prinzip her vergleichbar mit dem externen FIFOBaustein.

Jedoch werden die hineingeschriebenen Daten nicht von einer anderen Schaltung ausge-

lesen, sondern durch das USBInterface automatisch über den USBBus an den Host

geschickt, sobald dieser Daten anfordert. Die Firmware muss lediglich den GPIF so kon-

gurieren, dass dieser selbständig eine bestimmte Anzahl an Transfers aus dem externen

FIFO an die Endpoint FIFOs schreibt. Dabei beachtet er selbst die entsprechenden Signale

die einen vollen Endpoint FIFO mitteilen.

Die Konguration des GPIF wird über eine Vielzahl von Registern vorgenommen, über

die Taktrate, I/OLeitungen und die Waveform  die Vorgehensweise beim Auslesen des

externen FIFO  festgelegt werden. Dies ist sehr komplex, wird aber durch das Tool

 Cypress GPIF Designer erleichtert, welches dem Entwickler ein graphisches Interface

zur Konguration anbietet und auf Knopfdruck fertigen CCode zur Einbettung in das

eigene Projekt erstellt. Abbildung 3.9 zeigt einen Screenshot dieser Anwendung. Die in

dieser Arbeit verwendete Konguration wurde im Vorfeld von Herrn Graÿ erstellt und für

diese Arbeit zur Verfügung gestellt.

Die durch das Tool erzeugte Konguration wird bei jedem Wechsel in einen GPIFModus,

also sowohl beim kontinuierlichen Transfermodus als auch beim Blocktransfermodus, ak-

tiviert. Die Anzahl der durchzuführenden Transaktionen wird über ein weiteres Register

angegeben. Im Blocktransfermodus ist demnach die von der Firmware angeforderte An-

zahl an 16BitWörtern zu schreiben. Nachdem diese Transfers abgeschlossen wurden,

muss die Firmware entsprechend der Anforderungen wieder in den IdleModus wechseln.

Beim kontinuierlichen Transfermodus kann in dieses Register ein beliebiger Wert geschrie-

ben werden  es ist nur sicherzustellen, dass nach Durchführung aller Transaktionen dieses

Register erneut beschrieben wird. So wird den Anforderungen entsprechend eine durch-

gehende Übertragung gewährleistet.

34
3.1 Was sie leistet

Abbildung 3.9: Hauptdialog des Cypress GPIF Designer

35
3.2 Aufbau

Abbildung 3.10: Quelldateien der Firmware

3.2 Aufbau

Die Firmware ist zum gröÿten Teil in C programmiert. Lediglich die InterruptVektoren

und USBDeskriptoren sind aus Gründen der Positionierung im Speicher in Assembler

programmiert. Abbildung 3.10 zeigt die Quelldateien gruppiert nach Aufgaben und Typ.

Im Folgenden werden die Aufgaben der CDateien stichpunktartig aufgelistet:

• main.c nimmt die grundlegende Initialisierung vor, beinhaltet den Zustandsautomat


und die Hauptschleife

• interrupts.c handelt die eingegangen Interrupts ab, erledigt die in Abschnitt 3.1.1
beschriebene USBSetupBehandlung und das Einreihen der Kommandos in den

Kommandopuer

• commands.c arbeitet die im Kommandopuer stehenden Kommandos ab

• gpif_setup.c beinhaltet die durch den GPIF Designer generierte Konguration

• io,spi,i2c,gpif.c kapseln die entsprechenden Hardwarezugrie in eigene Routi-

nen

Diese Dateien werden mittels eines Makele und dem Small Devices C Compiler [21]

zu einer .hexDatei kompiliert. Aus dieser .hexDatei werden durch ein spezielles Tool

CStrukturen generiert, die später in einen Treiber eincompiliert werden können. Ins-

besondere für die InterruptAbwicklung dient ein Demoprojekt von Nathan Friess und

Patrick McNeil [8] als hervorragende Referenz.

36
Kapitel 4

Treiber

Dieses Kapitel behandelt den Treiber für das Gerät USBRX, durch den ein Zugri auf

die Funktionen des Gerätes vereinfacht werden. Bei diesem Treiber handelt es sich um eine

Treiber-Bibliothek für den UserSpace, die nur geladen wird, wenn die Bedienanwendung

dies anfordert. Das kann schon beim Laden der Bedienanwendung in den Speicher durch
10
das Betriebssystem erfolgen , oder aber während der Laufzeit durch spezielle Betriebs-
11
systemfunktionen .

Programmcode, der im UserSpace läuft hat keine Berechtigung, um direkt auf Hardware

zuzugreifen. Zugrie dieser Art können lediglich über BetriebssystemFunktionen durch-

geführt werden, die solche Anforderungen an KernelModeTreiber weiterleiten. Dem

gegenüber stehen die KernelModeTreiber, die im Kontext des BetriebssystemKernels

arbeiten und automatisch durch das Betriebssystem geladen werden. Ihre Aufgabe ist

es, die aus dem UserSpace angeforderten Zugrie auf die Hardware durchzuführen. Die

Existenz eines passenden KernelModeTreiber für das Gerät USBRX ist aus den ange-

führten Gründen zwingend erforderlich.

Um aus dem UserSpaceKontext, in dem der Treiber dieser Arbeit ausgeführt wird, auf

die USBHardware zugreifen zu können, wird sich der CyAPIBibliothek bedient. Die-
12
se stellt der Hersteller des Cypress FX2LP kostenlos zur Verfügung und besteht aus

einem KernelModeTreiber und einer statisch linkbaren UserSpaceBibliothek. Durch

10 Durch dynamisches Linken der Anwendung gegen die Treiber-Bibliothek wird später schon beim
Starten der Anwendung die Treiber-Bibliothek in den Speicher geladen.
11 Nachträgliches Laden von Bibliotheken mittels LoadLibrary, siehe [13]
12 Verfügbar als Teil der SuiteUSB [7]

37
4.1 Aufgaben

die CyAPIBibliothek können die Zugrie auf den Cypress FX2LP einfach realisiert wer-

den.

4.1 Aufgaben

Die Aufgaben des Treibers sind:

• Nachbildung der API der USB2.DLL

• Initialisierung des USBRX

2
• Zugri auf Gerätefunktionen wie I C, I/O und SPI

• Durchführung des Datentransfers vom Gerät zum Rechner

4.1.1 Nachbildung der API der USB2.DLL

Da dieser Treiber nicht von der USB2.DLL, einer Treiber-Bibliothek eines Drittherstellers,

zu unterscheiden sein soll, muss er auch deren API nachbilden. Beim Design des Treibers

wurde sich aber nicht auf den Aufbau der USB2.DLLAPI gestützt, sondern eine eigene,

interne API deniert, die jedoch alle Möglichkeiten bietet, die das Original auch erlaubt.

Durch speziellen WrapperCode wird die erwartete API nach auÿen hin nachgebildet.

Besonders bei Neuentwicklungen geht man Risiken ein, wenn man das komplette Design

nach der erwarteten API ausrichtet. Spätere Erweiterungen erfordern zudem umständ-
13
liche Hilfsmaÿnahmen , um diese zu realisieren und kompatibel zu bleiben. Deswegen

wurde zunächst ein TreiberKern mit einer eigenen, internen API deniert, mit dem un-

ter anderem die erwartete Funktionalität der USB2.DLL realisiert werden kann. Diese

API ist zunächst nicht nach auÿen sichtbar, sondern nur für speziellen WrapperCode zu-

gänglich. Die Funktionen der USB2.DLL, die nachgebildet werden müssen, werden durch

einen Wrapper realisiert, der die entsprechenden Aufrufe an die interne API weiterreicht.

Hilfsmaÿnahmen, die später aus Kompatibilitätsgründen eingeführt werden müssen, kön-

nen in diesem Wrapper untergebracht werden, ohne dass der TreiberKern durch solche

verändert werden muss.

13 Im Bereich heutiger PCkompatiblen Rechner gibt es viele solcher Hilfsmaÿnahmen um Rückwärts-


kompatibilität einzuhalten: A20Gate, Int30h, PAE, 1MiByteHole etc.

38
4.1 Aufgaben

Abbildung 4.1: Konzept des TreiberKerns und Wrapper für unterschiedliche Anwen-

dungsszenarien

Abbildung 4.2: Vendor und Product ID des Cypress FX2 [5]

Abbildung 4.1 veranschaulicht dieses Konzept in einer Grak. Die Bedienanwendung greift

über den USB2.DLL Wrapper auf den TreiberKern zu. Dieser Wrapper kann gegen einen

anderen ausgetauscht werden, um eine neuere API oder eine API für andere Einsatzzwecke

zur Verfügung zu stellen. Der in der Abbildung aufgeführte Java JNIWrapper ermöglicht

es beispielsweise, diese Treiber-Bibliothek direkt aus JavaAnwendungen zu verwenden.

Dieser ist nicht Teil der Anforderungen, sondern wurde aus Demonstrationsgründen zu-

sätzlich entwickelt.

Wird im Weiteren von einem Aufruf von Treiberfunktionen oder APIAufrufen geschrie-

ben, handelt es sich - sofern nicht anders angegeben - dabei um einen Aufruf der API

Funktionen, die der USB2.DLLWrapper bereitstellt.

4.1.2 Initialisierung

Beim Start der Bedienanwendung fordert diese den Treiber durch den Aufruf der Treiber-

funktionen UsbOpen() und UsbInit() auf, ein vorhandenes Gerät zu initialisieren. Bei

diesem Vorgang bezieht der Treiber über die CyAPI eine Liste der angeschlossenen USB

Geräte, iteriert durch diese und überprüft jedes Gerät auf dessen Vendor und Product ID

(siehe Abschnitt 3.1.1). Da zu diesem Zeitpunkt in das neu angesteckte Gerät noch keine

Firmware geladen wurde, sind die durch den Hersteller des FX2LP vorkongurierten IDs

aktiv. Diese sind in Abbildung 4.2 aufgelistet.

39
4.1 Aufgaben

Bezeichnung Vendor ID Product ID


USBRX ohne Firmware 0x04B4 0xEE00

USBRX mit Firmware 0x04B4 0xEE01

Tabelle 4.1: Verwendete Vendor und Product IDs

2
In späteren Revisionen des USBRX wurde ein serielles I CEEPROM verbaut, aus dem

der Cypress FX2LP beim Anmelden an den USBBus die zu verwendenden IDs liest.

So kann sich das Gerät auch ohne Firmware als USBRX zu erkennen geben. Auf diese

Weise riskiert man im späteren Betrieb keine Verwechslung mit DevelopmentBoards


14
oder anderen Geräten . Um zwischen einem USBRX mit Firmware und einem ohne

Firmware unterscheiden zu können, werden dafür jeweils unterschiedliche IDs verwendet.

Tabelle 4.1.2 zeigt die verwendeten IDs.

Wird ein Gerät gefunden, das die in der Tabelle 4.1.2 angegebenen Vendor und Product

IDs besitzt, wird versucht, dieses zu reservieren. Dieser Reservierungsvorgang ist so ge-

staltet, dass zunächst ein  Named Mutex [15], also ein im Betriebssystem durch einen

Namen eindeutig identizierter Mutex, erstellt wird. Der Name dieses Mutex wird von

der im Betriebssystem eindeutigen ID des Ports abgeleitet, an dem das USBGerät an-

geschlossen ist. Die Existenz dieses Mutex bedeutet, dass das Gerät an diesem USBPort

bereits durch eine Instanz des Treibers belegt ist. Teilt das Betriebssystem mit, dass dieser

Mutex bereits vorher existierte, wird der Reservierungsvorgang abgebrochen und weiter

nach einem freien Gerät gesucht. Dieser Mutex bleibt so lange bestehen, bis der Treiber

das Gerät wieder freigibt. Auf diese Art und Weise ist sichergestellt, dass auch mehrere In-

stanzen dieses Treibers parallel laufen können, ohne dass es zu Zugriskonikten kommt.

Das erforderliche Locking wird durch Verwendung des Mutex schon vom Betriebssystem

übernommen.

Ist das gefundene Gerät noch nicht durch eine andere Instanz belegt, wird eine interne

GeräteinfoStruktur für dieses Gerät angelegt, in der sich alle für die weitere Verwen-

dung notwendigen Informationen darüber benden. Dies umfasst neben dem Handle des

ReservierungsMutex auch verschiedene Handles u. A. von der der CyAPIBibliothek,

TransferStatistiken und Betriebszustände. Über diese GeräteStruktur wird im Treiber

das Gerät und dessen Zustand identiziert.

14 Durch Verwendung der originalen Vendor und Product IDs des Chipherstellers für ein Endgerät kam
es bereits zu Problemen. Microsoft Windows XP lieferte einen Treiber für einen USB DVBTEmpfänger
mit, der die Standard IDs verwendet. Anwender von Development Boards konnten deswegen nicht mehr
auf dieses zugreifen, da automatisch der falsche Treiber geladen wurde. Siehe dazu auch [2], [24].

40
4.1 Aufgaben

Wird anhand der Product ID erkannt, dass das Gerät noch keine Firmware besitzt, wird

diese über die Vendor Commands des Cypress FX2LP (siehe Abbildung 3.4) in den Spei-

cher des FX2LP geladen und zur Ausführung gebracht. Das Binärabbild der Firmwa-

re wurde vorab im BuildProzess in CStrukturen konvertiert und in den Treiber ein-

compiliert. Somit besitzt jede Version des Treibers die Firmware, für die er entwickelt

wurde. Probleme wegen Inkompatibilitäten durch unterschiedliche TreiberFirmware

Kombinationen sind daher ausgeschlossen.

Wie bereits im Kapitel 3 beschrieben, trennt sich das Gerät bei der FirmwareInitialisierung

vom USBBus und registriert sich neu. Es ist davon auszugehen, dass sich das Gerät dar-

aufhin am selben USBPort wieder anmeldet. Daher wird gewartet, bis das Gerät mit

der entsprechenden Product ID an diesem USBPort wieder verfügbar ist, oder bis ein

Timeout auftritt. Die Dauer bis zu diesem Timeout wurde auf eine Minute festgelegt, da

beim erstmaligen Anmelden des Geräts mit der neuen Product ID das Betriebssystem

nach Treibern sucht, was mehrere Sekunden dauern kann. Tritt ein Timeout auf, werden

alle Strukturen und Handles wieder freigegeben und dies der aufrufenden Routine der

Bedienanwendung über einen Fehlercode mitgeteilt.

Nachdem das Gerät sich neu angemeldet hat und die in Tabelle 3.1.1 angegebenen End-

points zur Verfügung stellt, werden diese mit Hilfe der CyAPI geönet und die entspre-

chenden Handles dazu in der GeräteinfoStruktur des Treibers eingetragen. Über einen

geeigneten Rückgabewert wird der aufrufenden Routine ein GeräteHandle zurückgege-

ben, mit dem diese GeräteinfoStruktur später eindeutig referenziert werden kann. Dies

erlaubt es, mit einer Instanz des Treibers mehrere Geräte zu bedienen, sofern die Bedi-

enanwendung das unterstützt.

4.1.3 Gerätefunktionen

Mittels der API des Treibers kann eine Anwendung auf verschiedene Gerätefunktionen
2
zugreifen. Als Gerätefunktionen werden die Zugrie auf den SPI und I CBus bezeichnet,

sowie das Kongurieren, Abfragen und Setzen der I/OPins.

Um das zu verwendende Gerät eindeutig zu identizieren, erfordert jeder APIAufruf

die Angabe des GeräteHandles, welcher bei der Registrierung zurückgegeben wurde.

Durch diesen Handle kann aus der entsprechenden GeräteinfoStruktur der Kommando

Endpoint entnommen werden. Über diesen KommandoEndpoint werden die in Tabelle

3.3 aufgeführten Kommandos abgesetzt. Der Treiber wartet nach jedem abgesetzten Kom-

mando auf die Mitteilung der Firmware über eine erfolgreiche Ausführung. Handelt es sich

41
4.1 Aufgaben

2
um Kommandos mit Rückgabedaten, wie z. B. dem Lesen vom I CBus, werden diese der

aufrufenden Routine in einen beim Funktionsaufruf angegebenen Puer geschrieben.

Weitere Tätigkeiten sind bei der Implementierung dieser Gerätefunktionen nicht erforder-

lich.

4.1.4 Datentransfer

Die Hauptaufgabe des Treibers ist es, das vom USBRX digitalisierte Funksignal aus

dessen FIFOBaustein an die Bedienanwendung bzw. an die Verteilungsschicht zu über-

tragen. Die Bedienanwendung startet die Datenübertragung durch den Aufruf der API

Funktion UsbParIn() und erwartet nach dessen Rücksprung die gelesenen Daten in einen
beim Aufruf angegebenen Puer.

Um Daten vom DatenkanalEndpoint des USBRX zu lesen, müssen mit Hilfe der CyAPI

zunächst Transfers gestartet werden. Die Gröÿe dieser Transfers ist laut USBSpezikation

begrenzt (siehe dazu [25, S. 54]). Ein einzelnes BulkPaket auf dem USBBus kann ma-

ximal 512 Byte Nutzdaten fassen und wird mit anderen Paketen in Transfers gebündelt.

Maximal 13 BulkPakete können bei einer Nutzdatengröÿe von je 512 Byte zu einem

USBTransfer zusammengefasst werden. Demnach ist die maximale Datenmenge, die bei

einem USBTransfer auf einmal übertragen werden kann, auf 6656 Byte begrenzt. Die

CyAPIBibliothek startet deshalb bei durch deren Funktion BeginDataXfer() eingelei-

teten Übertragungen bei Bedarf mehrere Transfers entsprechend der angeforderten Daten-

menge. Um eine optimale Übertragungsrate zu erzielen, empehlt es sich jedoch, Daten

immer in Blöcken anzufordern, die einem Vielfachen von 6656 Byte entsprechen. Nur so

kann der Verwaltungsoverhead durch CyAPI, Kernel und USBController gering gehalten

werden.

Der Start von Transfers wird durch den Aufruf der Funktion BeginDataXfer() des ent-

sprechenden EndpointHandles erledigt. Diese Funktion weist den KernelModeTreiber

an, Transfers zu initialisieren, welche asynchron durch den USBController durchgeführt

werden. Nachdem ein Transfer gestartet wurde, muss mittels WaitForXfer() auf dessen

Fertigstellung gewartet und durch FinishDataXfer() wieder freigegeben werden. Danach


stehen die übertragenen Daten zur Verfügung.

Ein solch gezielter Start von Transfers und dem Warten auf die Fertigstellung stellt kein

Problem dar, wenn nur einzelne Blöcke übertragen werden müssen. Für das geforderte

42
4.1 Aufgaben

Anwendungsszenario  Betrieb als Spektrumanalyser ist diese Art der Datenübertragung

absolut ausreichend.

Wird allerdings versucht, das digitalisierte Funksignal aufzuzeichnen, werden die Transfers

immer nur durchgeführt, wenn die Bedienanwendung dies explizit durch den Aufruf von

UsbParIn() einleitet. Während die Anwendung die beim letzten Aufruf übertragenen

Daten auswertet oder in eine Datei schreibt, ndet keine Aktivität auf dem USBBus statt.

Für Aufzeichnungen mit niedrigen Datenraten gibt es trotz der suboptimalen Ausnutzung

der Ressourcen keine Probleme. Jedoch bei Aufzeichnungen mit einer hohen Datenrate

wird der FIFOBaustein im USBRX nicht häug genug ausgelesen. Die Folge ist ein

Überlaufen des Puers im FIFOBausteins und damit der Verlust von Daten.

Um einen solchen Datenverlust zu verhindern, werden die Transfers über Threads abge-

wickelt. So können die Threads eine Übertragung mit maximaler Datenrate durchführen,

während die Bedienanwendung die beim letzten Aufruf der Funktion UsbParIn() gelese-

nen Daten weiterverarbeitet.

Threading

Die Aufgabe des Datentransfers wird durch zwei Threads erledigt, die beim Initialisieren

des Gerätes gestartet werden. Ein InitializeThread leitet die Transfers ein, auf deren

Fertigstellung in einem ProcessThread gewartet wird. Beide Threads schlafen so lange,

bis sie durch den anderen Thread oder durch den Aufruf von UsbParIn() aufgeweckt

werden. Dazu wurden bei der Initialisierung EventObjects [12] für beide Threads zur

Synchronisation angelegt und deren Handles in der GeräteStruktur des Treibers abgelegt.

Wird von der Bedienanwendung durch Aufruf der APIRoutine UsbParIn() ein Daten-

block mit einer bestimmten Gröÿe angefordert, muss zunächst zwischen den in den An-

forderungen beschriebenen Anwendungsszenarien unterschieden werden.

Spektrumanalyser: Wird die Bedienanwendung als Spektrumanalyser verwendet, for-

dert sie Daten nur in Intervallen von ca. 100ms an. Das Volllaufen des FIFOBausteins

auf dem USBRX würde bei kleinen Blockgröÿen eine für den Benutzer unerwünschte

Verzögerung zwischen der Digitalisierung des Signals und dessen Darstellung am Monitor
15
verursachen . Zudem werden beim Schreiben von Daten durch den DDC in den bereits

15 Bei einer FFT mit der Blockgröÿe 512 Samples und einer Aktualisierungsrate von 10 FFT pro Sekunde

verursacht ein voller FIFO mit 32Ki Samples eine Verzögerung der Anzeige um 6.4 Sekunden.

43
4.1 Aufgaben

vollen FIFOBaustein einzelne I oder QWörter eines Samples verworfen. Die Folgen

sind fehlende oder vertauschte I/QAnteile in den Samples und damit verbunden eine

fehlerhafte Darstellung des Spektrums am Monitor. Um ein Volllaufen des Puers und

einem damit verbunden Datenverlust entgegen zu wirken, löst die Bedienanwendung vor

jedem Transfer eines Blocks einen Reset des FIFOBaustein aus, indem sie einen be-
16 2
stimmten ResetBefehl auf den I CBus legt. Dann erst liest diese den nächsten Block

ein und stellt diesen in der SpektrogrammAnsicht dar. Dieses Verhalten ist fest kodiert

und nicht kongurierbar. Startet die Bedienanwendung die Transfers im Wechsel mit dem
2
I CBefehl zum FIFOReset, ist davon auszugehen, dass sie sich in einem Modus zur

Spektrumanalyse bendet. In diesem Fall setzt UsbParIn() die Firmware in den Zustand
zum Blocktransfer und gibt dieser die Menge der zu übertragenden Daten mit.

Datenaufzeichung: Startet die Bedienanwendung die Transfers hingegen ununterbro-

chen, ist davon auszugehen, dass sie die Daten aufzeichnet. UsbParIn() schaltet die Firm-
ware auf den kontinuierlichen Transfermodus, so dass diese permanent Daten aus dem

externen FIFOBaustein zum Rechner hin überträgt. Zusätzlich setzt sie eine bestimm-

te Zustandsvariable, so dass der InitializeThread kontinuierlich neue Transfers startet,

sobald im TransferPuer ein Platz frei wird.

Unabhängig vom aktuellen Szenario weckt die APIFunktion UsbParIn() den Initialize
Thread über das entsprechende EventObject auf. Dieser leitet mit BeginDataXfer() die

gewünschte Anzahl an Transfers ein, trägt deren Handles in einen TransferRingpuer

ein und weckt den ProcessThread. Sollte dieser TransferRingpuer bereits voll sein,

schläft der InitializeThread so lange, bis er wieder geweckt wird. Der ProcessThread

wiederum wartet so lange, bis ihm mitgeteilt wird, dass neue Transfers im Ringpuer

vorhanden sind. Diese Transfers arbeitet er ab und weckt den InitializeThread, sobald ein

Platz im TransferRingpuer frei wurde. Durch die Synchronisation der beiden Threads

wird sichergestellt, dass die Transfers mit minimalsten Verzögerungen eingeleitet und

abgearbeitet werden.

Puerung

Das Abarbeiten der Transfers im ProcessThread ndet mittels WaitForXfer() und

FinishDataXfer() statt. Die durch diesen Transfer übertragenen Daten werden im

ProcessThread an eine Verteilungsschicht weitergegeben, auf die im nächsten Kapitel ge-

16 Dieser Befehl weist den Atmel an, den FIFOBaustein zurückzusetzen.

44
4.2 Aufbau

Abbildung 4.3: Zusammenspiel der verschiedenen Threads

nauer eingegangen wird. Innerhalb der Funktion UsbParIn() werden diese geschriebenen

Daten über die Verteilungsschicht ausgelesen und wieder zurück an die Bedienanwendung

geliefert.

Das Verwenden der Verteilungsschicht bietet gegenüber einem einfachen Ringpuer den

Vorteil, dass sie bereits alle notwendigen Maÿnahmen zur Synchronisation und dem

Locking zwischen den zugreifenden Threads vornimmt. Da es jedoch Anforderung ist,

dass der Treiber die gelesenen Daten auch an die Verteilungsschicht weitergibt, bietet es

sich nur an, das interne Puern ebenfalls über diese abzuwickeln. Als positiver Neben-

eekt können so die Daten, die die Bedienanwendung vom Treiber bekommt, über die

Verteilungsschicht durch andere Anwendungen bei Bedarf gezielt modiziert werden.

So ist für die beiden Szenarien  Spektrumanalyser und  Datenaufzeichnung gewährlei-

stet, dass sowohl kurze Verzögerungen bei kleinen Datenraten als auch Datensicherheit

bei höheren Datenraten erzielt werden.

In Abbildung 4.3 sind die Zusammenhänge zwischen den einzelnen Threads, der Bedienan-

wendung und der Verteilungsschicht dargestellt. Die Synchronisation und Signalisierungen

zwischen den unterschiedlichen ThreadKontexten wird durch gepunktete Linien darge-

stellt. Die notwendige Synchronisation und das Locking zwischen den Threads, die auf

den Datenpuer zugreifen, wird transparent durch die Verteilungsschicht durchgeführt.

45
4.2 Aufbau

Abbildung 4.4: Quelldateien des Treibers

4.2 Aufbau

Wie aus Abbildung 4.4 zu erkennen ist, ist die Quellcodestruktur des Treibers sehr ein-

fach gestaltet. Unter den Externen Abhängigkeiten benden sich die CyAPIBibliothek

und das FirmwareAbbild für den Cypress FX2LP. Das FirmwareAbbild liegt in Form

einer CStruktur in einer Headerdatei vor und wird beim Compilieren des Treibers fest in

dessen Binärstruktur eingebunden. Die CyAPIBibliothek hingegen wird erst beim Link-

vorgang statisch in die TreiberDLL eingebunden. Dadurch besteht neben den üblichen

Laufzeitbibliotheken des Compilers keine weitere Abhängigkeit, die zur Laufzeit aufgelöst

werden muss.

Der Zugri auf die CyAPI erfolgt durch Transferroutinen in der Worker.cpp, welche in

C++ geschrieben wurden. Da die CyAPI objektorientiert arbeitet, ist der Zugri nur über

Routinen im C++Sprachstil möglich. Eine durchgehende Objektorientierung durch Kap-

selung des Treibers in Klassen wäre möglich gewesen, hätte aber durch die enge Bindung

an prozedurale Routinen keinen entscheidenden Vorteil geboten. Daher wurde sich auf den

prozeduralen CSprachstil mit vereinzelten C++Elementen für die CyAPIAnbindung

beschränkt.

Der zur Bereitstellung der USB2.DLLAPI benötigte Wrapper wird ebenfalls beim Build-

vorgang mit in den Treiber gebunden. Sofern sich die API der verfügbaren Wrapper nicht

überschneidet, ist das Einbinden mehrerer Wrapper in eine DLL denkbar. Davon wurde

jedoch vorerst abgesehen, da der Java JNIWrapper lediglich exemplarischen Charakter

hat.

46
4.3 Tests

4.3 Tests

Um die Zuverlässigkeit des Treibers im Zusammenspiel mit der Firmware zu überprüfen

wurden verschiedene Tests vorbereitet und durchgeführt.

Während der Entwicklung des Treibers wurde in der Firmware des USBRX neben  Id-

le ,  GPIF Transfer und  GPIF Blocktransfer ein zusätzlicher Betriebsmodus  Test

eingeführt. Die Aufgabe dieses Modus ist es, Datenblöcke mit 512 Byte Gröÿe und einem

bekanntem Inhalt mit minimaler Verzögerung (und demnach maximal möglicher Über-

tragungsrate) an den Treiber zu senden. Zusätzlich wird in diesen 512 Byte ein Zähler

untergebracht, der nach jedem gesendeten Block inkrementiert wird.

Mit diesen durch die Firmware generierte Datenblöcken kann zwar auf korrekte Übertra-

gung aus den internen Puern, nicht aber auf korrekte Konguration des GPIF für die

Übertragung aus dem externen FIFO überprüft werden. Deswegen wurde zusätzlich eine

spezielle Version des USBRX entworfen, die inkrementierende SampleWerte mit Hilfe

eines Zählerbausteins erzeugt und in den externen FIFO schreibt. Da jedoch ein Test der

GPIFKonguration immer das Spezialboard voraussetzt, wird ein entsprechender Test

nur bei Änderungen an der GPIFKonguration durchgeführt.

Auf der Treiberseite wurde zusätzlicher Testcode eingeführt, mit dem Benutzereingaben

akzeptiert, Informationen ausgegeben und die verschiedenen Tests durchgeführt werden.

So können während des Normalbetriebs Treiber und Firmware in den Testmodus versetzt

werden, um die verfügbaren Tests durchzuführen.

4.3.1 Testsystem

Da die Leistungsfähigkeit des Testsystems die gewonnenen Ergebnisse maÿgeblich be-

einusst, wurden alle Tests auf dem selben System durchgeführt. Informationen zum

verwendeten System sind in Tabelle 4.2 aufgeführt.

4.3.2 Kritische Fehler

Die Fehler dieser Kategorie sind unbedingt zu beheben, auch wenn es sich um Vorabver-

sionen oder TestReleases handelt, da es sich um fatale Programmierfehler oder defekte

Hardware handelt. Auch durch Versuchsläufe im Langzeitbetrieb muss sichergestellt wer-

den, dass diese Fehler nicht auftreten.

47
4.3 Tests

Komponente Bezeichnung
R
TM
Hauptprozessor Intel Core 2 Duo E8500, 3.16 GHz

Speicher 8 GiByte DDR-2


R

USBController Intel ICH9 EHCI
R
TM
Betriebssystem Microsoft Windows Vista Ultimate

Tabelle 4.2: Informationen zum verwendeten Testsystem

Datenfehler

In diesem Test überprüft der Testcode im Treiber jeden eingegangenen Datenblock, ob

dieser den erwarteten Inhalt hat. Weicht ein Byte vom erwarteten Inhalt ab, wird eine

entsprechende Fehlermeldung ausgegeben. Diese Überprüfung wird wie eingangs erwähnt

nach Änderungen an der GPIFKonguration mit dem Spezialboard durchgeführt, um

diese Konguration ebenfalls zu verizieren.

Paketverlust

Dieser Test fordert es vom Treiber, verloren gegangene Datenblöcke ausndig zu machen.

Dazu wird der in der Firmware geschriebene Zählerwert bei jedem Datenblock durch den

Testcode im Treiber überprüft. Weist der Zählerwert zwischen zwei Datenblöcken eine

gröÿere Dierenz als einen Zählerpunkt auf, ist davon auszugehen dass Pakete verloren

gingen oder umsortiert wurden. Beide Ursachen sind als Fehlerfall zu werten.

Gerätefunktionen fehlerhaft

Der Testcode des Treibers bietet auch die Möglichkeit, die I/OPins anzusteuern und
2
abzufragen und den I CBus nach Geräten zu scannen. Die I/OFunktionen wurden mit

Hilfe eines Testboards mit Leuchtdioden und Schaltern ausgiebig getestet. Auf den ak-
2
tuellen USBRXPlatinen ist ein serielles I CEEPROM verbaut, das für verschiedene
2
I CTests verwendet wurde.

Zu Testzwecken wurde das Programmierinterface des Atmel ATMega32 (siehe Abschnitt

2.1.5) an den SPIPins des Cypress FX2LP angeschlossen. Über dieses Interface kann eine

neue Firmware in den Atmel eingespielt werden. Mit Hilfe eines externen Testprogramms,

das in Java geschrieben wurde, konnte so die SPIFunktionalität des FX2LP veriziert

werden.

48
4.3 Tests

4.3.3 Unkritische Fehler

Treten Fehler dieser Kategorie auf, sind diese zwar in TestReleases tolerierbar, müssen

jedoch in späteren Releases behoben werden.

Niedrige Datenrate

Obwohl in den Anforderungen nicht explizit hohe Datenraten gefordert, jedoch sehr er-

wünscht sind, wird in diesem Test der Treiber auf die maximal mögliche Übertragungsrate

getestet. Zudem weist eine niedrige Übertragungsrate auf ein fehlerhaftes Design hin. Aus

diesem Grund wird die Übertragungsrate im Testbetrieb gemessen und angezeigt. Da das

theoretische Maximum bei Bussen selten auch praktisch erreicht wird, wird hier lediglich

qualitativ gemessen.

Die theoretische Übertragungsrate mit BulkTransfers liegt bei ca. 50 MiByte/s. Jedoch

wird im Cypress FX2LP im Testmodus jeder Datenblock durch die Firmware getriggert,

was bei der niedrigen Taktfrequenz von 48 MHz des integrierten Mikrocontrollers zu

Verzögerungen in der Übertragung führen kann. Eine Application Note[6] von Cypress

beschreibt einen ähnlichen Test, der ein Ergebnis von 22 MiByte/s lieferte. In Foren im

Internet sind von möglichen 38 MiByte/s die Rede [20]. Die originale USB2.DLL erreicht

eine vergleichsweise geringe Übertragungsrate von 12 MiByte/s.

Nach einem Test mit einer Dauer von 286 Sekunden betrug die durchschnittliche Über-

tragungsrate ca. 35 MiByte/s. Dieser Wert entspricht knapp 70% des theoretischen Ma-

ximums und nahezu dem Dreifachen der originalen USB2.DLL. Dieses Ergebnis ist daher

als akzeptabel einzustufen. Dies erlaubt es mit einer Filterbreite von 8 MHz aufzuzeich-

nen, was einem Vielfachen der geforderten 600 kHz entspricht. Abbildung 4.5 zeigt einen

Screenshot der Ausgaben des Testcodes.

Trotz der hohen Datenrate hat sich auf dem verwendeten Testsystem lediglich eine CPU

Auslastung von unter 2% ergeben.

Hohe Latenzen

Dieser Test misst die Dauer des Aufrufs der APIFunktion UsbParIn() und demzufolge

die Dauer zwischen Anforderung eines Datenblockes und dem Zeitpunkt, ab dem dieser

Datenblock für die Anwendung zur Verfügung steht. Diese Dauer wird im Weiteren auch

als Latenz bezeichnet.

49
4.3 Tests

Abbildung 4.5: Test der Übertragungsrate

50
4.3 Tests

Abbildung 4.6: Messung der Aufrufdauer der APIFunktion UsbParIn()

Wie in den Anforderungen beschrieben, muss die Latenz bei der Übertragung möglichst

niedrig gehalten werden. Daher ist der Fehlerfall  Hohe Latenz ebenso wie  Niedrige Da-

tenrate nicht quantitativ bewertbar. Als Maximalwert wurde deswegen 50 ms festgelegt,

so dass 20 Transfers pro Sekunde und damit ca. 20 FFT/s in der Bedienanwendung gerade

noch eine üssige Darstellung der WasserfallAnsicht garantieren.

Getestet wurden die Latenzen bei Transfers von Datenblöcken unterschiedlicher Gröÿe.

Aus der Ausgabe des Testcodes (siehe Abbildung 4.6) ist die Aufrufdauer der API

Funktion UsbParIn() zu entnehmen. Diese Aufrufdauer wurde für unterschiedliche Block-


gröÿen zwischen 512 Byte und 128 KiByte gemessen und in Tabelle 4.3 aufgelistet. Dieser

ist zu entnehmen dass die maximale Aufrufdauer bei Blöcken von 128 KiByte Gröÿe

auftritt, aber mit 7 ms deutlich unter dem Maximalwert von 50 ms liegt.

Nach weiteren Optimierungen wurde eine Lösung gefunden, diese Verzögerung in diesem

Test konstant auf ca. 2 ms zu reduzieren. Diese Lösung fordert den nächsten Datenblock

schon beim Verlassen von UsbParIn() an, so dass dieser bereits beim nächsten Aufruf

zur Verfügung steht. Diese Optimierung birgt den Nachteil, dass die der Anwendung

gelieferten Daten bereits einen Aufrufzyklus alt sind. Die Dauer der Übertragung selbst

ändert sich jedoch dadurch nicht, diese wird lediglich asynchron durchgeführt und ndet

somit statt, während die Anwendung die letzten Daten auswertet. Daher wird von einer

Bewertung in diesem Test abgesehen.

51
4.3 Tests

Blockgröÿe Durchschnittliche Latenz


0,5 KiByte 2 ms

1 KiByte 3 ms

2 KiByte 3 ms

4 KiByte 3 ms

8 KiByte 3 ms

64 KiByte 5 ms

128 KiByte 7 ms

Tabelle 4.3: Latenzen beim Lesen von Daten mittels UsbParIn()

52
Kapitel 5

Verteilungsschicht

Eine Verteilungsschicht soll die Verteilung der durch das Gerät USBRX gewonnenen

Daten an verschiedene Anwendungen  und zwischen diesen  übernehmen. Moderne Be-


17
triebssysteme wie Microsoft Windows oder Linux bieten zwar IPCMechanismen an,

die den Austausch von Daten zwischen Prozessen und Threads erleichtern, diese sind je-

doch betriebssystemabhängig und erlauben es nicht, Puergröÿen und das das Verhalten

z. B. bei vollen Puern anzupassen. Auch ist davon auszugehen, dass diese sehr stark mit

tieferen Betriebssystemschichten verknüpft sind und dies bei hohen Datenraten zu uner-

wünschten Latenzen führen kann. Eine geforderte Rekonguration während des Betriebs

aus einer beliebigen Instanz heraus ist bei diesen Mechanismen nicht vorgesehen.

Daher wurde eine eigenständige Lösung entwickelt, die in diesem Kapitel beschrieben

wird. Diese Lösung wird wegen der Verwendung von Shared Memory und der möglichen

Verkettung mehrerer Anwendungen untereinander als SHMemChain bezeichnet.

5.1 Konzept

5.1.1 Weitere Designziele

Für das grundlegende Design der SHMemChainBibliothek wurden mehrere Ziele festge-

legt, die diese weiter charakterisieren sollen. Diese gelten Ziele gelten als Ergänzung zu

den Anforderungen in Abschnitt 1.2.2 und sind wie folgt festgelegt:

17 Microsoft Windows bietet mit Pipes[16], Mailslots[14] und Sockets[18] mehrere solcher Mechanismen
zur Kommunikation zwischen Prozessen an.

53
5.1 Konzept

• Niedrige Verzögerungen und Latenzen: Werden Daten von Anwendung A an

eine Anwendung B übertragen, so soll unabhängig davon, ob Anwendung B auf

Daten wartet oder beschäftigt ist, der Schreibvorgang in Anwendung A mit mög-

lichst kurzer Ausführungszeit (=Schreibverzögerung) durchgeführt werden. Wartet

Anwendung B bereits auf Daten, so müssen diese mit möglichst kurzer Gesamt-

verzögerung in der Übertragung (=Latenz) für die Weiterverarbeitung verfügbar

gemacht werden. Die Verwendung von Puern und einer geeigneten Synchronisati-

on ist hierfür zwingend erforderlich.

• Hohe Durchsatzraten: Da es sich beim Datenaustausch grundsätzlich nur um

SpeicherKopieroperationen und einer entsprechenden Synchronisation der auf den

Speicher zugreifenden Prozesse handelt, müssen Durchsatzraten mit mehreren hun-

dert MiByte/s auf aktuellen Rechnersystemen erreicht werden.

• Portabilität: Die Bibliothek sollte neben den Grundkonzepten in der Informatik

wie Mutex, Signalisierung oder Shared Memory keine betriebssystemabhängigen

Funktionen verwenden, um eine zukünftige Portierung auf andere Betriebssysteme

zu erleichtern.

5.1.2 Logischer Aufbau

Um den Ablauf der Kommunikation innerhalb der Verteilungsschicht zu verstehen, muss

zuerst genauer auf deren Konzept eingegangen werden.

Eine Anwendung, die Daten mit einer anderen Anwendung austauschen soll, muss sich

zunächst bei der Verteilungsschicht registrieren und wird in deren Kontext als Node be-

zeichnet. Diese Node wird über einen Handle identiziert, welcher bei der Registrierung

zurückgegeben wird und bei jedem weiteren APIAufruf als Referenz angegeben werden

muss. Dabei kann sich eine Anwendung auch mehrfach registrieren und bekommt dement-

sprechend mehrere Nodes und Handles zugeteilt.

Jede Node ist in der Lage, Daten zu lesen und zu schreiben. Woher eine Node Daten liest,

bzw. wohin sie Daten schreibt, wird über Channels angegeben. Zu jeder Node gibt es einen

Source und einen Destination Channel, die bei der Registrierung angegeben werden. Diese
bestimmen Quelle und Ziel der Daten und werden durch beliebige Zahlen im positiven

32Bit IntegerBereich repräsentiert. Über weitere Bibliotheksfunktionen können diese

Channels jedoch auch im laufenden Betrieb nachträglich geändert werden. Unbenutzte

54
5.1 Konzept

Abbildung 5.1: Beispielaufbau einer Verteilung. ( Source und Destination Channel sind

hier durch src und dst dargestellt)

Source oder Destination Channels einer Node können deaktiviert werden, indem ihnen

ein negativer Wert zugewiesen wird.

Diese Channels dienen rein zur logischen Zuordnung, an welche Nodes die Daten einer

schreibenden Node geleitet werden sollen und benötigen keine weiteren Verwaltungsin-

formationen. Es wird jedoch sichergestellt, dass ein bestimmter Channel nur von jeweils

einer Node beschrieben werden kann. Könnten mehrere Nodes auf einen Channel schrei-

ben, würde dies zu einer unerwünschten Vermengung der Daten führen. Dies wird nicht

als Einschränkung betrachtet, da die Bibliothek ohnehin nur zur Übertragung von Daten-

strömen konzipiert wurde.

Schreibt, wie in Abbildung 5.1 dargestellt, die Node A mit Destination Channel 2 Daten,
so können diese Daten von allen Nodes gelesen werden, die ihren Source Channel eben-

falls auf 2 eingestellt haben. Dabei erhalten alle Nodes die gleichen Daten  die zeitliche

Abfolge, in der die Nodes die Daten lesen, ist unerheblich. Sind keine Nodes vorhanden,

die diesen Source Channel besitzen, werden die geschriebenen Daten verworfen.

Nodes, die Daten verarbeiten, wie z. B. Filter oder Verstärker, lesen demnach Daten

vom Source Channel, modizieren diese und schreiben sie wieder über den Destination
Channel an weitere Nodes. So können mehrere Verarbeitungsschritte aneinandergereiht
werden, die in unterschiedlichen Anwendungen implementiert wurden. Die notwendige

Synchronisation zwischen den Prozessen wird transparent durch die Verteilungsschicht

erledigt.

Der Vorteil durch die Verwendung von Channels ist, dass so die Daten kategorisiert werden

können. So ist z. B. vorgesehen, dass die durch den USBRXTreiber gelieferten Rohdaten

immer auf Channel 0 ausgegeben werden. Weitere Anwendungen können so diese Roh-

55
5.1 Konzept

daten lesen, ohne zu wissen, von welcher Node diese Daten stammen. Auch könnte eine

Kombination aus MessAnwendungen z. B. immer auf Channel 128 auf Daten warten.

Sollte eine Analyse von Daten erforderlich sein, kann eine Anwendung ihren Destination
Channel auf 128 setzen, so dass der Anwender diese Daten in den MessAnwendungen

genauer untersuchen kann.

Dieses Konzept ist vergleichbar mit dem Prinzip des Multicasting in Computernetzwerken.

5.1.3 Shared Memory

Shared Memory bezeichnet einen Speicherbereich, auf den von mehreren Prozessen gleich-

zeitig zugegrien werden kann. Da jedoch jeder Prozess durch Speichervirtualisierung sei-

nen eigenen Adressraum besitzt, ndet sich in diesem keine Adresse, die mit Sicherheit

bei allen anderen Prozessen frei ist. Daher werden Shared MemoryBereiche in einen be-

liebigen, freien Speicherbereich des Prozesses eingeblendet, der aber für jeden Prozess

verschieden ist.

Zum Erstellen oder Önen eines solchen Bereichs reichen seine Gröÿe und ein eindeutiger

Name, die alle Prozesse beim Aufruf der entsprechenden Betriebssystemfunktionen ver-

wenden müssen. Das Betriebssystem liefert dabei neben der Speicheradresse auch einen

Handle zurück, der diesem Bereich zugeordnet und nur für den aktuellen Prozess gültig

ist. Dieser Handle wird benötigt, um diesen Shared MemoryBereich später wieder zu

schlieÿen.

Da der Shared MemoryBereich bei jedem Prozess an einer anderen Speicheradresse liegt,

können zum einen keine direkten Speicherzeiger (engl.: Pointer) auf Shared Memory

Bereiche unter den Prozessen ausgetauscht werden und zum anderen muss jeder Prozess

selbst verwalten, welchen Handle und welche Adresse ein Shared MemoryBereich in sei-

nem Adressraum besitzt.

56
5.2 Realisierung

Abbildung 5.2: Aufbau des NodeinfoBereichs (Shared Memory)

5.2 Realisierung

5.2.1 Shared Memory

NodeKonguration

Die Informationen und Konguration aller Nodes muss wie gefordert in einem Shared

MemoryBereich liegen, so dass mehrere Instanzen der Verteilungsbibliothek darauf zu-

greifen und diese bearbeiten können. Die Informationen und Konguration zu einer Node

werden weiterhin als Nodeinfo bezeichnet, der Shared MemoryBereich in dem diese ge-

speichert sind demnach als NodeinfoBereich.

Dieser Bereich muss von der ersten Instanz der Bibliothek alloziert und initialisiert werden,

alle weiteren Instanzen können daraufhin mit dem vorbereiteten Bereich arbeiten.

Um den Verwaltungsoverhead gering zu halten, werden alle Nodeinfos im Nodeinfo

Bereich in Form eines Arrays gespeichert (siehe Abbildung 5.2). Dies erfordert es, vorab

zu wissen, wie viele Nodes maximal registriert werden. Daher wird von einer maximalen

Anzahl MAX_NODES an möglichen Nodes ausgegangen.

Eine exiblere Lösung, bei der die maximale Anzahl der Nodes nicht festgelegt ist, wur-

de auch überlegt. Dabei würden die Nodeinfos über verkettete Shared MemoryBereiche

hinweg verteilt werden. Jedoch wäre ein Zugri auf eine bestimmte Nodeinfo mit meh-

reren PointerDereferenzierungen und Speicherzugrien verbunden, was hingegen bei der

Auslegung als Array in einem Bereich konstant nur eine Dereferenzierung kostet. Zudem

erfordert eine Lösung mit verketteten Bereichen eine aufwändige Verwaltung von Handles

und Adresszeigern zu diesen Bereichen, bietet dafür aber keine entscheidenden Vorteile.

Daher wurde sich für die einfachere Variante entschieden.

Jede Nodeinfo in diesem Bereich entspricht einer CStruktur, die wichtige Informationen

über die jeweilige Node enthält. Tabelle 5.1 listet die wichtigsten Felder dieser Struktur

auf.

57
5.2 Realisierung

Feld Beschreibung
int version; wird bei Änderungen inkrementiert

int used; gibt an, ob diese Nodeinfo benutzt wird

int src_chan; Source Channel

int dst_chan; Destination Channel

unsigned char name[. . . ] gibt einen beschreibenden Namen an

unsigned int buer_size; Gröÿe des Ringpuers

unsigned int buer_start; RingpuerVariable

unsigned int buer_used; RingpuerVariable

unsigned char node_buer[. . . ] Name des Shared MemoryBereichs für Ringpuer

unsigned char node_mutex[. . . ] Name des Named Mutex für diese Node

unsigned char node_event[. . . ] Name des EventObject für diese Node

Tabelle 5.1: Die wichtigsten Felder einer Nodeinfo

Ob eine Nodeinfo bereits benutzt wird, oder noch verfügbar ist, wird über das Feld used
festgelegt. Daneben beinhaltet diese Struktur den Source und den Destination Channel,
die dieser Node zugewiesen sind. Auch sind dort die für den Datenpuer notwendigen

Variablen untergebracht und die Namen, mit denen der Shared MemoryBereich des Da-

tenpuers und die zur Synchronisation (siehe Abschnitt 5.2.2) notwendigen Mutex und

EventObjects geönet werden können. Diese Felder werden durch diejenige Instanz der

Bibliothek initialisiert, die die Registrierung dieser Node durchführt.

Das Feld version wird nach jeder Änderung, die ein erneutes Önen des Datenpuers,

des Mutex oder des EventObjects erfordert, inkrementiert. Das sind insbesondere Neu

oder Deregistrierungen einer Node oder das Ändern der Puergröÿe.

Parallel zum NodeinfoBereich führt jede Instanz der Verteilungsbibliothek ein lokales

Array, in dem nur für diese Instanz wichtige Informationen zu jeder Node in Form einer

weiteren Struktur gelistet sind. Dieses Array wird im Weiteren als Local Nodeinfo Array

bezeichnet. Es besitzt die gleiche Anzahl an Elementen wie das Nodeinfo Array, welche

u. A. die in Tabelle 5.2 aufgeführten Felder beinhalten.

Datenpuer

Da der Datenaustausch zwischen einzelnen Nodes auch über Prozesse  und damit auch

über mehrere Instanzen der Verteilungsbibliothek hinweg  stattnden soll, müssen die

58
5.2 Realisierung

Feld Beschreibung
int version; Version der Nodeinfo, auf die sich bezogen wird

int used; gibt an, ob diese Daten benutzt werden

int local; gesetzt, wenn diese Instanz der Inhaber der Node ist

unsigned char *buer Zeiger zum Datenpuer

HANDLE buer_h Handle für den Shared Memory des Puers

HANDLE node_mutex MutexHandle für die Synchronisation

HANDLE node_event EventObjectHandle für die Synchronisation

Tabelle 5.2: Die wichtigsten Felder einer Local Nodeinfo

dafür erforderlichen Puer ebenfalls in einem Shared MemoryBereich liegen. So können

sowohl der schreibende als auch der lesende Prozess auf den gleichen Speicherbereich

zugreifen, ohne dass die Daten durch Betriebssystemschichten hindurch mehrfach kopiert

werden müssen.

Jede Node besitzt einen Datenpuer, in den die Daten geschrieben, die für diese Node

bestimmt sind. Die zum Önen des Shared MemoryBereichs erforderlichen Informationen

wie Name und Gröÿe werden durch diejenige Instanz der Verteilungsbibliothek in die

Nodeinfo eingetragen, welche diese Node registriert hat. Greift eine andere Instanz auf

diese Node zu, muss zunächst der Shared MemoryBereich des Datenpuers der Node mit

Hilfe des Namens und der Gröÿe aus der Nodeinfo geönet werden. Die beim Erstellen

und Önen anfallenden Handles und Speicherzeiger verwaltet jede Instanz der Bibliothek

in ihrer Local Nodeinfo.

Da ein Ringpuer für den Verwendungszweck als Datenpuer besonders gut geeignet ist,

ndet dieser hier Anwendung. Bei Lese und Schreibzugrien auf diesen Datenpuer wird

eine für Ringpuer übliche Variante benutzt, bei der die Startposition und die Anzahl der

Daten in Variablen gehalten werden. Diese für den Ringpuer notwendigen Arbeitsvaria-

blen, werden in der Nodeinfo geführt.

Änderungsverwaltung

In der Local Nodeinfo bendet sich das Feld version, welches dem gleichnamigen Feld

aus der Nodeinfo entspricht. Weichen bei einem Zugri auf eine Nodeinfo die Werte beider

versionFelder voneinander ab, so ist davon auszugehen, dass die in der Local Nodeinfo

59
5.2 Realisierung

gespeicherten Handles nicht mehr denen entsprechen, die zur Synchronisation bzw. zum

Puerzugri benötigt werden. Dies ist z. B. der Fall, wenn eine Node deregistriert wurde.

Daher werden alle Handles in der Local Nodeinfo geschlossen und  sofern die Nodeinfo

noch benutzt wird  mit den aktuellen Informationen aus der Nodeinfo neu geönet. Auf

diese Weise wird bei einer Änderung wie z. B. Deregistrierung einer Node auch der für

den Puer allozierte Shared MemoryBereich wieder freigegeben.

Durch die Verwendung des versionFelds ergibt sich jedoch ein Problem, welches zu

einem temporären Speicherleck führen kann: Registriert eine Instanz A der Verteilungs-

bibliothek eine Node mit einer beliebigen Puergröÿe und eine andere Instanz B greift

in Folge eines Schreibvorgangs auf diese Node zu, wird der Shared Memory zum Puer

auch in der Instanz B geönet. Wird nun die Node in Instanz A deregistriert, bleibt der

Shared MemoryBereich in Instanz B trotzdem weiter geönet. Solange aus Instanz B

kein Zugri auf die deregistrierte Node, bzw. deren Nodeinfo mehr stattndet, belegt sie

trotzdem weiter diesen physikalischen Speicher.

Als mögliche Lösung ist hier ein weiterer Thread angedacht, welcher in jeder Instanz bei

Änderungen durch alle Nodeinfos iteriert und den Datenpuer deregistrierter Nodes auch

lokal wieder freigibt. Zur Signalisierung einer Änderung kann eine geeignete Signalisie-

rungsmethode (wie z. B. das EventObject) verwendet werden, die das Betriebssystem

anbietet.

5.2.2 Synchronisation

Da mehrere Prozesse gleichzeitig auf gemeinsame Ressourcen wie NodeinfoBereich oder

die Datenpuer zugreifen, ist eine ordentliche Synchronisation besonders wichtig. Dies

beinhaltet sowohl ein Sperren (Locking) der Ressourcen bei konkurrierenden Zugrien,

als auch die Signalisierung, dass neue Daten im Puer verfügbar sind.

Locking

Dafür wurde bei der Implementierung der Verteilungsschicht ein Lese/SchreibSemaphor

für den NodeinfoBereich eingeführt. Dadurch wird sichergestellt, dass bei einer Änderung

einer NodeinfoStruktur nur von einem Prozess zugegrien werden kann, bei Lesezugrien

diese aber untereinander parallel stattnden können.

60
5.2 Realisierung

Bei einem lesenden oder schreibenden Zugri auf die Datenpuer müssen die für den

Puer wichtigen Variablen (buffer_start, buffer_used und buffer_size) in einer No-


deinfo ebenfalls durch einen Sperrmechanismus vor Veränderung durch einen anderen

Prozess gesichert werden. Da die Zugrie auf die Datenpuer der registrierten Nodes je

nach Auslastung jedoch sehr häug stattnden können, würde ein komplettes Sperren des

NodeinfoBereichs bei jedem Zugri die Latenzen aller Prozesse stark negativ beeinus-

sen, da nur immer ein Zugri gleichzeitig stattnden dürfte.

Deswegen wird für Zugrie auf den Datenpuer selektiver gesperrt. Für jede Nodeinfo

existiert ein Mutex, der die Zugrie auf die Puervariablen innerhalb einer Nodeinfo

absichert. Bei Zugri auf den Datenpuer einer Node wird der Semaphor des Nodeinfo

Bereichs lediglich lesend, der Mutex für die Variablen jedoch komplett gesperrt.

Später wurde eine feingranularere Sperrmethode eingesetzt, durch die die Variablen für

den Datenpuer nur für die Dauer ihrer Änderung gesperrt werden. Durch das Konzept

dieser Verteilungsschicht können nur maximal zwei Prozesse auf den Datenpuer einer

Node zugreifen - der Prozess, der Daten an diese Node schreibt und der Prozess, der

Besitzer dieser ist und die geschriebenen Daten liest. Beide können durch die Verwendung

eines Ringpuers gleichzeitig auf den Puer selbst zugreifen, lediglich bei einer nicht

atomaren Änderung der Puervariablen muss der entsprechende Mutex gesperrt werden.

Dadurch kann während des Kopiervorgangs mittels memcpy() im jeweils anderen Prozess

ohne Wartezeiten zugegrien werden.

Abbildungen 5.3 und 5.4 stellen den Vorgang beim Schreiben und Lesen in einem Sequenz-

diagramm dar. Der dunkel schraerte Bereich kennzeichnet nichtatomare Operationen,

die durch Sperren gesichert wurden.

Signalisierung

Wartet ein Prozess auf Daten, so muss dieser benachrichtigt werden, sobald welche ver-

fügbar werden. Dazu existiert zu jeder Node ein eigenes EventObject[12], welches zur

Signalisierung dient. Sind nicht genug Daten zum Lesen vorhanden, wird im lesenden Pro-

zess mit Hilfe dieses EventObjects und der WindowsFunktion WaitForSingleObject()


gewartet, bis ihn ein schreibender Prozess über SendSignal() aufweckt. Dadurch bleibt

ein lesender Prozess nur so lange blockiert, wie es nötig ist.

61
5.2 Realisierung

Abbildung 5.3: Sperren beim schreibenden Zugri auf den Datenpuer einer Node

Abbildung 5.4: Sperren beim lesenden Zugri auf den Datenpuer einer Node

62
5.3 Performanceanalyse

5.2.3 API

Um den Anwendern der Verteilungsschicht möglichst freie Wahl bei der Auswahl ihrer

Programmiersprache zu lassen, wurde sich auf eine prozedurale Bibliothek mit stdcall
Aufrufkonvention beschränkt. Diese ist die für WindowsBibliotheken gebräuchlichste[19]

und wird von den meisten Programmiersprachen unterstützt.

Tabelle 5.3 listet die wichtigsten APIFunktionen der SHMemChain Bibliothek auf. Die

API arbeitet laut Anforderungen mit sprechenden Namen, die auch ohne die Hilfe einer

Dokumentation zu verstehen ist.

Funktion Beschreibung
shmemchain_register_node registriert eine Node

shmemchain_unregister_node deregistriert eine Node

shmemchain_update_node aktualisiert Source und Destination Channel


shmemchain_update_node_name setzt bzw. aktualisiert einen beschreibenden Namen

shmemchain_write_data schreibt eine angegebene Anzahl an Bytes

shmemchain_read_data liest eine angegebene Anzahl an Bytes

Tabelle 5.3: APIFunktionen der SHMemChain Bibliothek

Zusätzlich zu einer CHeaderDatei wurde eine PascalUnit als Interface entwickelt,

welche es dem Anwender ermöglicht, diese Bibliothek auch aus Pascal oder Delphi

Programmen zu verwenden. Klassenbibliotheken und denitionen für die Sprachen C#

und Java wurden ebenfalls entwickelt. Somit kann die für den Anwendungszweck günstig-

ste Sprache gewählt werden.

5.3 Performanceanalyse

Eine Analyse der Ziele, die in Abschnitt 5.1.1 deniert wurden, wurde mittels eines ein-

fachen Testprogramms durchgeführt. Dieses Testprogramm registriert sich in der Vertei-

lungsbibliothek als eine Node und ist in der Lage, Zeitstempel zu erzeugen und auszuwer-

ten. Je nach Konguration schreibt es diese Zeitstempel an einen Channel, oder empfängt

solche darüber.

So kann eine Instanz des Testprogramms Zeitstempel erzeugen und an eine weitere Instanz

schreiben, welche diese ausliest und auswertet. Auf diesen Weg können die Latenz, die

Dauer der Schreiboperation und die Dauer der Leseoperation bestimmt werden. Zusätzlich

63
5.3 Performanceanalyse

Abbildung 5.5: Testergebnis des Latenztests

ist dieses Testprogramm in der Lage, Datenblöcke beliebiger Gröÿe zu übertragen, um

hohe Datenraten zu simulieren.

Um eine möglichst hohe Genauigkeit bei der Messung zu erzielen, wird die Funktion

QueryPerformanceCounter()[17] der WindowsAPI verwendet. Diese liefert Zeitstempel


mit einer Genauigkeit, die vom verwendeten Rechnersystem abhängig ist, und beim ver-

wendeten Testsystem (siehe Tabelle 4.2) in etwa eine Auösung von 70 ns erreicht. Um

Einüsse durch andere Prozesse zu minimieren, wurde beim Test die Prozesspriorität auf

 Hoch gesetzt. Dadurch behandelt der BetriebssystemScheduler den Prozess vorrangig

und das Ergebnis ist weniger von der Aktivität anderer Prozesse abhängig. Über die Er-

gebnisse des Tests wird ein arithmetisches Mittel gebildet und im Messwertbereich des

Testprogramms angezeigt.

Abbildung 5.5 zeigt die Ergebnisse bei einem Test mit einer Blockgröÿe von einem KiByte,

welcher jede Millisekunde übertragen wurde. Dieser Test ergab bei einer CPUAuslastung

je Prozess von weniger als 0.1% eine Latenz von ca. 100 µs.

Die Dauer des Schreibvorgangs allein ist mit ca. 86 µs fast so hoch wie die Latenz, was

darauf zurückzuführen ist, dass beim Schreibvorgang alle Nodes auf ihren SourceChannel

überprüft werden müssen, während die Leseoperation nur noch auf ein Signal wartet,

um die geschriebenen Daten aus dem Puer zu lesen. Abbildung 5.6 stellt diesen Ablauf

64
5.3 Performanceanalyse

Abbildung 5.6: Ablaufdiagramm bei Schreib und Lesevorgängen über die Verteilungsbi-

bliothek

grasch dar. Diese Dauer könnte durch die Einführung eines zusätzlichen Arrays, in dem zu

jedem Channel die zugehörigen Empfängernodes stehen, verringert werden. Besonders bei

groÿen Werten von MAX_NODES und kleinen Blockgröÿen der zu übertragenden Daten ist

eine solche Optimierung in Betracht zu ziehen. Dem gegenüber steht jedoch der zusätzliche

Verwaltungsaufwand, der zum Pegen dieses Arrays notwendig ist.

Mehrfache Wiederholungen des Tests zeigten, dass die Messergebnisse je nach Rechneraus-

lastung sehr stark variieren können. Allein das Aktivieren eines anderen Anwendungsfen-

sters verschlechtert die Messergebnisse teilweise um bis zu 50%. Dies liegt nicht in einem

fehlerhaften Design begründet, sondern ist vielmehr auf das SchedulingKonzept eines

MultitaskingBetriebssystems zurückzuführen, bei dem die CPURessourcen unter meh-

reren Anwendungen aufgeteilt werden. Daher sind die gewonnenen Ergebnisse lediglich

als Indikator für eine gut abgestimmte Synchronisation innerhalb der Verteilungsschicht

zu betrachten.

Ein weiterer Test, bei dem groÿe Datenmengen in kurzen Zeitabständen übertragen wur-

den, ermittelte eine Übertragungsrate von mehr als 800 MiByte/s. Dieser Test verursachte

eine gesamte CPUAuslastung von ca. 90% und ergab eine gemessene Latenz von ca. 18

ms. Ein Screenshot der Testanwendung ist in Abbildung 5.7 zu sehen. Da bei groÿen Da-

tenblöcken von mehreren MiByte die Verzögerungen durch das Durchsuchen des Nodeinfo

Arrays und die Einüsse durch das Prozessscheduling relativ gering sind, schwankt dieses

Testergebnis nur minimal.

Orientiert man sich an den Anforderungen an die Teilprojekte  Treiber und  Firmware ,

so liegen sowohl verursachte Latenz als auch die mögliche Übertragungsrate der Vertei-

65
5.3 Performanceanalyse

Abbildung 5.7: Testergebnis des Durchsatztests

lungsbibliothek in Bereichen, die keinen merklichen negativen Einuss auf die anderen

Teilprojekte ausüben.

66
5.3 Performanceanalyse

vi
Literaturverzeichnis

[1] Böge, Wolfgang: Handbuch Elektrotechnik. Vieweg Verlag, 4. Auflage, 2007.

[2] Braintechnology Forum.


http://www.braintechnology.de/wbb2/thread.php?threadid=123.

[3] USB2.DLL Beschreibung.


http://www.braintechnology.de/braintechnology/usb2dll.html.

[4] Bronstein, Semendjajew: Taschenbuch der Mathematik. Teubner Verlag, 25.

Auflage, 1991.

[5] Cypress Semiconductor: Cypress FX2 Technical Reference Manual.


http://www.cypress.com/design/TR10001.

[6] Cypress Semiconductor: Streaming Data Through Isochronous/Bulk Endpoints


on EZ-USB FX2 and EZ-USB FX2LP.
http://www.cypress.com/design/AN4053.

[7] Cypress Semiconductor: SuiteUSB 1.0.


http://www.cypress.com/design/SD1077.

[8] Friess, Nathan: FX2 Demo Project.


http://pages.cpsc.ucalgary.ca/~walpole/425/SOFTWARE/LCDtest/LCDtest/.

[9] GNU Radio: USRP - Frequently Asked Questions.


http://www.gnuradio.org/trac/wiki/UsrpFAQ.

[10] Hoffmann, Rüdiger: Signalanalyse und -erkennung: Eine Einführung für


Informationstechniker. Springer Verlag, 1997.

[11] Meyer, Martin: Signalverarbeitung - Analoge und digitale Signale, Systeme und
Filter. Vieweg Verlag, 4. Auflage, 2006.

vii
LITERATURVERZEICHNIS

[12] Microsoft Corporation: MSDN - EventObjects.


http://msdn.microsoft.com/en-us/library/ms686915(VS.85).aspx.

[13] Microsoft Corporation: MSDN - LoadLibrary.


http://msdn.microsoft.com/en-us/library/ms684175.aspx.

[14] Microsoft Corporation: MSDN - Mailslots.


http://msdn.microsoft.com/en-us/library/aa365576(VS.85).aspx.

[15] Microsoft Corporation: MSDN - Named Mutex.


http://msdn.microsoft.com/en-us/library/ms682411.aspx.

[16] Microsoft Corporation: MSDN - Pipes.


http://msdn.microsoft.com/en-us/library/aa365780(VS.85).aspx.

[17] Microsoft Corporation: MSDN - QueryPerformanceCounter.


http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx.

[18] Microsoft Corporation: MSDN - Sockets.


http://msdn.microsoft.com/en-us/library/ms740673(VS.85).aspx.

[19] Microsoft Corporation: MSDN - stdcall.


http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.71).aspx.

[20] R., Christian: Cypress 68013, CyAPI.


http://www.mikrocontroller.net/topic/86093.

[21] SDCC Homepage.


http://sdcc.sourceforge.net/.

[22] SDCC Manual.


http://sdcc.sourceforge.net/doc/sdccman.html/node78.html.

[23] Siegl, Johann: Schaltungstechnik- analog und gemischt analog/digital. Springer

Verlag, 3. Auflage, 2008.

[24] TechArena Forum.


http://forums.techarena.in/xp-hardware/641037.htm.

[25] USB Konsortium: USB 2.0 Spezikation.


http://www.usb.org/developers/docs/usb_20_122208.zip.

[26] Wikipedia: Digital Radio Mondiale.


http://de.wikipedia.org/wiki/Digital_Radio_Mondiale.

viii
Eidesstattliche Erklärung
Ich erkläre hiermit, dass ich die Arbeit selbständig verfasst, noch nicht anderweitig für

Prüfungszwecke vorgelegt, keine anderen als die angegebenen Quellen oder Hilfsmittel

benützt sowie wörtliche und sinngemäÿe Zitate als solche gekennzeichnet habe.

Ingolstadt, 04.03.2009

Georg Hofstetter

ix