Forum: Mikrocontroller und Digitale Elektronik USB Enumeration


von Potter S. (potter68)


Lesenswert?

Hallo,

ich arbeite mich grade in den USB ein. Dazu verwende ich den PDIUSBD12 
und Mega8. Die ersten Schritte der Enumeration macht der D12 bereits:

BusReset
GetDescriptor
BusReset
SetAddress

Soweit sollte eigentlich alles stimmen. Aber danach macht mein D12 
wieder ein BusReset anstatt mit der neuen Adresse den Deskriptor 
anzufordern. Hat einer eine Idee was da los ist? Kann ja eigentlich nur 
am Deskriptor selber liegen oder?

Außerdem ist das eine Qual mit dem Debuggen. Ich sende mir die Daten 
über RS232 an den PC und schau sie mir dann da an. Aber irgendwie kommt 
da nicht immer alles an. Wie debuggt ihr eigentlich? Über LCD?

Gruß Ralf

von Stefan Salewski (Gast)


Lesenswert?

Welches Betriebssystem?
Schreibst Du den Enumeration-Code selbst,
oder benutzt Du fremden Code?

Gruß

Stefan Salewski

von Potter S. (potter68)


Lesenswert?

Hallo Stefan,

ich nutze Windows 2000. Der Code läuft auf dem ATmega8 von Atmel und 
steuert einen PDIUSBD12.

Die Software orientiert sich an dem Buch von J. Axelson bzw. dem Code 
von BeyondLogic.org (USB in a Nutshell) für einen PDIUSBD11. Bislang bin 
ich noch dabei die Firmware des Mikrocontrollers zum Laufen zu bringen.

Unter Windows habe ich noch nichts programmiert. Soweit ich weiss 
kümmert sich der Host standardmäßig selber um die Kommunikation mit den 
Geräten - jedenfalls bis zur erfolgreichen Enumeration. Und genau da 
haperts.

Gruß Ralf

von Thomas (Gast)


Lesenswert?

Das ist das std. Verhalten wenn dein D12 gar nichts sendet.
Win probiert dann alles mögliche um das Device doch noch irgendwie 
anzusprechen. Vermutlich geht schon dein erster GetDeskriptor(Device) 
nicht.
Poste doch mal deinen Code.

Thomas

von Tom T. (tomtorres)


Lesenswert?

hi,
wärs möglich das du mir dein code schicken kannst? weil ich 
experementiere auch mit dem PDIUSBD12 und hab extreme problem den 
irgendwie zum laufen zu bekommen, das er überhaupt irgend etwas macht
MFG
Tom

von Ralf Handrich (Gast)


Lesenswert?

Ich weiss leider nicht, wie ich hier Code hochladen kann (vlt. kann mir 
das ja jemand sagen), deshalb habe ich die Dateien auf meiner Seite 
hochgeladen: http://rahand.oyla12.de. Hier dann bitte unter 'Downloads' 
nachschauen. Ein Debug-Protokoll mit Anmerkungen von mir ist auch dabei. 
Die Dateien sind z.T. im .doc-Format. Das liegt an meinem Provider.

Gruß Ralf

von Stefan Salewski (Gast)


Lesenswert?

>Soweit ich weiss
>kümmert sich der Host standardmäßig selber um die Kommunikation mit den
>Geräten - jedenfalls bis zur erfolgreichen Enumeration.

Ich kenne den PDIUSBD12 zwar nicht so genau, aber er ist doch wohl dem 
USBN9604 sehr ähnlich, den Benedikt Sauter für sein usbn2mc-Projekt 
eingesetzt hat. Bei dem USBN9604 und bei dem von mir verwendeten AT90USB 
geht praktisch nichts automatisch. Nach dem ersten Bus-Reset muss das 
Device gleich den Device-Descriptor schicken, dann kommt ein weiterer 
Bus-Reset und dann geht es munter weiter mit dem Senden der Descriptors.

Wenn man da Unsinn oder gar nichts sendet macht der Host wieder einen 
Reset.

