Forum: Mikrocontroller und Digitale Elektronik USB-Host LPC1769


von M. K. (avr-frickler) Benutzerseite


Angehängte Dateien:

Lesenswert?

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. ;-)

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Kennt sich denn keiner mit USB aus und kann mir helfen?

von Martin M. (capiman)


Lesenswert?

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/)

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

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

von Martin M. (capiman)


Lesenswert?

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?

von Martin M. (capiman)


Lesenswert?

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?

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

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.

von M. K. (avr-frickler) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von Martin M. (capiman)


Lesenswert?

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.

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

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?

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

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

von Martin M. (capiman)


Lesenswert?

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

von Martin M. (capiman)


Lesenswert?

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.

von M. K. (avr-frickler) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von M. K. (avr-frickler) Benutzerseite


Angehängte Dateien:

Lesenswert?

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
Noch kein Account? Hier anmelden.