Hier eine ausführliche englische Dokumentation. Der folgende Text wurde aus dieser Dokumentation herausgearbeitet. Um USB wirklich verstehen zu können, muss der gesamte Text gelesen werden, einige Sachen werden erst weiter unten im Text erklärt.
USB ist die Abkürzung für "Universal Serial Bus". Dies ist eine Art der Verkabelung von Peripheriegeräten, die sehr bequem, sicher und schnell ist. Ausserdem hat sich USB in grundsätzlich allen modernen Betriebssystemen eingebürgert, wodurch Kompatibilitätsprobleme zu einem grossen Teil gelöst werden konnten.
Hardware
Ein USB-Kabel besitzt stets nur 4 Leitungen:
| Anschluss-Nummer | Farbe des Kabels | Bedeutung |
|---|---|---|
| 1 | rot | Vcc (Stromversorgung) |
| 2 | weiss | D- (Datenleitung negativ) |
| 3 | grün | D+ (Datenleitung positiv) |
| 4 | schwarz | GND (Stromabfluss) |
Durch die Anschlüsse 1 und 4 wird das Gerät mit Strom (maximal 500 mA) versorgt. Reicht dies nicht aus, so muss das Gerät eine eigene Stromversorgung besitzen. Die Datenleitungen senden ein sogenanntes differenitelles 1, wenn die Spannung von D+ 200 mV grösser ist als D-. Eine differentielle 0 wird übertragen, wenn die Spannung von D+ 200mV kleiner ist als D-. Bei Low- und Full-Speed-Geräten wird ein differentielles 0 als J und ein differentielles 1 als K bezeichnet. Bei High-Speed-Geräten sind diese Terme vertauscht. Sind beide Datenleitungen auf einem niedrigen Level (kleiner als 0.3 V), so wird ein sogenanntes Single-Ended-0 (SE0) übertragen.
Da kein Taktsignal existiert, werden die Daten nach dem NRZI-Condierungs-Verfahren gesendet: Nach 6 Einsen wird automatisch (Hardware) eine 0 in den Bit-Strom eingefügt. Ein 1-Bit wird versendet, indem die Polarität unverändert bleibt, ein 0-Bit wird gesendet, indem die Polarität wechselt. Beim Empfänger wird dasselbe Verfahren in umgekehrter Reihenfolge ausgeführt.
Es gibt 4 Varianten von Steckern für ein USB-Kabel, wovon zwei jedoch nur die Mini-Ausführungen der anderen beiden sind. Die Mini-Ausführungen werden beispielsweise für Kameras oder PDAs benötigt, welche keinen Platz für einen grossen Steckplatz haben.
Stecker AStecker A zeigt stets in Richtung Computer (Host), der das Gerät ansteuern soll. ![]() |
Stecker BStecker B zeigt stets in Richtung Gerät, das angeschlossen werden soll. ![]() |
Varianten und Versionen von USB
Von Anfang an waren drei Arten einer USB-Verbindung geplant:
Low Speed mit 1.5 Mbit/s:
Die einfachste Variante des USB wird verwendet für billigere und einfachere Geräte wie Maus, Tastatur, elektronisches Zeichenbrett, Datenübertragung von Computer zu Handys, PDAs und anderem. Der B-Stecker ist meistens im Peripheriegerät fest verdrahtet. Das Kabel von Low-Speed-Geräten ist weder verdrillt, noch abgeschirmt, was sich in einer maximalen Kabellänge von 3 Metern niederschlägt. Diese Verbindungsart ersetzt sozusagen den ADB von Apple-Computern bzw den PS2-Anschluss von PCs.
Full Speed mit 12 Mbit/s:
Diese Variante hat sich durchgesetzt für Digital-Photoapparate, Scanner und andere Geräte, die eine relativ grosse Daten-Übertragungsrate voraussetzen. Die Datenleitungen sind verdrillt und das Kabel ist abgeschirmt, weshalb diese Kabel bis 5 Meter lang sein können. Diese Verbindungsart ersetzt Anschlüsse wie Parallel, Seriell, SCSI.
High Speed mit 480 Mbit/s: (erst ab USB 2.0)
Diese Version hat mittlerweile Einzug in den Computern gefunden. Sie wird benötigt für Digitalkameras externe Massenspeicher usw, also Geräte, die eine sehr hohe Datenübertragungs-Rate benötigen. Das Kabel kann wiederum bis zu 5 Meter lang sein.
Um zwischen den einzelnen Varianten zu unterscheiden, existieren Speed-Identifications, welche in obigem Link nachzulesen sind.
Kommunikation zwischen den Geräten
Die Kommunikation mit USB-Geräten geht folgendermassen vor sich:
Alle USB-Geräte werden im sogenannten Polling-Modus betrieben, was bedeutet, dass nicht die Geräte selbst berechtigt sind, Daten unkontrolliert zu senden (wie bei Interrupts), sondern dass nur der Host die Daten explizit anfordern kann, worauf das entsprechende Gerät dann antwortet.
Die Daten werden mittels Paketen übertragen. Um diese Pakete an die richtigen Stellen weiterzuleiten, werden folgende Bestandteile benötigt: SYNC, PID, ADDR, ENDP, CRC und EOP.
SYNC (8 Bit): Dient zur Synchronisierung mit dem anzusprechenden Gerät: Diese Synchronisation muss bei allen Paketen gesendet werden.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
PID (8 Bit): Dient zur Festlegung des Paket-Typs:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| p0 | p1 | p2 | p3 | ~p0 | ~p1 | ~p2 | ~p3 |
p0 bis p3 sind die einzelnen Bits der folgenden Tabelle, ~p0 bis ~p3 sind die jeweiligen invertierten 0-1-Werte. Dadurch werden folgende Pakettypen möglich:
| Pakettyp | PID | Beschreibung |
|---|---|---|
| Token | 0001 1110 | OUT (Auf Gerät schreiben) |
| 1001 0110 | IN (Von Gerät lesen) | |
| 0101 1010 | SOF (Start of Frame) | |
| 1101 0010 | SETUP (Initialisierungsbefehle) | |
| Data | 0011 1100 | DATA0 |
| 1011 0100 | DATA1 | |
| 0111 1000 | DATA2 | |
| 1111 0000 | MDATA | |
| Handshake | 0010 1101 | ACK |
| 1010 0101 | NACK | |
| 1110 0001 | STALL | |
| 0110 1001 | NYET | |
| Special | 1100 0011 | PRE |
| 1100 0011 | ERR | |
| 1000 0111 | Split | |
| 0100 1011 | Ping |
ADDR (7 Bit): Dient zur Festlegung des Zeilgerätes: Jedes Gerät erhält eine Nummer von 1 bis 127, wodurch es eindeutig indetifizierbar wird. Hat ein Gerät noch keine Nummer, so antwortet es auf die Nummer 0.
ENDP (4 Bit): ENDP dient zur Identifikation der von einem USB-Gerät angebotenen Funktionen. Beispielsweise könnte eine Tastatur zwei Funktionen anbieten: eine, welche die Tastenbetätigungen zurückgibt und eine, welche die Steuerung der Lämpchen für NumLock, ScrollLock und CapsLock empfängt. Bei jedem Gerät muss der ENDP 0 fest eingebaut sein, welcher bei Anfrage den Status des Gerätes zurückgibt. Low-Speed-Geräte können nur 2 zusätzliche ENDP anbieten.
Die ADDR- und ENDP-Bits werden auch als 11-Bit-Frame-Number zusammengefasst.
CRC (5 bit oder 16 bit): Der CRC-Check wird bei einigen Paketen durchgeführt (Fehlerdetektion). Daten-Pakete benutzen einen CRC16, alle Token-Pakete einen CRC5.
EOP: Dient zur Festlegung des Endes des Paketes. Dieses EOP steht am Ende jedes Paketes. Das EOP wird erreicht durch ungefähr 2 SE0 und ein anschliessendes J (siehe oben).
Der Aufbau der verschiedenen Paket-Typen
Token-Pakete:
| Bits | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| SYNC | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| PID | x | x | 0 | 1 | x | x | 1 | 0 |
| ADDR | x | x | x | x | x | x | 1 | |
| ENDP | x | x | x | x | ||||
| CRC5 | x | x | x | x | x | |||
| EOP | ...xxx... | |||||||
Ein IN-Paket informiert das Gerät, dass der Host Informationen lesen will.
Ein OUT-Paket informiert das Gerät, dass der Host Informationen senden will.
Ein SETUP-Paket ist der Header für Kontrolldaten.
Ein SOF-Paket wird vom Host versendet und zwar alle 0.5 bis 1.5 Millisekunden.
Daten-Pakete:
| Bits | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| SYNC | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| PID | x | x | 1 | 1 | x | x | 0 | 0 |
| Daten | xxxxxxxx | |||||||
| ... | ||||||||
| xxxxxxxx | ||||||||
| CRC16 | x | x | x | x | x | x | x | x |
| x | x | x | x | x | x | x | x | |
| EOP | ...xxx... | |||||||
Als Daten-Pakete werden DATA0 und DATA1 verwendet. Im Daten-Bereich können 0 bis 1023 Bytes übermittelt werden.
Handshake-Pakete:
| Bits | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| SYNC | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| PID | x | x | 1 | 0 | x | x | 0 | 1 |
| EOP | ...xxx... | |||||||
Ein ACK wird versendet, wenn das Paket korrekt angekommen ist.
Ein NAK wird versendet, wenn das Gerät momentan nichts senden kann. Dies bedeutet normalerweise, dass das Gerät die Anfrage zwar verstanden hat, jedoch an dieser noch zu kauen hat. Ein NAK wird also standartmässig gesetzt, sobald das Gerät die Anfrage verstanden hat. Erst wenn die Funktion ausgeführt werden konnte, wird dieses wieder gelöscht und das korrekte Resultat bereitgestellt.
Ein STALL wird versendet, wenn das Gerät vom Host neu aufgesetzt werden muss (Es ist ein Fehler aufgetreten).
Kontroll-Strukturen
Die Kommunikation zwischen den Geräten funktioniert immer vom Host aus. So hat also auch jedes Gerät für jeden ENDP je einen IN- und einen OUT-Puffer (von normalerweise 8 Bit). Das OUT beinhaltet stets das, was vom Host gesendet wurde und das IN das, was vom Host gelesen werden soll. Die Kontroll-Strukturen legen fest, wie die Übermittlung der Daten vom Host zum Gerät und umgekehrt verläuft.
Setup
Um eine Gerät zu initialisieren, wird das Setup-Schema angewendet: Zuerst sendet der Host ein SETUP-Paket an die zu überprüfende ADDR. Die angesprochene Funktion (ENDP) des festgelegten Gerätes erwartet nun vom Host als nächstes ein DATA0-Paket, worin beschrieben ist, was genau initialisiert werden soll (Siehe unten). Hat das Gerät alle Daten korrekt bekommen (CRC und PID sind fehlerfrei), so sendet es ein ACK, ansonsten nichts.
Je nach Inhalt des DATA0-Pakets erwartet dieselbe Funktion nun weitere Kontroll-Befehle. Um den Datenfluss zu kontrollieren, können ein oder mehrere Datenpakete versendet werden. Um wieviele Daten es sich handelt, wird ebenfalls im DATA0-Paket des Setups festgehalten. Sind es mehr Daten als die maximale Länge eines Datenpakets erlaubt, so werden sie in mehreren Paketen gesendet, wovon alle die maximale Länge haben ausser dem letzten.
Hier muss noch angefügt werden, dass eine Funktion eines beliebigen Gerätes nur entweder als Sender oder als Empfänger dienen kann (deshalb sind bei Low-Speed-Geräten auch 2 ENDP erlaubt). Je nachdem, was die betreffende Funktion anbietet, muss auch das entsprechende überprüft werden.
Datenfluss Sender (Funktion -> Host):
Der Host sendet ein IN-Token. Erhält die Funktion dieses Paket nicht oder enthält es Fehler, so ignoriert es die weiteren Schritte und tut nichts. Falls das Paket korrekt ankam, so kann die Funktion entweder ein DATA-Paket zur Kontrolle ausgeben, oder durch ein STALL-Paket anzeigen, dass das Gerät einen Fehler hat oder ein NAK, um anzuzeigen, dass die Funktion noch nicht bereit ist, um eine Antwort auf die Anfrage zu liefern. Der Host liest nun das Resultat aus und antwortet, falls ein DATA-Paket gesendet wurde, mit einem ACK.
Datenfluss Empfänger (Host -> Funktion):
Der Host sendet ein OUT-Token, wodurch die Funktion nun ein DATA-Paket erwartet, welches der Host auch gleich als zweites sendet. Kam eines dieser Pakete nicht korrekt bei der Funktion an, so wird nichts zurückgegeben. Des weiteren reagiert die Funktion genau gleich, wie bei der obigen Kontrolle (Funktion -> Host)
Nach bestimmten Befehlen muss die Übertragungsprozedur noch abgeschlossen werden, damit das Gerät wieder auf andere Befehle reagieren kann. Je nachdem, was getan wurde (je nachdem, ob die Funktikon als Sender oder als Empfänger arbeitet) muss hier noch mitgeteilt werden, ob alles glatt gelaufen war. (Kleine Anmerkung: in der oben aufgeführten englischen Dokumentation sind die Zeichnungen aus Versehen vertauscht)
Abschluss für Sender:
Bei einer Sende-Funktion muss der Host der Funktion melden, dass alle Daten korrekt angekommen sind. Dies geschieht mittels einem OUT-Token und einem anschliessenden DATA0-Paket mit der Länge 0. Wiederum kann die Funktion mit einem ACK, STALL oder NAK antworten. Danach sollte die Prozedur abgeschlossen sein.
Abschluss für Empfänger:
Der Host muss die Funktion fragen, ob alle Daten korrekt angekommen sind. Deshalb sendet er ein IN-Token. Die Funktion gibt entweder ein NAK (noch nicht bereit), ein STALL (Fehler) oder ein DATA0-Paket der Länge 0 zurück. Erhält der Host dieses DATA0-Paket, so sendet er noch ein ACK und damit ist die Prozedur abgeschlossen.
Interrupt-Transfer
Da USB im polling-Modus betrieben wird, gibt es keine eigentlichen Interrupts. Ein Gerät kann jedoch, wenn es Aufmerksamkeit erfordert, ein Interrupt-Paket bereitlegen, welches sofort nach dem Erhalt eines IN-Tokens an den Host zurückgegeben wird. Der Host antwortet darauf mit einem ACK und führt den Interrupt aus. Soll kein Interrupt ausgeführt werden, so legt die Funktion ein NAK bereit.
Möchte der Host ein Interrupt auf einem USB-Gerät erwirken, so sendet er einfach ein OUT-Paket gefolgt von einem DATA-Paket. Das Gerät antwortet dann mit einem ACK, falls der Interrupt ausgeführt werden kann und mit einem STALL oder NAK, wenn das Gerät einen Fehler hat oder nicht bereit ist.
Asynchroner Transfer
Beim asynchronen Transfer werden Daten ohne Handshake übergeben. Will der Host lesen, so sendet er ein IN-Paket und erwartet ab nun lauter DATA-Pakete von dem Gerät. Will der Host schreiben, so sendet er ein OUT-Paket und gleich darauf alle DATA-Pakete, die er senden will. Das Gerät hat keine Möglichkeit irgendwelche Fehlermeldungen zurückzugeben. Es kann also durchaus passieren, dass Datenverlust auftritt.
Synchroner Transfer (Bulk)
Beim synchronen Transfer wird für jedes Paket, das gesendet wird, überprüft, ob es korrekt angekommen ist und je nachdem ein ACK oder ein NAK gesendet.
Konfigurationen
Jedes Gerät muss sich beim Host zu erkennen geben können. Ein Gerät muss also seine gesamte Funktionalität kennen und die entsprechenden Konfigurationen dem Host übermitteln können. Beispielsweise können einige Geräte sowohl mit eigener Stromversorgung, als auch mit dem maximal 500mV des USB-Netzwerkes arbeiten. Je nachdem, was gerade möglich ist, muss dem Host also übermittelt werden, welche Konfiguration gerade aktiv ist. Tatsächlich existiert für viele USB-Geräte jedoch gerade mal eine Konfiguration, obschon durch dieses System eine enorme Flexibilität möglich wäre.
Device-Descriptor
Die Informationen sind als Baum in einem Gerät gespeichert. Zuoberst (Wurzelknoten) steht jeweils der Device-Descriptor. Dieser beinhaltet folgende Daten:
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x01) |
| 2 | 2 | bcdUSB | USB-Version als packed-BCD mit folgendem Format: JJMN wobei JJ die Hauptnummer und M und N jeweils Sub-Nummern der vorangehenden sind. Version 1.0 hat also den Code 0x0100, Version 1.1 den Code 0x0110 und Version 2 den Code 0x0200 |
| 1 | 4 | bDeviceClass | Klassen-Code |
| 1 | 5 | bDeviceSubClass | Subklassen-Code |
| 1 | 6 | bDeviceProtocol | Protokoll-Code. Die letzten drei Grössen dienen dem System, um den richtigen Klassen-Treiber zu aktivieren. Wenn Klassen-Code gleich 0, dann definiert jedes Interface seinen eigenen Klassen-Code. Wenn Klassen Code gleich 0xff, so ist der Code Vendor-spezifisch. |
| 1 | 7 | bMaxPacketSize | Maximale Paketgrösse für ENDP 0. Mögliche Werte sind 8, 16, 32 und 64. |
| 2 | 8 | idVendor | Vendor-ID |
| 2 | 10 | idProduct | Produkt-ID. Die letzten beiden Grössen dienen ebenfalls dem System, um den korrekten Treiber zu aktivieren. |
| 2 | 12 | bcdDevice | Diese Zahl hat dasselbe Format wie die USB-Version. Sie bezeichnet die Version des Gerätes. |
| 1 | 14 | iManufacturer | String-Index für Hersteller |
| 1 | 15 | iProduct | String-Index für Produkt |
| 1 | 16 | iSerialNumber | String-Index für Seriennummer Die letzten drei Werte dienen dazu, um das Gerät genauer zu beschreiben. Falls diese Strings nicht existieren, sollten sie NULL sein. |
| 1 | 17 | bNumComfigurations | Anzahl Konfigurationen |
Configuration-Descriptor
Ein Configuration-Descriptor enthält Informationen wie Anzahl mA, die benötigt werden, ob eine eigene Stromversorgung verwendet wird und die Anzahl Interfaces, die das Gerät unter dieser Konfiguration anbietet. Sobald ein solcher Deskriptor geladen wird, wird automatisch der gesamte darunterstehende Baum übergeben
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x02) |
| 2 | 2 | wTotalLenght | Länge der total zurückgegebenen Daten (gesamter Baum) |
| 1 | 4 | bNumInterfaces | Anzahl Interfaces |
| 1 | 5 | bConfigurationVal | Konfigurations-Nummer |
| 1 | 6 | iConfiguration | String-Index für Konfiguration |
| 1 | 7 | bmAttributes | Bit 7 gesetzt, falls USB-Strom benutzt wird (wurde nur in USB-Version 1.0 benutzt) Bit 6 gesetzt, falls eigene Stromversorgung Bit 5 gesetzt, falls Gerät den Host aufwecken kann |
| 1 | 8 | bMaxPower | Anzahl mA, die benötigt werden. |
Interface-Descriptor
Ein Interface-Descriptor ist eine Art Header für die verschiedenen implementierten Funktionalitäten. Beispielsweise könnte ein Multifunktionsgerät Interfaces anbieten für das Fax, den Printer und den Scanner. Diese Interfaces könnnen alle gleichzeitig aktiv sein. Der Host kann jedoch zwischen den Interfaces umschalten. Tatsächlich können sogar mehrere Interfaces für die gleiche Funktionalität erstellt werden. Dazu gibt es im Interface-Descriptor nebst der Interfacenummer und der anzahl Entpoints noch eine Nummer für das nächste alternative Interface.
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x04) |
| 1 | 2 | bInterfaceNumber | Interface-Nummer |
| 1 | 3 | bAlternateSetting | nächstes alternatives Interface |
| 1 | 4 | bNumEndpoints | Anzahl ENDP für dieses Interface (ohne ENDP 0) |
| 1 | 5 | bInterfaceClass | Klassen-Code |
| 1 | 6 | bInterfaceSubClass | Subklassen-Code |
| 1 | 7 | bInterfaceProtocol | Protokoll-Code. Die letzten drei Werte stehen für Treiber Informationen, die das System zu laden hat. |
| 1 | 8 | iInterface | String-Index für Index-Beschreibung. |
Endpoint-Descriptor
Ein Endpoint-Descriptor schliesslich speichert den Transfer-Typ, die Richtung, das polling-Intervall und die maximale Paketgrösse. Der Endpoint 0 wird nicht durch einen Descriptor beschrieben, er ist standartisiert (Kontroll-Funktion).
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x05) |
| 1 | 2 | bEndpointAddress | Bit 7 ist 0 für einen Empfänger und 1 für einen Sender. Die Bits 6 bis 4 sind reserviert (0). Die Bits 3 bis 0 bezeichnen die Nummer des ENDP. |
| 1 | 3 | bmAttributes | Bits 1 und 0 legen den Transfertyp fest: 00=Kontroll 01=Asynchron 10=Synchron (Bulk) 11=Interrupt Bits 7 bis 2 sind grunsätzlich reserviert, ausser wenn Asynchron: Bits 3 und 2: 00=Keine Synchronisation, 01=Asynchron, 10=Adaptiv, 11=Synchron Bits 5 und 4: 00=Data Edpoint, 01=Feedback Endpoint, 10=Explicit Feedback Data Endpoint, 11=reserved |
| 2 | 4 | wMaxPacketSize | Maximale Paketgrösse |
| 1 | 6 | bInterval | Nur für Asynchron und Interrupt: Anzahl Frames, die zwischen den Pollings gewartet werden muss. Ein Frame ist bei einem Low- und Full-Speed-Gerät 1 ms und bei einem High-Speed-Gerät 125 microSekunden. |
String-Descriptor
Was noch bleibt sind die String-Deskriptoren. Darin werden die genauen Bezeichnungen von den Geräten, Interfaces, usw. festgehalten. Die Strings liegen in Unicode vor. Jeder Index, der in den oben aufgeführten Deskriptoren nicht benutzt wird, muss 0 enthalten. Der Index 0 beinhaltet folgende Definitionen:
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x03) |
| 2 | 2 | wLANGID[0] | Code-Null-Sprache |
| 2 | 4 | wLANGID[1] | Code-Eins-Sprache |
| 2 | 6 | wLANGID[2] | Code-x-Sprache |
Die Sprachen sind international für USB festgelegt. Die folgenden Deskriptoren definieren die eigentlichen Strings:
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bLength | Grösse des Descriptors in Bytes |
| 1 | 1 | bDescriptorType | Descriptor-Typ (0x03) |
| n | 2 | bString | String der Länge n |
Das SETUP-Paket
Nun kommt noch die Beschreibung des SETUP-Paketes (Siehe oben), womit die Geräte erst angesprochen und initialisiert werden können. Der Host schickt dabei das SETUP-Token an die entsprechende Adresse und erwartet allgemein eine Antwort innerhalb von 5 Sekunden. Für spezifische Anfragen sind andere Ablaufzeiten vorgesehen:
Geräte ohne eigenen Speicher müssen innerhalb von 50 ms antworten.
Geräte mit eigenem Speicher müssen innerhalb von 500 ms antworten und jedes weitere Paket muss wiederum maximal 500 ms nach dem ersteren gesendet worden sein. Die Status-Abfrage muss innerhalb von 50 ms erfolgt sein.
Der SetAddress-Befehl muss innerhalb von 50 ms erfolgt sein. Danach hat das Gerät noch 2 ms
Zeit, um die Adresse tatsächlich zu ändern.
Diese Einschränkungen haben für den normalen Gebrauch kaum Auswirkungen, erzeugt jedoch für das Testen von Geräten einige Probleme.
Jede Statusanfrage enthält ein 8-Byte langes Datenpaket, worin folgende Anfragen enthalten sind:
| Bytes | Offset | Name | Inhalt |
|---|---|---|---|
| 1 | 0 | bmRequestType | Bit 7: Transferrichtung 0: vom Host, 1: zum Host Bits 6 und 5: Typ: 00=Standart, 01=Klasse, 10=Vendor, 11=reserviert Bits 4 bis 0: angesprochener Teil: 0=Gerät, 1=Interface, 2=ENDP, 3=anderes, 4 bit 31: reserviert |
| 1 | 1 | bRequest | Art der Anfrage (siehe unten) |
| 2 | 2 | wValue | Parameter |
| 2 | 4 | wIndex | Parameter |
| 2 | 6 | wLegnht | gibt die Anzahl Daten an, die beim folgenden Übertragungstest gesendet werden |
Geräte-Anfragen:
Was der Wert bRequest beinhaltet hängt vom Hersteller und Programmierer ab, es gibt jedoch einige Anfragen, die auf jedem Gerät implementiert sein müssen:
| bmRequestType | bRequest | wValue | wIndex | wLength | Daten |
|---|---|---|---|---|---|
| 1000 0000 | 0x00 GET_STATUS | 0 | 0 | 2 | Geräte-Status |
| 0000 0000 | 0x01 CLEAR_FEATURE | Modus | 0 | 0 | - |
| 0000 0000 | 0x03 SET_FEATURE | Modus | 0 | 0 | - |
| 0000 0000 | 0x05 SET_ADDRESS | Adresse | 0 | 0 | - |
| 1000 0000 | 0x06 GET_DESCRIPTOR | Typ+Index | 0 oder Sprache | Länge | Deskriptor |
| 0000 0000 | 0x07 SET_DESCRIPTOR | Typ+Index | 0 oder Sprache | Länge | Deskriptor |
| 1000 0000 | 0x08 GET_CONFIG | 0 | 0 | 1 | Konfigurations-Wert |
| 0000 0000 | 0x09 SET_CONFIG | Wert | 0 | 0 | - |
Beim GET_STATUS wird das Gerät 2 Bytes zurückgeben, von welchen momentan erst die untersten beiden Bits gebraucht werden. Bit 0 besagt, ob das Gerät eine eigene Stromversorgung besitzt, und das Bit 1 besagt, ob das Gerät den Host aufwecken darf.
Das CLEAR_ und SET_FEATURE können das Gerät entweder in den Aufweck-Modus oder in den Test-Modus versetzen (bzw sie davon befreien).
SET_ADDRESS wird benötigt, wenn ein Gerät frisch angeschlossen wurde. Dann nämlich hat das Gerät die Nummer 0 und muss erst eine gültige Adresse bekommen.
SET_ und GET_DESCRIPTOR dienen dazu, um die Funktionalität des Gerätes abzufragen. Es können dabei entweder Geräte-, Konfigurations- oder String-Deskriptoren geladen werden (Interface- und ENDP-Deskriptoren werden mit den Konfigurations-Deskriptoren mitgeliefert). Der Typ entspricht den Typen, die bei den Deskriptoren eingetragen sind (siehe oben). Für String-Deskriptoren muss zusätzlich eine Sprache angegeben werden.
GET_ und SET_CONFIGURATION dient zum Setzen von bestimmten Konfigurationen.
Interface-Anfragen:
| bmRequestType | bRequest | wValue | wIndex | wLength | Daten |
|---|---|---|---|---|---|
| 1000 0001 | 0x00 GET_STATUS | 0 | Interface | 2 | Geräte-Status |
| 0000 0001 | 0x01 CLEAR_FEATURE | Modus | Interface | 0 | - |
| 0000 0001 | 0x03 SET_FEATURE | Modus | Interface | 0 | - |
| 1000 0001 | 0x0a GET_INTERFACE | 0 | Interface | 1 | alternatives Interface |
| 0000 0001 | 0x11 SET_INTERFACE | alternatives Set | Interface | 0 | - |
Für den Wert von wIndex wird nur das untere Byte benötigt, um die Interface-Nummer einzutragen.
GET_STATUS gibt momentan erst den Wert 0x0000 zurück, ist aber für zukünftike Funktionen reserviert.
CLEAR_ und SET_FEATURE sind ebenfalls noch reserviert.
GET_ und SET_INTERFACE dienen zum Erreichen von alternativen Interfaces (siehe oben)
ENDP-Anfragen:
| bmRequestType | bRequest | wValue | wIndex | wLength | Daten |
|---|---|---|---|---|---|
| 1000 0010 | 0x00 GET_STATUS | 0 | ENDP | 2 | Geräte-Status |
| 0000 0010 | 0x01 CLEAR_FEATURE | Modus | ENDP | 0 | - |
| 0000 0010 | 0x03 SET_FEATURE | Modus | ENDP | 0 | - |
| 1000 0010 | 0x12 SYNCH_FRAME | 0 | ENDP | 2 | Frame-Nummer |
Für den Wert von wIndex wird nur das untere Byte benötigt. Bit 7 gibt die Transferrichtung an und die Bits 3 bis 0 die Nummer des ENDP.
GET_STATUS gibt 2 Bytes zurück, bei denen nur das unterste Bit relevant ist. Dieses zeigt an, ob der ENDP einen Fehler aufweist oder nicht.
CLEAR_ und SET_FEATURE sind dazu da, um ein ENDP in den Fehlerzustand zu versetzen, oder ihn davon zu befreien.
SYNCH_FRAME gibt die Frame-Adresse zurück.
Geräteerkennung
Was passiert, wenn ein USB-Gerät eingesteckt wird? Dieser Prozess, welcher Enumeration genannt wird, ist im Normalfall nicht geregelt, es gibt jedoch einige Dinge, die in einer gewissen Reihenfolge passieren müssen. Hier ist das Beispiel, wie Windows Geräte erkennt:
- Der Controller erkannte, dass ein neues Gerät angeschlossen wurde, indem sich die Spannung auf den beiden Datenleitungen änderte (wie genau, weiss ich nicht). Der Controller wartet darauf 100ms, sodass der Stecker vollständig eingesteckt werden kann und das Gerät ausreichend mit Strom versorgt ist.
- Windows bekommt nun vom Controller die Meldung, dass sich ein neues Gerät angeschlossen hat und auf die Adresse 0 initialisiert ist.
- Windows fragt nach 64 Bytes vom Device-Deskriptor. (Ist kein Schreibfehler, siehe Dokumentation)
- Sobald die ersten 8 Bytes gelesen wurden, wird das Gerät wieder auf NULL gesetzt.
- Nun wird dem Gerät eine neue Adresse zugeteilt.
- Nochmals wird der Device-Deskriptor angefordert (diesmal unter der neuen Adresse) und vollständig geladen.
- Der Konfigurations-Deskriptor wird angefordert. Jedoch werden nur die ersten 9 Bytes beachtet.
- Die Anzahl Bytes des gesamten Deskriptor-Baumes wird herausgelesen und dieselbe Anzahl vom Konfigurations-Deskriptor angefordert.
- Falls irgendwelche String-Deskriptoren aufgetreten sind, werden diese noch angefordert.
- Windows sucht nach Treibern.
Quelle: USB in a Nutshell