Ich arbeite aber nur unter Linux, aber bei Windows ist das wohl ähnlich.
USB Complete habe ich auch, ich finde aber das Buch von H.J.Kelm etwas 
übersichtlicher.

Warum hast Du Dich gerade für den PDIUSBD12 entschieden?

Kennst Du das Projekt von B. Sauter? Der hat mit dem USBN9604 ja schon 
sehr viel gemacht, teilweise auch unter Windows.

Und mein Projekt mit dem AT90USB funktioniert (unter Linux) auch schon 
ganz gut, die Dokumentation ist nun auch fast fertig.

Ach ja, Du hattest nach Debugging gefragt: Das mache ich auch über die 
serielle Schnittstelle. Auf meiner Platine habe ich einen Max232, und 
ich sende Debuggingausgaben dann an ein Terminalprogramm (minicon). Geht 
wunderbar. Beispiel Enumeration. Ich gebe den Standard-Request aus (8 
Byte) der vom Host gesendet wird, und dann den Descriptor, den meine 
Firmware als Antwort sendet. So sieht man sofort, wenn etwas aufgrund 
eines Programmierfehlers schief läuft.

Gruß

Stefan Salewski

von Thomas (Gast)


Lesenswert?

es ist eine schlechte idee 16bit Werte direkt in die Deskriptoren 
einzutragen. Je nach Compiler und Proz geht das schief.
sizeof() funktioniert auch nicht immer.
Diese Teile musst du in jedem Fall anhand des LST files prüfen.

Thomas

von Potter S. (potter68)


Lesenswert?

@ Stefan: Das mit dem 'automatisch' war nicht so gemeint, dass ich den 
Controller anstöpsel und das wars dann. Es ist mir schon klar, dass In- 
und Out-Requests zu beantworten sind. Was ich meinte war, dass ich 
PC-seitig noch nichts programmiert habe. Bis zum Ende der Enumeration 
sollte dies meines Wissens auch nicht notwendig sein.

@ Thomas: Das mit den 8- und 16-Bit-Werten muß ich mir im Einzelnen mal 
genau anschaun. Was mich nur wundert ist, dass laut meinem Protokoll der 
PC meinem Controller eine ID zuweißt. Und nach dem Setzen derselbigen 
wieder ein Reset kommt.

Wenn ich also eine ID vom PC erhalte dann kann doch bis dahin nicht viel 
falsch sein, sonst würde er doch keine ID senden? Und sobald ich dann 
die ID setze kann doch kein Reset kommen, sondern dann folgt doch 
erstmal wieder das Einlesen der Deskriptoren, oder?

Gruß Ralf

von René K. (king)


Lesenswert?

Schuß ins Blaue: Du darfst die zugewiesene Adresse nicht zu früh 
aktivieren. Die Status-Stage für den SET_ADDRESS Request muß noch auf 
Adresse 0 erfolgen. Erst nach Beendigung der Status-Stage darfst Du die 
Adresse aktivieren. Hast Du das bedacht?

von Stefan Salewski (Gast)


Lesenswert?

>Wenn ich also eine ID vom PC erhalte dann kann doch bis dahin nicht viel
>falsch sein, sonst würde er doch keine ID senden? Und sobald ich dann
>die ID setze kann doch kein Reset kommen, sondern dann folgt doch
>erstmal wieder das Einlesen der Deskriptoren, oder?

Mit ID meinst du die neue Device-Adresse?
Wenn Du die erhälst ist das schon mal gut.

Ist Dir bewußt, dass du bestätigen musst, dass Du die neue Adresse 
erhalten hast, und dass Du erst nachdem  dieses Bestätigungs-Handshake 
beendet ist die neue Adresse für Dein Gerät setzen darfst?

von Thomas (Gast)


Lesenswert?

