Hallo. Ich möchte ein Messgerät mit dem PC per USB verbinden. Mikrocontroller: STM32F767, USB Core von ST, WinUSB Umsetzung angelehnt an http://searchingforbit.blogspot.de/2014/05/winusb-communication-with-stm32-round-2.html PC seitig verwende ich WinUSB.Net. https://github.com/madwizard-thomas/winusbnet Auf meinem Rechner hat die Kommunikation super funktioniert (Announcements per Control Transfer, Datentransfer über Bulk In/Out Pipe). Auf einem anderen Rechner auch, beide Windows 10 und USB 2.0 Anschlüsse. (Gerät ist USB 2.0 High Speed) Auf neueren Rechnern mit USB3.0 Anschlüssen funktioniert es nicht. (Auch mit USB 2.0 Hub nicht) Es lässt sich runterbrechen, dass Readpipe nach einer handvoll Aufrufen keine Daten liefert sondern hängen bleibt bzw. in Timeout geht wenn eingestellt. Wenn ich in einer while-Schleife direkt danach wieder abfrage, geht es immer wieder schief. Wenn ich kurz warte und per Hand nochmal abrufe, klappt es. Ich habe es auch schon im RAW-Modus probiert, keine Veränderung. Hat jemand eine Idee was da schief geht? Ich weiß ja noch nichtmal so genau ob das Problem im Mikrocontrollercode liegt oder PC seitig, wobei ich eher die PC-Seite in Verdacht habe, weil mikrocontrollerseitig alles soweit in Ordnung aussieht dass die Daten im Sende-FIFO bereit liegen aber einfach nicht abgeholt werden in dem Fall wo es schief geht.
:
Verschoben durch User
Exakt die gleiche Windows-Version? OS schrieb: > Wenn ich kurz warte und per Hand nochmal abrufe, klappt es. Was heißt "per Hand"? Hast du das Gerät zwischendurch neu geöffnet?
Zugegeben, die Rechner wo es funktioniert sind Windows 10 1511 und 1607, einer wo es nicht geht ist 1703 und der andere da komme ich grad nicht ran. per Hand heißt einfach nur über einen Button ReadPipe nochmal gestartet. Es scheint so dass der USB Stack im Windows durcheinander kommt und nach dem Timeout einen Moment braucht sich zu erholen. Wenn ich zu schnell Readpipe starte klappt es wieder nicht.
der 2. Rechner wo es nicht funktioniert ist Windows 10 Version 10240, also ganz alt. Aber eben auch USB 3 Anschlüssen und xhci Host Controller
OS schrieb: > Es lässt sich runterbrechen, dass Readpipe nach einer handvoll Aufrufen > keine Daten liefert sondern hängen bleibt bzw. in Timeout geht wenn > eingestellt. Wenn ich in einer while-Schleife direkt danach wieder > abfrage, geht es immer wieder schief. Wenn ich kurz warte und per Hand > nochmal abrufe, klappt es. Häng doch mal Deinen Source Code an. Eventuell sind Timeouts o.ä. zu kurz geraten.
Ich glaube im Code gibt es nicht viel spannendes zu sehen: Initialisierung
1 | m_oUSBDevice = USBDevice.GetSingleDevice(GUID); |
2 | m_oUSBDevice.Interfaces[0].InPipe.Policy.PipeTransferTimeout = 200; // problem tritt genauso mit 5000 oder ganz ohne Timeout auf |
Daten abholen
1 | byte[] data = new byte[25500]; |
2 | int len2 = 0; |
3 | while (len2 == 0) |
4 | {
|
5 | try
|
6 | {
|
7 | len2 = m_oUSBDevice.Interfaces[0].InPipe.Read(data); |
8 | }
|
9 | catch (Exception e) |
10 | {
|
11 | }
|
12 | |
13 | Console.WriteLine("Received " + len2.ToString() + " Bytes"); |
14 | }
|
Wie gesagt steht dann immer "Received 0 Bytes" da. Wenn ich am Ende der while Schleife 100ms warte, werden die Daten dann im 2. Durchlauf korrekt abgeholt. Das ist aber keine Lösung weil ich so nicht die benötigte Datenrate schaffe wenn ich andauernd 100ms warten muss Auf den älteren Rechnern kommt InPipe.Read halt nicht in den Timeout.
Ich hatte dort schon mehr drin stehen. Es kommt dort im Fehlerfall immer dieselbe Exception - Semaphore timeout. Siehe auch (return values..): https://msdn.microsoft.com/en-us/library/windows/hardware/ff540297(v=vs.85).aspx Das ist also ein ganz normaler Fehler weil das Timeout kommt (welches ich selber gesetzt habe). Die Exception wird von WinUSB.Net selbst geworfen auf niedrigerer Ebene, wo der API32 Call return value ausgewertet wird. Ich habe mir auch eine Kopie dieser Funktion gemacht die diese Exception gar nicht erst wirft. Ich sehe das Verhalten auch wenn ich mit einem (SW-) USB Sniffer mitschneide, sobald das Timeout greift bekomme ich 0x0 Bytes zurückgeliefert.
OS schrieb: > Es kommt dort im Fehlerfall immer > dieselbe Exception - Semaphore timeout. > Siehe auch (return values..): > https://msdn.microsoft.com/en-us/library/windows/hardware/ff540297(v=vs.85).aspx > Das ist also ein ganz normaler Fehler weil das Timeout kommt (welches > ich selber gesetzt habe) Das ist kein wirklicher Fehler, sondern normales Verhalten wenn "nix" gesendet wurde. Außerdem würde ich mal nachschauen ob da nicht zufällig ein Vielfaches von MaxPacketSize (im EP Deskriptor) gesendet wurde: Dann gibt der USB Host Treiber nämlich nix aus, siehe USB 2.0 Spec Kapitel 5.8.3 "Bulk Transfer Packet Size Constraints". Entsprechendes Handling (z.B. zusätzliches Zero Packet) musste ich bisher immer selber einbauen.
Das ist schon richtig, dass das Timeout normal wäre, wenn ich nichts senden würde. Aber im Mikrocontroller liegen 200 Byte zum abholen. Der nächste InPipe.Read Befehl liefert dann auch die Daten, wenn ich mindestens 100ms nach Timeout warte. MaxPacketSize habe ich auf 0xFF, das sollte mit 200 Bytes Nutzdaten also kein Problem sein. Ich sehe im Mikrocontroller im SendeFIFO ja auch, dass der PC (bzw. der Hostcontroller) die Daten überhaupt nicht abholt im Fehlerfall. Mikrocontrollerseitig weiß ich auch nicht wo ich noch schauen könnte, ich habe die Daten ja quasi schon an den Hardwareteil übergeben. Könnte es vielleicht was damit zu tun haben dass ich im DeviceDescriptor bcdUSB auf 2.00 gesetzt habe? Der STM USB Stack unterstützt theoretisch auch LPM und damit USB 2.01 wenn das entsprechende define gesetzt ist. Das habe ich aber bisher noch nicht probiert weil ich dann eher noch mehr Probleme erwarte
Setzt du denn auf der uC Seite auch das PacketEnd wenn du nur 200Byte zu liefern hast? Wenn du weniger als die Endpoint Größe hast musst du das setzen. Wir setzen WinUSB erfolgreich seit Jahren ein, mit Cypress Controllern.
Ich nutze auf Mikrocontrollerseite die Funktion USBD_LL_Transmit des ST USB Stacks. Da gibt es wenig Doku darüber. Wenn ich in den Code reinschaue, wird wiederum HAL_PCD_EP_Transmit aufgerufen. Darin werden Datenpointer und Länge im Endpoint vermerkt, dann USB_EPStartXfer aufgerufen. Darin: - setzen der Transfergröße und Paketanzahl im DIEPTSIZ Register - TX FIFO Empty Interrupt aktivieren im DIEPEMPMSK Register - Clear NAK und setze EndointEnable im DIEPCTL Register Im Tx FIFO Empty Interrupt werden dann die Daten entsprechend in den Tx FIFO kopiert. Um den Rest kümmert sich dann der (HW-)Core. Wenn der PC die Daten korrekt abgeholt hat, erkenne ich das darin, dass der Endpoint nicht mehr enabled ist und der FIFO wieder leer ist Ich weiß nicht ob ich noch irgendwo PacketEnd setzen kann/muss. Ich finde dazu nichts im Reference Manual zum STM32F7, nichts im STM32Cube USB Device Library Manual (dort werden eh nur die typischen sachen MSD, CDC, HID etc. erklärt), nichts im Code. Ich denke das macht der Core automatisch. Auch wenn ich mir die CDC-Klasse von ST angucke, da wird auch einfach nur USBD_LL_Transmit genutzt.
Stelle doch mal testweise Pakete mit exakt der Paketlänge bereit die im zugehörigen Endpoint Descriptor angegeben ist. Klappt das?
Der Fehler tritt genauso auf. Ich habe aber gerade mal noch etwas versucht. Weiter oben kam ja der Hinweis mit den USB Specs. Ich habe nochmal genau nachgelesen: "All Host Controllers are required to have support for 8-, 16-, 32-, and 64-byte maximum packet sizes for full-speed bulk endpoints and 512 bytes for high-speed bulk endpoints. No Host Controller is required to support larger or smaller maximum packet sizes" Man kann das also so deuten, dass für USB HS nur 512 Bytes zugelassen sind als maximum packet size. An anderen Stellen (USB in a Nutshell) steht nur was von maximal 512 (nicht GENAU 512). Ich habe mal umgebaut auf 512 und jetzt scheint es an einem Rechner zu gehen, an anderen Rechnern muss ich erstmal testen.
Ja die maximale Packet Size sollte man tunlichst auf 512 Byte bei HighSpeed und 64 Byte bei FullSpeed setzen. Beim Cypress kann man auch 1024 einstellen, das bringt etwas mehr Speed aber läuft nicht überall. Wie viel man dann pro Transfer wirklich überträgt ist ja davon unabhängig. Denk aber dran dass pro abgeschlossenem Paket ein gesamter Microframe weg ist, wenn du viel Geschwindigkeit schaffen willst, musst du immer gleich große Brocken anfordern.
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.