Hallo! Ich beschäftige mich seit ein paar Wochen näher mit USB. Als Ziel habe ich eine USB-Tastatur, einen USB-Speicherstick und einen HUB zu verwenden. Aber zuerst habe ich mal damit angefangen die USB-Geräte zu identifizieren die an den USB-Port angeschlossen werden. Bei ein paar Geräten klappt das bereits schon, dazu zählen ein USB-Hub und 2 Speichersticks. Folgende Probleme habe ich noch. 1. Gelegentlich kommt es vor, dass ein Gerät nicht auf ein Setup-Paket antwortet. 2. Ein USB-Tastatur bekomme ich überhaupt nicht ans laufen die antwortet überhaupt nicht auf USB-Pakete. 3. Bei 1 von 3 USB-Speichersticks bekomme ich an verschiedenen Stellen einen PIDCheckFailure. Bei den beiden funktionierenden Sticks handelt es sich um den selben Chip, mit lsusb -v auf Linux überprüft. Hardware kann ich ausschließen, ich benutze ein LPCxpresso1769 und das LPCxpresso BaseBoard. Prinzipiell muss zumindest die USB-Tastatur auch funktionieren, ich hatte mir mal die LPCUSBlib von lpcware.com heruntergeladen und kompiliert. Das Keyboardhost-Besipiel funktionierte, ob der Problemstick allerdings funktioniert weiß ich nicht da ich ihn nicht neu formatieren will um es zu testen. Ich möchte euch mal bitten über die Quelltexte zu schauen und mir zu sagen was ich an der Enumeration der USB-Geräte noch ändern muss, damit es auch bei den noch nicht funktionierenden USB-Geräten klappt. Ich habe 2 Archive beigefügt, das eine ist das USB-Host Projekt das andere die CMSIS und die LPC-Treiber Bibliothek. Die Libs benötigt man nur wenn man das Projekt kompilieren möchte, in der CMSIS hatte ich etwas verändert. ;-)
Die Tastatur ist vermutlich (als einzige?) ein Low-Speed-Device. Du verwendest Linux? Probier mal folgendes tail -f /var/log/syslog und steck die Tastatur dann mal ein. (siehe auch http://linuxindetails.wordpress.com/tag/lsusb/)
[code] Jan 7 07:09:19 marco-1 kernel: [ 2809.272021] usb 8-2: new low-speed USB device number 2 using uhci_hcd Jan 7 07:09:19 marco-1 mtp-probe: checking bus 8, device 2: "/sys/devices/pci0000:00/0000:00:1d.2/usb8/8-2" Jan 7 07:09:19 marco-1 kernel: [ 2809.584375] input: USB Keyboard as /devices/pci0000:00/0000:00:1d.2/usb8/8-2/8-2:1.0/input/input10 Jan 7 07:09:19 marco-1 kernel: [ 2809.584481] generic-usb 0003:04D9:1603.0006: input,hidraw3: USB HID v1.10 Keyboard [ USB Keyboard] on usb-0000:00:1d.2-2/input0 Jan 7 07:09:19 marco-1 mtp-probe: bus: 8, device: 2 was not an MTP device Jan 7 07:09:19 marco-1 kernel: [ 2809.677106] input: USB Keyboard as /devices/pci0000:00/0000:00:1d.2/usb8/8-2/8-2:1.1/input/input11 Jan 7 07:09:19 marco-1 kernel: [ 2809.677262] generic-usb 0003:04D9:1603.0007: input,hidraw4: USB HID v1.10 Device [ USB Keyboard] on usb-0000:00:1d.2-2/input1 [/usb] Ja ist als ein zigstes ein low-speed Device, gibt es da was zu beachten beim initialisieren?
M. K. schrieb: > Ja ist als ein zigstes ein low-speed Device, gibt es da was zu beachten > beim initialisieren? Google mal nach einer Spec. "OHCI" (Open Host Controller Interface). Darin gibt es eine Beschreibung für einen Endpoint Descriptor. Darin gibt es zumindest ein Bit Speed, welches full-speed (S=0) oder low-speed (S=1) bedeutet. Ein anderes Bit habe ich beim Überfliegen der Spec. nicht gefunden. OHCI arbeitet mit einer Menge an verketteten Liste, auf die der Host Controller (HC) dann losgelassen wird. Du hattest geschrieben, dass die Tastatur mit LPCUSBlib funktioniert. Hast Du mal vergleichen, was die anders machen wie Du?
Ich sehe gerade, Du bist bereits sehr tief in der OHCI-Spec. :-) File ohci.h Zeile 191: // 4.2.1 Endpoint Descriptor Format Seite 30 in OHCI-Spec bzw. direkt in Zeile 198: uint32_t S:1; //< Speed Vielleicht reicht es in ohci.c Zeile 267ff noch das Feld S auf 1 zu setzen, damit (nur !) low speed aktiv ist?
Martin Maurer schrieb: > Ich sehe gerade, Du bist bereits sehr tief in der OHCI-Spec. :-) Oha jaa. Martin Maurer schrieb: > Vielleicht reicht es in ohci.c Zeile 267ff > noch das Feld S auf 1 zu setzen, damit (nur !) low speed aktiv ist? So wie ich die OHCI-Spec verstehe setzt der HC mir das Bit je nachdem was er erkannt hat. Ich werde sobald etwas Zeit ist mir mal das Bit auf der Seriellen Schnittstelle ausgeben lassen, bzw. setzen. Fragt sich dann allerdings wie ich selbst erkennen kann das es sich um ein LS-Device handelt. Martin Maurer schrieb: > Du hattest geschrieben, dass die Tastatur mit LPCUSBlib > funktioniert. Hast Du mal vergleichen, was die anders machen > wie Du? Ja ich habe es zumindest versucht, die NXPLib ist riesig. Die Enumeration meine ich gefunden zu haben, bei NXP wurde die komplette Enumeration in eine State-Machine gepackt. Ich kann gleich mal die Datei bzw Abschnitt hochladen. (sitze gerade an einem anderen Rechner) Einen Unterschied konnte ich auch erkennen, den habe ich auch in meinen Quelltexten dokumentiert. In der NXPLib wir an einer Stelle die VUSB ab-/eingeschaltet, die Pins die dafür am Prozessor vorgesehen wurden, sind an den beiden LPCxpresso-Boards nicht angeschlossen. Bei dem BaseBoard wird der USB-Port direkt aus der Spannungsversorgung gespeist.
Der Tip mit dem LowSpeed-Device war sehr gut. Erkennung von LowSpeed-Devices geht über HcRh->PortStatus[0].LSDA, man kann also für jeden Port erkennen ob ein LowSpeed-Device angeschlossen wurde. Dann muss im Endpoint-Descriptor das Flag S auf 1 gesetzt werden, so wie Martin Maurer es vorgeschlagen hat. Der Descriptor den ich aus gelesen habe ist zwar Schrott (siehe Anhang) aber da weiß ich wo ich dran drehen muss. Für die anderen Probleme kommt mir auch gerade eine Idee. Ich verwende für die komplette Kommunikation nur einen Buffer (TDBuffer) den caste ich beim zusammenstellen des Setup-Tokens um.
1 | // Setup-Packet zusammenstellen. |
2 | ((SETUP *)TDBuffer)->rescipient = recipient; |
3 | ((SETUP *)TDBuffer)->type = type; |
4 | ((SETUP *)TDBuffer)->direction = direction; |
5 | ((SETUP *)TDBuffer)->request = bRequest; |
6 | ((SETUP *)TDBuffer)->value = wValue; |
7 | ((SETUP *)TDBuffer)->index = wIndex; |
8 | ((SETUP *)TDBuffer)->length = wLength; |
Ich beschreibe zwar die kompletten 8 Bytes, kann es aber evtl. trotzdem sein das noch Bits aus dem vorherigen Paket dazwischen sind? Edit: Ich habe noch die Enumeration der NXPUSBlib angehangen.
Da passt etwas beim Parsen nicht: <\r><\n> Endpoint Descriptor 1<\r><\n> bLength: 0x09<\r><\n> bDescriptorType: 0x21<\r><\n> bEndpointAddress: 0x10<\r><\n> bmAttributes: 0x01<\r><\n> wMaxPacketSize: 0x0100<\r><\n> bInterval: 0x22<\r><\n> <\r><\n> Der Endpoint Descriptor hat (hier) eine Länge 9, es werden aber nur 7 Bytes ausgewertet/ausgegeben. Dann verschieben sich die anderen Descriptoren dann um die 2 Bytes.
Ja die Länge werte ich noch gar nicht aus, ich bin davon ausgegangen das nach dem Configuration-Descriptor nur Interface und Endpoint-Descriptoren folgen und springe daher immer nur 7 Bytes weiter Martin Maurer schrieb: > bDescriptorType: 0x21<\r><\n> Ist aber sicher kein Endpoint-Descriptor, evtl. der HID-Descriptor?
HID-Spec Seite 22
1 | Part Offset/Size Description |
2 | (Bytes) |
3 | ------------------------------------------------- |
4 | bLength 0/1 Numeric expression that is the total size of the HID descriptor. |
5 | bDescriptorType 1/1 Constant name specifying type of HID descriptor. |
6 | bcdHID 2/2 Numeric expression identifying the HID Class Specification release. |
7 | bCountryCode 4/1 Numeric expression identifying country code of the localized hardware. |
8 | bNumDescriptors 5/1 Numeric expression specifying the number of class descriptors (always at least one i.e. Report descriptor.) |
9 | bDescriptorType 6/1 Constant name identifying type of class descriptor. See Section 7.1.2: Set_Descriptor Request for a table of class descriptor constants. |
10 | wDescriptorLength 7/2 Numeric expression that is the total size of the Report descriptor. |
11 | [bDescriptorType]... 9/1 Constant name specifying type of optional descriptor. |
12 | [wDescriptorLength]... 10/2 Numeric expression that is the total size of the optional descriptor. |
HID-Spec Seite 49
1 | Value Class Descriptor Types |
2 | ----------------------------------- |
3 | 0x21 HID |
4 | 0x22 Report |
5 | 0x23 Physical descriptor |
6 | 0x24 - 0x2F Reserved |
Steck die Tastatur nochmal an deinen Linux-Rechner und lass Dir mit lsusb -v die Deskriptoren der Tastatur ausgeben. Dann kannst du vergleichen, ob die Inhalte passen oder ab welcher Stelle sie nicht mehr passen. HID-Spec Seite 49 Value Class Descriptor Types ----------------------------------- 0x21 HID hört sich nicht schlecht an
PS: Könntest Du mir den Descriptor in der Form 09 02 6D 00 02 01 00 A0 32... ausgeben? Ich habe vor langer Zeit mal ein Programm geschrieben, ähnlich wie "lsusb -v" und würde deinen Descriptor dort gerne mal einfüttern.
Ich habe das auslesen der Descriptoren jetzt mal angepasst. Das auslesen klappt ziemlich gut, bei meinen USB-Sticks wird der 2. Endpoint allerdings nicht richtig interpretiert. Hier mal der angepasst Code der den Config-Descriptor komplett ausliest.
1 | // Alle Interface und Endpoint-Descritoren einlesen.
|
2 | descIndex = c; descLength = DeviceListTail->ConfigureList[c].Descriptor.wTotalLength; |
3 | rc = ControlTransfer(DEVICE_TO_HOST, REQUEST_TYPE_STANDARD, RECIPIENT_DEVICE, GET_DESCRIPTOR, (CONFIGURATION_DESCRIPTOR << 8) | (descIndex), 0, descLength, TDBuffer); |
4 | if (rc != OK) { |
5 | printf("ERROR: In %s at Line %u - rc = %li\r\n", __FUNCTION__, __LINE__, rc); |
6 | releaseAddress(address); |
7 | return (rc); |
8 | }
|
9 | for (x = 0; x < DeviceListTail->ConfigureList[c].Descriptor.wTotalLength; x++) { printf("%02x ", TDBuffer[x]); } |
10 | printf("\r\n"); |
11 | |
12 | DeviceListTail->ConfigureList[c].InterfaceList = (USBInterface_t *)malloc(sizeof(USBInterface_t) * DeviceListTail->ConfigureList[c].Descriptor.bNumInterfaces); |
13 | for(i = 0, offset = 9; i < DeviceListTail->ConfigureList[c].Descriptor.bNumInterfaces; i++) { |
14 | if (TDBuffer[offset + 1] == INTERFACE_DESCRIPTOR) { |
15 | memcpy(&(DeviceListTail->ConfigureList[c].InterfaceList[i].Descriptor), (const void *)&(TDBuffer[offset]), 9); |
16 | offset += 9; |
17 | DeviceListTail->ConfigureList[c].InterfaceList[i].EndpointList = (struct EndpointDescr *)malloc(sizeof(struct EndpointDescr) * DeviceListHead.ConfigureList[c].InterfaceList[i].Descriptor.bNumEndpoints); |
18 | for(e = 0; e < DeviceListTail->ConfigureList[c].InterfaceList[i].Descriptor.bNumEndpoints; e++) { |
19 | if (TDBuffer[offset + 1] == ENDPOINT_DESCRIPTOR) { |
20 | memcpy(&(DeviceListTail->ConfigureList[c].InterfaceList[i].EndpointList[e]), (const void *)&(TDBuffer[offset]), 7); |
21 | offset += 7; |
22 | } else { |
23 | printf("Descriptor type = 0x%02x, laenge = %i\r\n", TDBuffer[offset + 1], TDBuffer[offset]); |
24 | offset += TDBuffer[offset]; |
25 | e--; |
26 | }
|
27 | }
|
28 | } else { |
29 | printf("Descriptor type = 0x%02x, laenge = %i\r\n", TDBuffer[offset + 1], TDBuffer[offset]); |
30 | offset += TDBuffer[offset]; |
31 | i--; |
32 | }
|
33 | }
|
34 | }
|
Der 3. USB-Stick macht noch immer Probleme ich habe mal ein Fehler-Log und passenden Quelltext an gehangen.gehangenen Quelltext.
Das Problem mit dem auslesen der Endpoint-Descriptoren ist nun auch behoben. Die Probleme bei der Enumeration habe ich zwar immer noch, bei den Geräten die mich momentan interessieren funktionieren dies aber fast immer auf Anhieb. Momentan beschäftige ich mich mit der USB-Tastatur. Den Report für die Tasten kann ich auch schon per Control-Transfer pollen und auch das schalten der LEDs funktioniert. Nun möchte ich aber die Tasten per Interrupt-Transfer abfragen, hier habe ich nun ein paar Fragen. Bei einem Control-Transfer habe ich ein Setup-Paket, Daten-Paket und ein Handshake-Paket laut [1][2] besteht ein Interrupt-Transfer nur aus einem Daten-Paket und einem Handshake-Paket? Muss ich nun 2 TDs aneinander hängen und diese dann an einen ED hängen? Wie sage ich dem Gerät dann was ich von ihm möchte? Wie bekomme ich den OHCI-HostControler dazu den ED abzuarbeiten? Bekomme ich auch einen WritebackDone Interrupt wenn der ED abgearbeitet wurde? Ihr seht eine ganze menge Fragen, hoffentlich hat jemand Antworten! Meinen aktueller Versuch befindet sich im Anhang. [1] http://www.usbmadesimple.co.uk/ums_3.htm [2] http://www.beyondlogic.org/usbnutshell/usb4.shtml#Interrupt
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.