nein eine Device Addresse erhalten erst mal auch kaputte Geräte.
Win wird die jedem Gerät erst mal zuzuweisen.
Der Grund für dieses Verhalten liegt farin begründet, das zu Anfang oft 
kaputte Geräte am Markt waren. MS versuchte eben auch diese zu 
enumerieren.
Erst wenn das Device auf der neuen Adresse nicht antwortet kommt der 
nächste Busreset und das ganze beginnt von vorne.
Nach 3 Mal ist dann Schluss.

Also nochmal:
1. die Deskriptoren sind im off
2. D12 sendet nichts
3. Die Status Stage für SetAddress ist falsch (Spec genau lesen!)

Der erste GetDescriptor(Device) Request kommt mit wLenght 64! Der D12 
hat glaube ich im ControlEP nur 8 oder 16 bytes Fifo. Auch wenn der Host 
64 Bytes anfragt darf in der Data Stage nur max Fif0 Size bytes auf 
einmal gesendet werden.


Thomas

von ----- (Gast)


Lesenswert?

Ich habe diese Ding mal zum laufen gebracht. Leider funktionierte die 
Initialisiereung nur unter Linux 2.4, später unter Windows oder Linux 
2.6 nicht mehr. Wieso es nur unter Linux 2.4 funktionierte habe ich 
nicht weiter untersucht.

Setzen der Adresse:

// Adresse setzen
usbWriteCommand(0xD0); // Set Address/Enable
usbWriteData(Address | 0x80); // Adresse setzen

// Packet mit der Länge 0 senden
usbWriteCommand(0x01); // Endpoint wählen
usbWriteCommand(0xF0); // Write
usbWriteData(0); // Reserve
usbWriteData(0); // Length
usbWriteCommand(0xFA); // Validate

von Stefan Salewski (Gast)


Lesenswert?

>Ich habe diese Ding mal zum laufen gebracht.

Für mich sieht das gerade falsch herum aus.
Wie  René König ein paar Sekunden vor mir schrieb:

Die Status-Stage für den SET_ADDRESS Request muß noch auf
Adresse 0 erfolgen. Erst nach Beendigung der Status-Stage darfst Du die
Adresse aktivieren.

von Potter S. (potter68)


Lesenswert?

Hallo,

es ist bei mir exakt so, wie Thomas sagt:

1. Setup-Token: es werden 64 Bytes angefragt -> gesendet werden 8.
2. In-Token: Es werden 10 Bytes angefragt (8+10 = 18 Größe des 
kompletten Deskriptors) -> gesendet werden 8.
3. Nun erfolgt der Reset.
4. Setup-Token: SetAddress wird angefordert -> ich schreibe Null-Byte 
und setze Flag.
5. In-Token: Da nun die Flag gesetzt ist -> zugewiesene Adresse setzen.

Ab nun sollte er eigentlich über die neue Adresse den Deskriptor wieder 
anfragen (falls ich das richtig verstanden habe). Stattdessen kommt ein 
Reset und alles fängt von vorne an. Nach 3 mal ist Schluß.

Im übrigen frage ich immer den LastTransactionStatus ab. Und der zeigt 
mir an, das die Packete immer angekommen sind ... mit einer Ausnahme: 
Bei dem In-Token unter Punkt 2 (der erste In-Token nach einem Reset) 
bekomme ich den Status, daß nichts angekommen ist. Aber ich denke, da es 
der erste In-Token ist, kann ja zuvor auch garnichts empfangen worden 
sein. Der Status (nichts empfangen) ist also richtig in dem Fall.

Naja wie gesagt, das wird dann 3 mal durchlaufen und dann ist Schluß.

Also ich werde jetzt, wie Thomas vorschlägt, nochmal die Spezifikation 
durchlesen. Falls jemand einen konkreten Vorschlag hat, um etwas 
gezielter nach dem Fehler zu suchen, dann immer her damit.

Schönes Wochende, Gruß Ralf

von Potter S. (potter68)


Lesenswert?

Ich hab mir jetzt alles noch einmal angesehn und finde einfach keinen 
Fehler. Der Deskriptor ist ok. Die unsigned short Werte werden 
[LOW][HIGH]-Byte geschrieben.

