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?
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.
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.
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