| Zeile 169: | Zeile 169: | ||
===== Zusammenfassung ===== | ===== Zusammenfassung ===== | ||
Hier nochmal alles auf einen Blick: | Hier nochmal alles auf einen Blick: | ||
| − | {| {{Prettytable}} | + | {| {{Prettytable}} cellpadding="5" |
! Transfertyp !! Datenmenge !! Datensicherheit !! Bandbreite !! Typischer Einsatz | ! Transfertyp !! Datenmenge !! Datensicherheit !! Bandbreite !! Typischer Einsatz | ||
|- | |- | ||
| Zeile 186: | Zeile 186: | ||
Die USB-Zeit wird in Abschnitte, genannt Frames unterteilt. Solch ein Frame dauert immer eine Millisekunde, er beginnt mit einem SOF-Paket (Start of frame). Dies garantiert einerseits, dass ein Gerät nicht in den Suspendzustand gerät, andererseits aber auch, dass die Bandbreite sinnvoll aufgeteilt werden kann. So kann in jedem Frame eine gewisse Zeit für periodische Transfers reserviert werden, der Rest wird dann mit asynchronen Transfers aufgefüllt. Frames gibt es nur bei Full- und High-Speed-Geräten, Low-Speed-Geräte erhalten keine Frames (da sie nur Control- und Interrupttransfers ausführen dürfen, fällt das Scheduling hier nicht schwer), sondern sogenannte Low-Speed-Keepalives. Diese besitzen an sich keine Funktion, sie sorgen nur für etwas Busaktivität und verhindern so, dass das Gerät in den Suspendmodus schaltet. | Die USB-Zeit wird in Abschnitte, genannt Frames unterteilt. Solch ein Frame dauert immer eine Millisekunde, er beginnt mit einem SOF-Paket (Start of frame). Dies garantiert einerseits, dass ein Gerät nicht in den Suspendzustand gerät, andererseits aber auch, dass die Bandbreite sinnvoll aufgeteilt werden kann. So kann in jedem Frame eine gewisse Zeit für periodische Transfers reserviert werden, der Rest wird dann mit asynchronen Transfers aufgefüllt. Frames gibt es nur bei Full- und High-Speed-Geräten, Low-Speed-Geräte erhalten keine Frames (da sie nur Control- und Interrupttransfers ausführen dürfen, fällt das Scheduling hier nicht schwer), sondern sogenannte Low-Speed-Keepalives. Diese besitzen an sich keine Funktion, sie sorgen nur für etwas Busaktivität und verhindern so, dass das Gerät in den Suspendmodus schaltet. | ||
| − | Im High-Speed-Betrieb gibt es zusätzlich noch sogenannte Microframes. Während eines Frames gibt es acht Microframes, welche somit jeweils 125 µs dauern. Jeder Microframe beginnt mit einem SOF-Paket. Dabei ändert sich die dort eingetragene Framenummer (zwischen 0 und | + | Im High-Speed-Betrieb gibt es zusätzlich noch sogenannte Microframes. Während eines Frames gibt es acht Microframes, welche somit jeweils 125 µs dauern. Jeder Microframe beginnt mit einem SOF-Paket. Dabei ändert sich die dort eingetragene Framenummer (zwischen 0 und 2047) jedoch nur alle 8 Microframes (also bei jedem vollen Frame). |
==== Flusskontrolle ==== | ==== Flusskontrolle ==== | ||
| Zeile 241: | Zeile 241: | ||
| PING || 0xB4 || Wird zur High-Speed-Flusskontrolle eingesetzt (s. [[#High-Speed|entsprechender Abschnitt]]). | | PING || 0xB4 || Wird zur High-Speed-Flusskontrolle eingesetzt (s. [[#High-Speed|entsprechender Abschnitt]]). | ||
|} | |} | ||
| + | |||
| + | ==== ADDR ==== | ||
| + | Dieses Feld ist sieben Bit lang und enthält die USB-Adresse des Zielgeräts (so ergeben sich die Adressen 0 bis 127, wobei 0 ja als Defaultadresse nach dem Reset reserviert ist). Wenn diese Adresse nicht mit der des USB-Geräts übereinstimmt, muss es das Paket natürlich verwerfen. | ||
| + | |||
| + | ==== ENDP ==== | ||
| + | Kommen wir nun zum Endpunkt, der oben mit einem Netzwerkport verglichen wurde. Dieses Feld gibt seine Nummer an und ist vier Bit lang, so ergeben sich theoretisch 16 verschiedene Endpunkte. Ein Endpunkt kann allerdings nur in eine Richtung weisen, sodass es theoretisch 32 verschiedene Endpunkte gibt. Allerdings gibt es auch hier einen Defaultendpunkt, und das ist auch Endpunkt 0 (EP0). Er wird nur für Controltransfers verwendet und kann in beide Richtungen benutzt werden. Damit gibt es praktisch 31 Endpunkte (30 frei verwendbare unidirektionale und der bidirektionale Defaultendpunkt). Low-Speed-Geräte dürfen nur drei Endpunkte definieren, während Full- und High-Speed-Geräte die volle Zahl von 31 Endpunkten benutzen dürfen. | ||
| + | |||
| + | Wenn ein Gerät den angegebenen Endpunkt nicht besitzt, oder dieser in irgendeiner Weise initialisiert werden muss, aber nicht wurde, dann muss das Gerät das Paket verwerfen. | ||
| + | |||
| + | ==== Framenummer ==== | ||
| + | Dieses elf Bit lange Feld gibt die aktuelle Framenummer an (0 bis 2047) und wird nur in SOF-Paketen gesendet. | ||
| + | |||
| + | ==== Datenfeld ==== | ||
| + | Jetzt folgen endlich die Daten. Dieses Feld besitzt keine feste Länge, sondern kann von 0 bis 1024 Bytes enthalten. | ||
| + | |||
| + | ==== CRC ==== | ||
| + | Ganz zum Schluss folgt noch ein CRC-Feld, das gewährleistet, dass die empfangenen Daten korrekt sind. Wird bei der CRC-Berechnung ein Fehler erkannt, dann wird das Paket verworfen. | ||
| + | |||
| + | Bei Tokenpaketen (in diesem Fall IN, OUT, SOF, SETUP, PING, SPLIT) folgt ein CRC5 über ADDR und ENDP (oder das Framenummerfeld bei SOF), bei Datenpaketen ein CRC16 über das Datenfeld. | ||
| + | |||
| + | Bei CRC5 erfolgt die Berechnung mit dem Startwert 0x1F und dem Polynom 0x05, bei CRC16 mit dem Startwert 0xFFFF und dem Polynom 0x8005. Nachdem der Wert berechnet wurde, wird er invertiert und mit dem MSb voran gesendet. Der Empfänger berechnet dann den CRC-Wert über die zu berechnenden Felder und das empfangene CRC-Feld (wobei es angehangen wird, als wäre es ein normaler nicht invertierter LSb-Wert), bei CRC5 sollte sich dann ein Wert von 0x0C ergeben, bei CRC16 0x800D. | ||
| + | |||
| + | Ein Beispiel wäre der Wert 01010100 (42). Als CRC5 berechnet sich hier 0x06, als CRC16 0x7CF9. Gesendet wird dann der Wert 0x13 bzw. 0x60C1, so ergeben sich beim Empfänger 0101010011001 bzw. 010101001000001100000110. Dafür ergibt sich nach CRC5 0x0C und nach CRC16 0x800D – es ist also kein Problem aufgetreten. | ||
| + | |||
| + | ==== EOP ==== | ||
| + | Nun ist die Frage, wie ein Gerät erkannt, wie lang das Datenfeld ist (da ja nirgendwo die Länge festgelegt ist). Dies geschieht über das EOP-Signal (End of packet), welches das Ende eines Pakets anzeigt (und damit auch seine Länge). Dieses besteht aus einem zwei Bitzeiten langen SE0, gefolgt von einem J-Zustand (welcher als Idle-Zustand anhält). Bei High-Speed wird der aktuelle Zustand invertiert und ''sieben'' Bitzeiten gehalten – hier passiert also auf jeden Fall ein Bitstufffehler, welcher als Indikator für das EOP verwendet wird (entspricht also einer Bitsequenz von 01111111 vor NRZI; beim SOF-Token wird 0111111111111111111111111111111111111111 gesendet (also fünf NRZI-Bytes), dies wird zum Erkennen von Disconnects verwendet (da High-Speed-Geräte ja normalerweise keine Spannung an D+/D- anlegen), hierbei wird dann eine höhere Spannung gemessen, wenn kein Gerät mehr vorhanden ist). Danach wird der Idle-Zustand (SE0) eingenommen. | ||
| + | |||
| + | ==== Verwendete Felder ==== | ||
| + | Nicht alle Felder werden gleichzeitig verwendet. Bei welchem Pakettyp welches Feld vorhanden ist, zeigt die folgende Tabelle: | ||
| + | |||
| + | {| {{Prettytable}} cellpadding="5" | ||
| + | ! PID !! ADDR !! ENDP !! Frame !! Daten !! CRC | ||
| + | |- | ||
| + | | OUT || x || x || || || 5 | ||
| + | |- | ||
| + | | IN || x || x || || || 5 | ||
| + | |- | ||
| + | | SOF || || || x || || 5 | ||
| + | |- | ||
| + | | SETUP || x || x || || || 5 | ||
| + | |- | ||
| + | | DATA0 || || || || x || 16 | ||
| + | |- | ||
| + | | DATA1 || || || || x || 16 | ||
| + | |- | ||
| + | | DATA2 || || || || x || 16 | ||
| + | |- | ||
| + | | MDATA || || || || x || 16 | ||
| + | |- | ||
| + | | ACK || || || || || | ||
| + | |- | ||
| + | | NAK || || || || || | ||
| + | |- | ||
| + | | STALL || || || || || | ||
| + | |- | ||
| + | | NYET || || || || || | ||
| + | |- | ||
| + | | PRE || || || || || | ||
| + | |- | ||
| + | | ERR || || || || || | ||
| + | |- | ||
| + | | SPLIT || x || || || || 5 | ||
| + | |- | ||
| + | | PING || x || x || || || 5 | ||
| + | |} | ||
| + | |||
| + | == USB-Transfer == | ||
| + | Ein richtiger USB-Transfer besteht allerdings nicht nur aus einzelnen Paketen. Es werden mehrere hintereinandergeschaltet, um eine richtige Transaktion durchzuführen. | ||
| + | |||
| + | === Handshake-Datentransfer === | ||
| + | Solch ein Datentransfer besteht normalerweise aus drei Paketen: | ||
| + | * Einem Token (IN/OUT/SETUP) | ||
| + | * Dem Datenpaket (DATA0/DATA1) | ||
| + | * Dem Handshake | ||
| + | |||
| + | Das Token gibt die Richtung des Transfer sowie den Empfänger an. Danach folgt das Datenpaket, welches logischerweise die Daten enthält. Gefolgt wird es dann vom Handshakepaket, das schlussendlich angibt, ob das Paket korrekt empfangen wurde. Ist es NAK, STALL oder fehlt es ganz, so ist ein Fehler aufgetreten. Bei STALL wird der Transfer abgebrochen, bei NAK und fehlendem Handshake meist komplett neu begonnen (ab dem IN/OUT). Ein ACK bedeutet, dass das Paket korrekt empfangen und akzeptiert wurde, ebenso wie ein NYET, dass den Host lediglich darauf hinweist, vor dem nächsten Transfer PING zu benutzen. Ein Beispiel für einen solchen Transfer wäre: | ||
| + | |||
| + | {| {{Prettytable}} cellpadding="5" | ||
| + | {{USB-Transferliste}} | ||
| + | {{USB-Transfer|dir=out|type=OUT|addr=42|endp=1|crc=0x1C}} | ||
| + | {{USB-Transfer|dir=out|type=DATA0|data=0x4C 0x6F 0x77 0x6C 0x65 0x76 0x65 0x6C 0x3F|crc=0x80F2}} | ||
| + | {{USB-Transfer|dir=in|type=ACK}} | ||
| + | |} | ||
| + | |||
| + | === Nicht-Handshake-Datentransfers === | ||
| + | Es gibt auch Datentransfers ohne Handshake, diese werden bei Isochronoustransfers verwendet. Ein Beispiel wäre hier: | ||
| + | |||
| + | {| {{Prettytable}} cellpadding="5" | ||
| + | {{USB-Transferliste}} | ||
| + | {{USB-Transfer|dir=out|type=IN|addr=42|endp=7|crc=0x13}} | ||
| + | {{USB-Transfer|dir=in|type=DATA0|data=0x4D 0x6F 0x69 0x6E 0x2C 0x20 0x6D 0x6F 0x69 0x6E 0x2C 0x20 0x47 0x65 0x6E 0x6F 0x73 0x73 0x65 0x6E 0x5C 0x21|crc=0x04A9}} | ||
| + | |} | ||
| + | |||
| + | == Zusammengesetzte Transfers == | ||
| + | Diese kleinen Bausteine werden dann zu den Transfertypen zusammengesetzt. | ||
| + | |||
| + | === Controltransfers === | ||
| + | Ein Controltransfer beginnt mit einer Setupstage, danach folgt die Datenstage und zuletzt kommt noch eine Handshakestage, die aber nichts mit den Handshakepaketen zu tun hat. Die in der Setupstage verwendeten Datenpakete sind immer DATA0, danach alterniert der Wert (DATA0/DATA1) und das letzte Paket ist immer DATA1. Daraus ergibt sich ein Gesamttransfer wie der dieses Beispiel, das den Device-Descriptor eines Geräts einliest, wobei hier für den Endpunkt 0 eine maximale Paketgröße von 8 Byte angenommen wird: | ||
| + | |||
| + | {| {{Prettytable}} cellpadding="5" | ||
| + | {{USB-Transferliste}} | ||
| + | {{USB-Transfer|dir=out|type=SETUP|addr=1|endp=0|crc=0x1D}} | ||
| + | {{USB-Transfer|dir=out|type=DATA0|data=0x80 0x06 0x00 0x01 0x00 0x00 0x12 0x00|crc=0x1A4E}} | ||
| + | {{USB-Transfer|dir=in|type=ACK}} | ||
| + | {{USB-Transfer|dir=out|type=IN|addr=1|endp=0|crc=0x1D}} | ||
| + | {{USB-Transfer|dir=in|type=DATA1|data=0x12 0x01 0x00 0x01 0x00 0x00 0x00 0x08|crc=0x3718}} | ||
| + | {{USB-Transfer|dir=out|type=ACK}} | ||
| + | {{USB-Transfer|dir=out|type=IN|addr=1|endp=0|crc=0x1D}} | ||
| + | {{USB-Transfer|dir=in|type=DATA0|data=0x27 0x06 0x01 0x00 0x00 0x00 0x03 0x02|crc=0xA7A8}} | ||
| + | {{USB-Transfer|dir=out|type=ACK}} | ||
| + | {{USB-Transfer|dir=out|type=IN|addr=1|endp=0|crc=0x1D}} | ||
| + | {{USB-Transfer|dir=in|type=DATA1|data=0x01 0x01|crc=8307}} | ||
| + | {{USB-Transfer|dir=out|type=ACK}} | ||
| + | {{USB-Transfer|dir=out|type=OUT|addr=1|endp=0|crc=0x1D}} | ||
| + | {{USB-Transfer|dir=out|type=DATA1}} | ||
| + | {{USB-Transfer|dir=in|type=ACK}} | ||
| + | |} | ||
| + | |||
| + | Wie man sieht, ist das letzte Datenpaket ein Paket ohne Inhalt. Hier wird immer die entgegengesetzte Richtung der Datenstage genommen (IN in der Datenstage → OUT in der Handshakestage und umgekehrt). Mit diesem wird noch einmal bestätigt, dass alle Daten korrekt empfangen wurden und auch korrekt interpretiert werden können (falls nicht, kommt ein STALL). | ||
== Links == | == Links == | ||