Wie ich allerdings feststellen soll, ob der D12 überhaupt etwas sendet 
ist mir schleierhaft. Die gelesenen Daten vom Host sind richtig. Nach 
dem Schreiben der ersten 8 Bytes des Deskriptors erhalte ich einen 
IN-Token. Die 8 Bytes werden also an den Host gesendet. Danach erfolgt 
ein Reset, was laut Spezifikation auch richtig ist. Wie soll ich nun 
feststellen, ob der Host tatsächlich die 8 Bytes gelesen hat oder ob er 
nur Schema-F durchläuft? Beim auslesen der 
LastTransactionStatus-Register werden auch keine Fehler angezeigt. Also 
ist die Übertragung erfolgreich abgeschlossen worden.

Hat jemand noch eine Idee?

Gruß Ralf


von Stefan Salewski (Gast)


Lesenswert?

>Hat jemand noch eine Idee?

USB ist eben nicht ganz einfach -- ich musste in den vergangenen
Monaten auch manchmal kämpfen. Insbesondere bei Fehlern oder
Ungenauigkeiten im Datenblatt wird es unangenehm.

Aber meine freie USB-Firmware für den AT90USB ist jetzt inklusive 
Beispielprogramm und etwas Dokumentation online.

Falls Du mit dem PDIUSBD12 nicht weiter kommst wäre das vielleicht eine
Alternative.

Beitrag "Freie USB-Firmware für AT90USB verfügbar"
http://www.ssalewski.de/Misc.html.de

Gruß

Stefan Salewski

von Thomas (Gast)


Lesenswert?

ich suche heute abend mal meine Implementation raus.
Vieleicht bringt das ja was.
sizeof() hast du überprüft?

Wenn ich mich richtig errinnere ist da was beim SetAddress() was beim 
D12 anders funktioniert als normal.

Thomas

von Potter S. (potter68)


Lesenswert?

Danke für Deine Links Stefan, aber noch bin ich mit dem D12 nicht 
fertig.

Thomas, ist echt nett von Dir. Du kannst mir das Ganze auch gerne per 
eMail schicken: ralf.handrich@gmx.de.

Hier nochmal das neueste Debug-Protokoll:

Initialization
----------------
SetAddressEnable = 80                         // Resets und Suspend 
Change
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B
ReadInterruptRegister = 40 , 00
SetAddressEnable = 80
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B

ReadInterruptRegister = 80 , 00
SetEndpointStatus (ep, status)= 00 , 00
SetEndpointStatus (ep, status)= 01 , 00

ReadInterruptRegister = C0 , 00
SetAddressEnable = 80
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B
SetEndpointStatus (ep, status)= 00 , 00
SetEndpointStatus (ep, status)= 01 , 00

ReadInterruptRegister = 80 , 00
SetEndpointStatus (ep, status)= 00 , 00
SetEndpointStatus (ep, status)= 01 , 00

ReadInterruptRegister = C0 , 00
SetAddressEnable = 80
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B
SetEndpointStatus (ep, status)= 00 , 00
SetEndpointStatus (ep, status)= 01 , 00
                                             // HIER GEHTS LOS
ReadInterruptRegister = 01 , 00              // SETUP-TOKEN
ProcessIRQ_EP0OUT
ReadLastTransactionStatus = 21
- SetupPacket -
ReadEndpoint = 80 06 00 01 00 00 40 00
AcknowledgeEndpoint = 00
AcknowledgeEndpoint = 01
GetDescriptor
Write2Endpoint = 12 01 00 02 00 00 00 08

ReadInterruptRegister = 03 , 00              // IN-TOKEN + OUT-TOKEN ?
ProcessIRQ_EP0IN
ReadLastTransactionStatus = 00               // DATA0 - warum?
PROGRESS_IDLE
Write2Endpoint = 25 09 34 12 00 01 01 00
ProcessIRQ_EP0OUT
ReadLastTransactionStatus = 00
- Out-Token -                                // OUT-TOKEN - warum?
nBytes = 00

