An alle USB-Experten ;-) Ich arbeite mich gerade ein wenig in USB Full-Speed ein und habe eine Frage bezüglich des Data-Toggle-Verfahrens bei Bulk-Transfers. Ich versuche das Ganze mal mit meinen Worten zu erklären, korrigiert mich bitte, falls ich falsch liege ;) Wenn die zu übertragenden Daten eine Größe von 64 Byte überschreiten (entspricht der maximalen Größe des Endpoint-Buffers bei Bulk-Transfers, die hier angenommen wird), müssen sie auf mehrere Transaktionen aufgeteilt werden. Angenommen ich möchte von einem USB Device bzw. von einer Function Daten an den USB Host senden und das Toggle-Bit ist bei Sender und Empfänger auf 0. Dann ist der Ablauf wie folgt: Host (0): Sendet IN-Token Device (0): Falls USB-Adresse und Endpoint-Nummer gültig sowie Sende-FIFO des Endpoints mit Daten gefüllt sind, wird ein DATA0-Paket mit den entsprechenden Daten gesendet. Host (0) -> (1): Bestätigt Empfang der Daten, falls sie fehlerfrei empfangen wurden mit einem ACK-Handshake. Data-Toggle-Bit wird auf (1) gesetzt. Device (0) -> (1): Empfängt ACK-Handshake und setzt daraufhin Data-Toggle-Bit ebenfalls auf (1). Host (1): Sendet IN-Token Device (1): Sendet DATA1-Paket Host (1) -> (0): Sendet ACK-Handshake, Data-Toggle-Bit wird auf (0) gesetzt. Device (1) -> (0): Empfängt ACK-Handshake und setzt daraufhin Data-Toggle-Bit ebenfalls auf (0). Das Ganze wiederholt sich so lange, bis alle Daten gesendet wurden und der Host ein unvollständiges DATAx-Paket oder ein Zero-Length-Paket erhält. Zu einer Asynchronität zwischen den Data-Toggle-Bits des Senders und Empfängers kann es nur bei einem fehlerhaft übertragenen Handshake kommen. Also wieder am Beispiel einer IN-Transaktion: Host (0): Sendet IN-Token Device (0): Sendet DATA0-Paket Host (0) -> (1): Empfängt DATA0-Paket fehlerfrei, setzt Data-Toggle-Bit auf (1), sendet ACK-Handshake Device (0): Empfängt fehlerhaftes ACK-Token, kein Togglen des Data-Toggle-Bit. Zu diesem Zeitpunkt hat der Host die Daten korrekt Empfangen, die Function denkt jedoch, dass bei der Datenübertragung Fehler aufgetreten sind und der Host die Daten verworfen hat, da die Transaktion nicht bestätigt wurde. Host (1): Sendet IN-Token Device (0): Sendet DATA0-Paket erneut Host (1) -> (1): Empfängt DATA0-Paket fehlerfrei, Toggle-Bits stimmen jedoch nicht überein (DATA1-Paket wurde erwartet), Daten werden verworfen und Toggle-Bit nicht gesetzt, sendet trotzdem ACK-Handshake Device (0) -> (1): Empfängt ACK-Token, setzt Data-Toggle-Bit auf (1). Damit herrscht nun wieder Synchronität bezüglich des Data-Toggle-Bits. Wo liegt nun der Sinn des ganzen Manövers? Dient das Data-Togglen nur dem Entdecken und Korrigieren eines Handshake-Fehlers? Außerdem habe ich eine weitere Frage: USB ist ein Single-Master Bus, bei dem der Host der einzige Master ist und alle Transfers initiiert. Am Beispiel eines IN-Bulk-Transfers: Woher weiß der Host, dass das USB Device Daten senden möchte? Läuft das irgendwie über den Control-Endpoint? Vielen Dank!
Andi K. schrieb: > Am > Beispiel eines IN-Bulk-Transfers: Woher weiß der Host, dass das USB > Device Daten senden möchte? Läuft das irgendwie über den > Control-Endpoint? Er pollt die Devices in einer vom Device konfigurierten Zeit. (Bei fullspeed minimal 5ms) MfG
Dann müsste die Polling-Zeit aber in einem Descriptor stehen. Zwar gibt es an einer Stelle einen ähnlichen Eintrag, nämlich bIntervall in den Endpoint-Descriptors, der ist aber für Interrupt- oder Isochronous-Transfers gedacht und wird von Bulk-Transfers ignoriert.
Andi K. schrieb: > Wo liegt nun der Sinn des ganzen Manövers? Dient das Data-Togglen nur > dem Entdecken und Korrigieren eines Handshake-Fehlers? Genau. Ausserdem: Was passiert, wenn der Empfänger nicht so schnell die Daten verarbeitet, wie der Sender sendet? - Dann gehen Datenpakete verloren. Aber genau dann wird das Data-Toggle nicht umgeschaltet vom Empfänger, die Antwort lautet NAK und der Sender weiss, dass er das gleiche Paket noch einmal senden muss. Was passiert, wenn der Empfänger ein Paket mit ACK bestätigt und der Sender das nicht mitbekommt? Der Sender sendet das gleiche Paket nochmal, aber der Empfänger verwirft es (falsches Data-Toggle) und gibt nur ein ACK zurück -> alles wieder synchron. Bei den Control-Transfers ist es wieder etwas anders. Im Setup-Abschnitt immer Data0, Data1 in der ersten Transaktion (schaltet dann um bei weiteren) und im Status-Abschnitt immer Data0. Andi K. schrieb: > Läuft das irgendwie über den > Control-Endpoint? Nein. Das läuft über die Daten-Endpunkte und da steht dann in den Descriptoren auch das Polling-Intervall drin.
Vielen Dank für deine Antwort! Im konkreten Fall habe ich hier einen Mikrocontroller, der als Device mit der Geräteklasse CDC ACM läuft und als virtueller COM Port am PC sichtbar ist. Dazu habe ich keine eigenen Funktionen geschrieben, sondern verwende Libraries vom Hersteller. Wenn ich nun im Code nach den Endpoint-Descriptors suche, erhalte ich für die beiden Data-Endpoints folgendes:
1 | .ep_in.bLength = sizeof(usb_ep_desc_t),\ |
2 | .ep_in.bDescriptorType = USB_DT_ENDPOINT,\ |
3 | .ep_in.bmAttributes = USB_EP_TYPE_BULK,\ |
4 | .ep_in.bInterval = 0,\ |
5 | .ep_out.bLength = sizeof(usb_ep_desc_t),\ |
6 | .ep_out.bDescriptorType = USB_DT_ENDPOINT,\ |
7 | .ep_out.bmAttributes = USB_EP_TYPE_BULK,\ |
8 | .ep_out.bInterval = 0, |
Dass es sich um Bulk-Endpoints handelt ist klar. Allerdings ist hier kein Intervall angegeben; daher auch meine Frage, woher der Host weiß, wann Daten verfügbar sind. Anscheinend wird das über einen Interrupt-Endpoint geregelt, da dieser (neben den beiden Bulk-Endpoints) als einziger noch definiert ist:
1 | .ep_notify.bLength = sizeof(usb_ep_desc_t),\ |
2 | .ep_notify.bDescriptorType = USB_DT_ENDPOINT,\ |
3 | .ep_notify.bmAttributes = USB_EP_TYPE_INTERRUPT,\ |
4 | .ep_notify.wMaxPacketSize = LE16(UDI_CDC_COMM_EP_SIZE),\ |
5 | .ep_notify.bInterval = 0x10,\ |
6 | .ep_notify.bEndpointAddress = UDI_CDC_COMM_EP_##port,\ |
Kann ich also davon ausgehen, dass der Host mit einem Interrupt-Intervall von 16 ms anfragt, ob Daten vorhanden sind und falls welche vorhanden sind, ein entsprechendes IN-Token an den Bulk-Endpoint sendet? Oder ist das zu sehr durch die Glaskugel geschaut? ;)
Das mit der 0 in den Bulk-Endpunkten ist meiner Meinung nach Käse. Ich gehe davon aus, wenn da eine Null drin steht, dass der Host das dann einfach ignoriert und das Intervall selber festlegt. Der Interrupt-Endpunkt übernimmt die Steuerleitungen der RS232 - also RST, CTS, ... Die Bulk-Endpunkte übertragen die Nutzdaten.
Ich muss mich korrigieren: Der Interrupt-Endpunkt schickt Status-Updates an den Host. Ob das auch die Steuerleitungen betrifft, k.A. - es ist schon etwas her, dass ich mich damit beschäftigt habe.
Danke! Wo kann ich nähere Informationen dazu finden? Die USB-Spezifikation ist dafür wohl nicht der richtige Anlaufpunkt. Auch die Spezifikation der Communication Device Class ist hier nicht weiter ergiebig.
:
Bearbeitet durch User
Andi K. schrieb: > Kann ich also davon ausgehen, dass der Host mit einem > Interrupt-Intervall von 16 ms anfragt, ob Daten vorhanden sind und falls > welche vorhanden sind, ein entsprechendes IN-Token an den Bulk-Endpoint > sendet? Nein. Der Host sendet IN-Tokens an Bulk EPs, wenn "noch Platz im 1 ms Frame" ist. Bedingung ist nur das auch jemand auf Host Seite die Daten haben will. Bei CDC muss also die Schnittstelle geöffnet sein. Wenn das Device grade keine Daten im Puffer hat, sendet es ein NAK als Antwort. Wie oft nun IN Tokens an einem Bulk EP eines Devices ankommen, hängt auch von der Auslastung des Busses ab.
Jim Meba schrieb: > Nein. Der Host sendet IN-Tokens an Bulk EPs, wenn "noch Platz im 1 ms > Frame" ist. > > Bedingung ist nur das auch jemand auf Host Seite die Daten haben will. > Bei CDC muss also die Schnittstelle geöffnet sein. Okay vielen Dank! Das heißt es kommt auch auf die Busauslastung an, zu welchem Zeitpunkt ein Bulk-Transfer gestartet werden kann. Weiß jemand, wo man das nachlesen kann? In der USB-Spezifikation bin ich noch nicht fündig geworden. Eine Frage hätte ich noch, dieses mal zu Interrupt-Transfers: Laut USB-Spezifikation ist es mit Full-Speed-Geräten möglich, bei einer Paketgröße von 64 Bytes eine maximale Datenrate von 1216000 byte/s zu erreichen, falls 19 Interrupt-Transfers in einem 1-ms-Frame gepackt werden (siehe angehängtes Bild, vorletzte Zeile). Allerdings wird auch erwähnt, dass die minimale Polling-Zeit des Hosts bei 1 ms liegt. Mit der maximalen Paketgröße (64 byte) hieße das, dass nur 64000 byte/s übertragen werden könnten (das liest man oft im Internet, u.A. auf wikipedia). Was ist nun richtig? P.S.: Sorry für das Ausgraben meines alten Threads ;)
:
Bearbeitet durch User
Andi K. schrieb: > Allerdings wird auch erwähnt, dass die minimale Polling-Zeit des Hosts > bei 1 ms liegt. Mit der maximalen Paketgröße (64 byte) hieße das, dass > nur 64000 byte/s übertragen werden könnten (das liest man oft im > Internet, u.A. auf wikipedia). Was ist nun richtig? Das gilt bei Interrupt-Endpunkten. Andi K. schrieb: > Laut USB-Spezifikation ist es mit Full-Speed-Geräten möglich, bei einer > Paketgröße von 64 Bytes eine maximale Datenrate von 1216000 byte/s zu > erreichen, falls 19 Interrupt-Transfers in einem 1-ms-Frame gepackt > werden (siehe angehängtes Bild, vorletzte Zeile). Das gilt bei Bulk-Endpunkten. Stichwort: Micro-Frames.
Mir ist bewusst, dass das für Interrupt-Endpoints gilt, deswegen habe ich auch ausdrücklich von Interrupt-Transfers gesprochen ;) Micro-Frames sind erstmal irrelevant, weil es hier nur um USB Full-Speed und nicht um High-Speed geht. Hast du dir das Bild angesehen? Das stammt direkt aus der USB-Spezifikation und zeigt, dass anscheinend 1216000 byte/s statt 64000 bytes/s für USB Full-Speed Interrupt-Transfers möglich sind.
:
Bearbeitet durch User
Andi K. schrieb: > Mir ist bewusst, dass das für Interrupt-Endpoints gilt, deswegen habe > ich auch ausdrücklich von Interrupt-Transfers gesprochen ;) > > Micro-Frames sind erstmal irrelevant, weil es hier nur um USB Full-Speed > und nicht um High-Speed geht. Hast du dir das Bild angesehen? Das stammt > direkt aus der USB-Spezifikation und zeigt, dass anscheinend 1216000 > byte/s statt 64000 bytes/s für USB Full-Speed Interrupt-Transfers > möglich sind. Die Applikation kann den Interrupttransfer schon so aufsetzen, dass pro Poll mehr als 64 Bytes übertragen werden (in einem URB). Ist nur unüblich. Interrupt und Bulk unterscheiden sich nur in der Art und Weise wie das Polling gehandhabt wird. Bulk: Wenn ein URB submitted wirdm wird der Transfer sofort eingeplant, Interrupt: Der Transfer wird erst nach Ablauf des Interrupt Polling Intervals eingeplant.
Lattice User schrieb: >>... Kleiner Nachtrag: Ein weiterer Unterschied besteht, wenn das Device den Transfer mit NAK ablehnt. Bulk: Sofort wiederholen, Interrupt: Erst beim nächsten Pollinginterval.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.