ReadInterruptRegister = 40 , 00              // RESET
SetAddressEnable = 80
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B

ReadInterruptRegister = 01 , 00              // SETUP-TOKEN mit Adresse
ProcessIRQ_EP0OUT
ReadLastTransactionStatus = 21
- SetupPacket -
ReadEndpoint = 00 05 03 00 00 00 00 00       // Die Adresse
AcknowledgeEndpoint = 00
AcknowledgeEndpoint = 01
Write2Endpoint =

ReadInterruptRegister = 02 , 00              // IN-TOKEN:
                                             // neue Adresse setzen
ProcessIRQ_EP0IN
ReadLastTransactionStatus = 41
PROGRESS_ADDRESS
SetAddressEnable = 83

ReadInterruptRegister = 40 , 00               // Reset und von vorne, 
weil
                                              // irgendwo ein Fehler war
SetAddressEnable = 80
SetEndpointEnable = 01
SetMode (config,clock) = 16 , 0B

Nach dem GetDescriptor() erhalte ich einen Interrupt mit IN- und 
OUT-Token. Das ist schon sehr komisch. Ich nehme mal an, daß da der 
Fehler liegt. Was ja Thomas auch schon vermutet hat. Ich frage mich nur, 
was an meinem Code falsch sein soll: 8 Bytes werden gelesen - 
Acknowledge geht raus - die ersten 8 Bytes des Deskriptors werden 
geschrieben.

von Potter S. (potter68)


Lesenswert?

Das sizeof() liefert den richtigen Wert (0x12).

von Potter S. (potter68)


Lesenswert?

Ich habe den Fehler gefunden. Das Setzen der Adresse muß direkt nach 
Erhalt der Selbigen erfolgen und nicht erst beim Eintreffen des nächsten 
In-Tokens, wie das bei 'USB in a Nutshell' beschrieben wird. Allerdings 
arbeiten die auch mit einem D11.

Danke an Alle, die mir geholfen haben.

Gruß Ralf

von Stefan Salewski (Gast)


Lesenswert?

>Das Setzen der Adresse muß direkt nach Erhalt der Selbigen erfolgen

Das ist erstaunlich -- nach USB-Spezifikation soll, wie weiter oben von 
einigen anderen auch erwähnt, die Transaktion mit Adresse 0 
abgeschlossen werden. Erst ganz am Ende soll die neue Adresse gesetzt 
werden.

Da wäre ich nicht drauf gekommen -- steht davon irgendwas im Datenblatt?
Der Beitrag von Datum: 30.03.2007 19:55
geht ja wohl auch in diese Richtung.

Gruß

Stefan Salewski

von Ralf (Gast)


Lesenswert?

Der D12 setzt die Adresse nicht direkt nach dem SetAddress()-Befehl, 
sondern er wartet intern damit, bis das nächste IN-Token mit Adresse 0 
beantwortet wurde.

Schau dazu mal bei:

http://www.robmeerman.co.uk/project/usb/code/hid-mouse

Gruß Ralf

von Johannes T. (johnsn)


Lesenswert?

Hi,
ich weiß der Thread ist schon länger tot, aber ich wollte kein neues 
Thema anreißen. Hab nur eine kurze Frage für USB-Spezialisten:

Wenn der Setuprequest "GetDescriptor (Configuration)", soll dann 
grundsätzlich immer die gesamte Konfiguration geschickt werden, d.h. mit 
sämtlichen Interface- und Endpointdescriptoren oder soll ich mich 
vorerst mal an den Wert, der im Feld wLength angegeben ist halten, bis 
0x00FF Bytes angefordert werden?

Gruß,
Johnsn

von René K. (king)


Lesenswert?

Du hälst Dich an wLength, solange dieser Wert kleiner ist als 
ConfigDescriptor.wTotalLength. Ansonsten gilt der letztere Wert 
(wTotalLength).

von Johannes T. (johnsn)


Lesenswert?

Alles klar, danke!

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.