Forum: Mikrocontroller und Digitale Elektronik STM32L052x8 USB mit Bare Metal Code funktioniert nicht. SET_ADDRESS fehlerhaft


von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich brauche mal jemanden, der sich mit USB auskennt. Ich habe ein 
eigenes Board mit einem STM32L052x8. Das Board ist recht simpel. Außer 
dem STM sind nur ein LDO zwei Eingänge und 4 viel LEDs darauf.

Das Board wird über USB versorgt und das USB ist an den STM verdrahtet. 
Siehe Schaltplan. Der 1k5 Widerstand an D+ ist aktuell nicht bestückt. 
Der STM kann diesen intern zuschalten.

Die Software habe ich euch angehängt. Das template (startup code  / 
linkerscript) habe ich selbst verbrochen. Könnte somit immernoch den ein 
oder anderen Fehler haben.

Zur Nutzung des USBs habe ich mir von hier 
https://github.com/kcuzner/led-watch
die USB Library rauskopiert und gegenwärtig noch nichts adaptiert. Das 
Gerät sollte normal enumerieren.

Direktlink zur USB-Logik: 
https://github.com/kcuzner/led-watch/blob/master/common/src/usb.c

Es wird der interne 48 MHz Oszillator mit Clock-Recovery für's USB 
genutzt. Der Core/Peripherie läuft vom internen 16 MHz HSI mittels PLL 
auf 32 MHz.

Das System scheint soweit auch korrekt zu sein. Sobald der STM seinen 
internen Pullup an D+ aktiviert, beginnt der Rechner mit der 
Enumerierung. Hierbei wird der Device Deskriptor korrekt ausgelesen. Das 
kann ich mir mit Wireshark anschauen.

Das Problem tritt erst auf, sobald der Rechner über das SET_ADDRESS 
Kommando eine USB Adresse vergeben will.

In Zeile 747 in usb.c wird die Adresse gesetzt, nachdem die Statusstage 
des SET_ADDRESS Kommandos abgeschlossen ist.
1
USB->DADDR = (1<<7) | (last_setup->wValue & 0x7F);

Diesen Code habe ich etwas adaptiert. Ursprünglich stnad hier:
1
USB->DADDR |= last_setup->wValue & 0x7F;

Das Ergebnis bleibt jedoch das Gleiche:

Mein dmesg output zeigt mir:
1
[May19 19:41] usb 1-11: new full-speed USB device number 39 using
2
xhci_hcd
3
[  +0.123507] usb 1-11: Device not responding to setup address.
4
[  +0.206599] usb 1-11: Device not responding to setup address.
5
[  +0.206558] usb 1-11: device not accepting address 39, error -71
6
[  +0.123343] usb 1-11: new full-speed USB device number 40 using
7
xhci_hcd
8
[  +0.123458] usb 1-11: Device not responding to setup address.
9
[  +0.206686] usb 1-11: Device not responding to setup address.
10
[  +0.206496] usb 1-11: device not accepting address 40, error -71
11
[  +0.000093] usb usb1-port11: attempt power cycle
12
[  +0.643242] usb 1-11: new full-speed USB device number 41 using
13
xhci_hcd
14
[  +0.000188] usb 1-11: Device not responding to setup address.
15
[  +0.206616] usb 1-11: Device not responding to setup address.
16
[  +0.206475] usb 1-11: device not accepting address 41, error -71
17
[  +0.123383] usb 1-11: new full-speed USB device number 42 using
18
xhci_hcd
19
[  +0.000221] usb 1-11: Device not responding to setup address.
20
[  +0.206570] usb 1-11: Device not responding to setup address.
21
[  +0.206474] usb 1-11: device not accepting address 42, error -71
22
[  +0.000103] usb usb1-port11: unable to enumerate USB device

Wenn ich das Gerät mehrfach ab und anstecke klappt es sporadisch. 
Manchmal erst nach einigen versuchen. Manchmal sofort:
1
[May19 19:23] usb 1-10: new full-speed USB device number 122 using
2
xhci_hcd
3
[  +0.123557] usb 1-10: Device not responding to setup address.
4
[  +0.206537] usb 1-10: Device not responding to setup address.
5
[  +0.206590] usb 1-10: device not accepting address 122, error -71
6
[  +0.123298] usb 1-10: new full-speed USB device number 123 using
7
xhci_hcd
8
[  +0.123599] usb 1-10: Device not responding to setup address.
9
[  +0.206508] usb 1-10: Device not responding to setup address.
10
[  +0.206686] usb 1-10: device not accepting address 123, error -71
11
[  +0.000098] usb usb1-port10: attempt power cycle
12
[  +0.643120] usb 1-10: new full-speed USB device number 124 using
13
xhci_hcd
14
[  +0.000189] usb 1-10: Device not responding to setup address.
15
[  +0.206593] usb 1-10: Device not responding to setup address.
16
[  +0.206582] usb 1-10: device not accepting address 124, error -71
17
[  +0.123315] usb 1-10: new full-speed USB device number 125 using
18
xhci_hcd
19
[  +0.018547] usb 1-10: New USB device found, idVendor=16c0,
20
idProduct=05dc, bcdDevice= 0.11
21
[  +0.000013] usb 1-10: New USB device strings: Mfr=1, Product=2,
22
SerialNumber=0
23
[  +0.000007] usb 1-10: Product: LED Wristwatch
24
[  +0.000004] usb 1-10: Manufacturer: kevincuzner.com
25
[  +0.002376] hid-generic 0003:16C0:05DC.001E: hiddev96,hidraw5: USB
26
HID v1.11 Device [kevincuzner.com LED Wristwatch] on usb-
27
0000:00:14.0-10/input0

Um das Problem zu debuggen, habe ich einen Breakpoint an die stelle 
gesetzt, wo die Adresse ins USB-Modul geschrieben wird. an dieser Stelle 
lese ich exemplarisch im wValue Feld der Setup Anfrage den Wert 15. Kurz 
danach beschwert sich Linux, dass das Gerät Adresse 58 nicht akzeptieren 
wollte. Ich verstehe das nicht... Ich kann dort nicht die "korrekte" 
Adresse sehen.

hat irgendjemand eine Idee? Das treibt mich seit einigen Tagen um und 
ich finde einfach keinen Fehler.

Anmerkung:

Ich weiß, dass USB vorschreibt, dass die Adresse erst nach der Status 
stage im control kommando gesetzt wird. Das hat bei mir allerdings, als 
ich etwas für den STM32F407 geschrieben habe nicht geklappt. Da musste 
ich das Adressfeld umgehend beschreiben, damit sich der Host nicht 
beschwert. Erhlich gesagt habe ich das nicht verstanden. Zum Test habe 
ich das auch hier versucht. Ergebnis: bringt nichts.

Es wäre toll, wenn jemand eine Idee hat. Das einzige, was mich halbwegs 
beruhigt, ist dass der Device Deskrtiptor korrekt gelesen wird und auch 
das set address kommando zuverlässig erkannt wird. An ein HW Problem 
glaube ich aktuell weniger.

(Ja ich weiß, dass ich auch einfach CubeMX oder so nehmen kann.... Aber 
nein...)

Vielen Dank

von Thomas Z. (usbman)


Lesenswert?

M. H. schrieb:
> Ich weiß, dass USB vorschreibt, dass die Adresse erst nach der Status
> stage im control kommando gesetzt wird.

genau so ist es auch, Manchmal geht es auch wenn man das ignoriert und 
einfach ein kurzes delay einbaut und die addresse direkt beim SetAddress 
setzt, aber sauber ist das nicht.

Dein Usb Code ist etwas schwer zu verstehen. Deshalb ein paar Hinweise
- setzt du die USB Addresse wieder auf 0 wenn ein UsbReset kommt?
- USBSetAddress ist ein OutRequest d.h Status ist ein EP0In (ZLP)

Der Ablauf ist wie folgt:
- Setup(SetAddress) // auf Ep0Out mit wLenght == 0;
- EP0In // Status für out
  erst dann die die Addresse setzen bevor der EP0In Handler verlassen 
wird

Das funktioniert bei mir sowohl auf dem F103 als auch L05X (VCP)

Für dein Problem kann ich mir nur 2 Ursachen vorstellen
- du sendest kein ZLP mit der alten Addresse (normalerweise 0)
- du sendest das ZLP schon mit der neuen Addresse.

Edit: Ein USBReset kann während der Enum ein paar mal auftreten.

: Bearbeitet durch User
von M. Н. (Gast)


Lesenswert?

Hallo,

vielen Dank für die Antwort.

Thomas Z. schrieb:
> - setzt du die USB Addresse wieder auf 0 wenn ein UsbReset kommt?

Ja. In usb.c:834 wird das DADDR Register zurückgesetzt.

Thomas Z. schrieb:
> - USBSetAddress ist ein OutRequest d.h Status ist ein EP0In (ZLP)

Auch dies wird gemacht.

Thomas Z. schrieb:
> - du sendest kein ZLP mit der alten Addresse (normalerweise 0)
> - du sendest das ZLP schon mit der neuen Addresse.

Das ZLP wird gesendet und im Transmission complete des ZLP wird dann die 
Adresse umkonfiguriert. ICh werde da mal noch ein wenig rumbasteln. Aber 
wirklich nen Plan habe ich noch nicht.

Wie gesagt: Das ist fertiger Code aus einem wohl funktionierendem 
Projekt. Aber ich versuche es nochmal.

von Thomas Z. (usbman)


Lesenswert?

M. H. schrieb:
> Transmission complete

das geht zwar ist aber nicht das gleiche wie EP0In Interrupt. Ich 
filtere im EP0 In Interrupt auf SetAddress.

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> M. H. schrieb:
>> Transmission complete
>
> das geht zwar ist aber nicht das gleiche wie EP0In Interrupt. Ich
> filtere im EP0 In Interrupt auf SetAddress.

So habe ich es jetzt umgeschrieben. Es kommt das Setup Paket rein. 
Controller erkennt, dass es sich um set Address handelt und sendet ein 
ZLP. Nach dem schreiben des ZLP wir dann direkt das Adress-register 
umprogrammiert. Ergebnis ist das gleiche: Mehrere male an und abstecken 
führen sporadisch zum Ziel. Aber zuverlässig geht da nichts.

von beden kendräger (Gast)


Lesenswert?

M. H. schrieb:
> Es wird der interne 48 MHz Oszillator mit Clock-Recovery für's USB
> genutzt.

Bin mir bei einem/diesem speziellen Controller nicht sicher
da ich das Datenblatt nicht durchforstet habe aaaaaber:

USB in Zusammenhang mit internen Oszillatoren halte ich immer
für wenig stabil und zuverlässig.

Ein interner Oszillator wird immer mehr oder weniger stark vor
sich hindriften, im Gegensatz zu einem Quarzoszillator. Auch
wenn das Datenblatt evtl. verspricht dass es möglich ist damit
USB zu betreiben.

von M. Н. (Gast)


Lesenswert?

beden kendräger schrieb:
> Ein interner Oszillator wird immer mehr oder weniger stark vor
> sich hindriften, im Gegensatz zu einem Quarzoszillator. Auch
> wenn das Datenblatt evtl. verspricht dass es möglich ist damit
> USB zu betreiben.

Deswegen synchronisiert sich dieser Oszillator auf den SOF des USBs und 
trimmt sich automatisch nach.

von Stefan F. (Gast)


Lesenswert?

M. H. schrieb:
> Deswegen synchronisiert sich dieser Oszillator auf den SOF des USBs und
> trimmt sich automatisch nach.

Und das funktioniert auch zuverlässig, habe ich auf einem L073 getestet.

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> das geht zwar ist aber nicht das gleiche wie EP0In Interrupt. Ich
> filtere im EP0 In Interrupt auf SetAddress.

Nochmal genau gefragt: Es gibt keinen In Interrupt. Soweit ich die 
Register durchwühlt habe gibt es nur einen Transmission complete 
interrupt. Sowohl für out, als auch für in.

Was genau meinst du mit EP0 In interrupt? Ein Interrupt, der ausgelöst 
wird, sobald das IN token empfangen wird?

von Thomas Z. (usbman)


Lesenswert?

was ich seltsam fnde ist deine USB Addresse. Setz mal einen BP direkt 
auf die den SetAddress Request. Dann solltest du auch die gleiche 
Addresse in wValue sehen wie unter Linux.

Wie steht dein EP0IN Status wenn der Request kommt NAK ACK oder STALL?

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

M. H. schrieb:
> Nochmal genau gefragt: Es gibt keinen In Interrupt.

natürlich gibt es den. Schau mal ins UsbIntStatus Register. Da gibts 
Interrupts für sogut wie alles. Brauchst du z.B für Bulkin auch nur dann 
halt nicht auf EP0

von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

Thomas Z. schrieb:
> was ich seltsam fnde ist deine USB Addresse. Setz mal einen BP direkt
> auf die den SetAddress Request. Dann solltest du auch die gleiche
> Addresse in wValue sehen wie unter Linux.

Breakpoint direkt nach dem empfangen des Setup commands. Linux meldet:
1
[  +0.859038] xhci_hcd 0000:00:14.0: Timeout while waiting for setup device command
2
[  +0.206619] usb 1-10: device not accepting address 80, error -62
3
[  +0.126687] usb 1-10: new full-speed USB device number 81 using xhci_hcd
4
[  +0.126696] usb 1-10: device descriptor read/64, error -71
5
[  +0.229968] usb 1-10: device descriptor read/64, error -71
6
[  +0.106702] usb usb1-port10: attempt power cycle
7
[  +0.643265] usb 1-10: new full-speed USB device number 82 using xhci_hcd
8
[  +0.000153] usb 1-10: Device not responding to setup address.
9
[  +0.209993] usb 1-10: Device not responding to setup address.
10
[  +0.206499] usb 1-10: device not accepting address 82, error -71
11
[  +0.123349] usb 1-10: new full-speed USB device number 83 using xhci_hcd
12
[  +0.000160] usb 1-10: Device not responding to setup address.
13
[  +0.206616] usb 1-10: Device not responding to setup address.
14
[  +0.206555] usb 1-10: device not accepting address 83, error -71
15
[  +0.000121] usb usb1-port10: unable to enumerate USB device

Adresse im wValue Feld des Setup Pakets: 41
Die restlingen Felder stimmen (bmrequest etc.)

Das EP0R register sieht direkt nach empfang des Setup request wie im 
Anang aus. STAT_TX ist 00 => disabled. Die SW würde nach dem Breakpoint 
nun dazu übergehen das ZLP für die Statusstage zu konfigurieren.

von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

Thomas Z. schrieb:
> natürlich gibt es den. Schau mal ins UsbIntStatus Register. Da gibts
> Interrupts für sogut wie alles. Brauchst du z.B für Bulkin auch nur dann
> halt nicht auf EP0

Du meisnt vermutlich den Transmission complete interrupt, wenn daten vom 
Device an den host gesendet wurden. Einen anderen interrupt sehe ich 
nicht. Siehe Register im Anhang.

von Thomas Z. (usbman)


Lesenswert?

CTR in Verbindung mit DIR und EP Nummer
also CTR | DIR | 0 -> EP0In
ein Code ausschitt aus dem VCP Code von WS / Stefan und mir
1
...
2
    /* Endpoint Interrupts */
3
    if (I & CTR_)
4
    {
5
        trace("CTR ");
6
        USB_ISTR = ~CTR_;     /* Interruptbit löschen */
7
        EpNum = I & MASK_EA_; /* welcher EP? todo mask 0x07    */
8
        EpStatus = USB_EPREGS(EpNum); /* EP Status lesen      */
9
10
        if (I & DIR_) /* OUT, also Paket wurde empfangen */
11
        {
12
            trace("out\n");
13
            USB_EPREGS(EpNum) = EpStatus & ~CTR_RX_ & EP_NoToggleBits;
14
            if (EpNum == 0)
15
            {
16
                trace("logEpCtrl\n");
17
                if (EpStatus & SETUP_)
18
                {
19
                    trace("SETUP\n");
20
                    OnSetup(); /* Handle the Setup-Packet   */
21
                }
22
                else
23
                {
24
                    trace("EpCtrlOut\n");
25
                    OnEpCtrlOut(); /* eigentlich nur Class-spezifisches */
26
                }
27
            }
28
            if (EpNum == VCP1_BULK)
29
            {
30
                trace("logEpBulkOut\n");
31
                OnEp1BulkOut();
32
            }
33
       }
34
       else
35
       {
36
          //EPIn
37
          ....
38
       }
39
40
...
ich hab das jetzt einfach mal so raukopiert den Code findest du bei 
Stefan auf der HP

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> CTR in Verbindung mit DIR und EP Nummer
> also CTR | DIR | 0 -> EP0In
> ein Code ausschitt aus dem VCP Code von WS / Stefan und mir

Genauso wird das gemacht. Der Interrupt kommt auch. Aber es klappt 
nicht.

Beim STM32F4 ist da genau die Konstellation, die bei mir nicht geklappt 
hat. Da muss ich die Adresse direkt ändern, nachdem ich das ZLP 
konfiguriert habe. Wenn ich die Adresse erst ändere, wenn das ZLP raus 
ist, dann funktioniert da auch gar nichts.

von Stefan F. (Gast)


Lesenswert?

Ich würde hier den Vergleich mit F4 vermeiden, denn der hat eine andere 
USB Schnittstelle. Siehe 
https://www.st.com/resource/en/application_note/dm00296349-usb-hardware-and-pcb-guidelines-using-stm32-mcus-stmicroelectronics.pdf 
Tabelle 3.

von M. Н. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich würde hier den Vergleich mit F4 vermeiden, denn der hat eine andere
> USB Schnittstelle. Siehe
> 
https://www.st.com/resource/en/application_note/dm00296349-usb-hardware-and-pcb-guidelines-using-stm32-mcus-stmicroelectronics.pdf
> Tabelle 3.

Ich weiß. Aber auch da saß ich mehrere Tage, bis ich herausgefunden 
habe, dass ich die Adresse nicht im EP0In interrupt konfigurien kann, da 
sonst gar nichts funktioniert. Das ist etwas, das ich bis heute nicht 
verstanden habe. Aber nachdem ich gemerkt habe, dass ST da sowieso echt 
üble Silicon Bugs im USB Modul hat, die nicht im Erratasheet stehen, 
hatte ich die Lust an USB verloren und das alles ignoriert.

von Thomas Z. (usbman)


Lesenswert?

welche bugs meinst du? F407 ist OTG was naturgemäs aufwändiger ist.
Also im VCP code funktioniert das setzen der Addresse im EPIn0 Handler 
problemlos.
nochmal ein codeausschnitt:
1
void OnEpCtrlIn(void)
2
{
3
    if (IsStandardRequest())
4
    {
5
        trace("IsStandardRequest\n");
6
        switch (CMD.SetupPacket.bRequest)
7
        {
8
           case USB_GET_DESCRIPTOR:
9
                trace("GET_DESCRIPTOR\n");
10
                //if (CMD.TransferLen > 0)
11
                DescriptorBlockwiseIn();
12
                return;
13
           // special case SET_ADDRESS
14
           // spec requires that the address should be changed after
15
           // a successfull status ACK from the HOST    
16
           case USB_SET_ADDRESS:
17
                USB_DADDR  = 0x80 | CMD.SetupPacket.wValue; 
18
                usb_state |= STATUS_ADDRESSED;
19
                return;
20
/*           
21
           //todo wrong place gets never executed
22
           case CDC_GET_LINE_CODING: 
23
                trace("GET_LINE_CODE\n");
24
                ACK();
25
                break;
26
*/
27
           default:
28
               trace("default\n");
29
               ACK();
30
        }
31
        return;
32
    }
33
34
    if (IsClassRequest())
35
    ......

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> welche bugs meinst du? F407 ist OTG was naturgemäs aufwändiger ist.
> Also im VCP code funktioniert das setzen der Addresse im EPIn0 Handler
> problemlos.
> nochmal ein codeausschnitt:

Ich weiß, dass es so funktionieren sollte. Aber meine erfahrung ist da 
anders. Da klappt gar nichts. Und ich weiß nicht warum.

Bugs bzw. features gibt's da viele. Mein Fovorit, der mich 3 Tage 
gekostet hat: https://github.com/libopencm3/libopencm3/issues/531

Wenn man auf das FIFO zugreift, darf kein USB Interrupt kommen, in dem 
das das Interrupt status register gelesen wird. Sonst verliert das FIFO 
ein Wort und baut stattdessen den Wert des Statusregisters ins TX FIFO 
ein.

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Also im VCP code funktioniert das setzen der Addresse im EPIn0 Handler
> problemlos.

So macht der Code das auch. Exakt so. Aber es funktioniert einfach nicht 
:(.
Außer manchmal. Wenn es gut läuft geht es auch mal 3 mal 
hintereinanader. Aktuell geht es wieder gar nicht mehr.... Sehr komisch.

Was mich total verwirrt, ist dass das wValue Feld in der Anfrage eine 
Adresse zeigt, die mein Kernel nicht meldet. Andere USB Geräte klappen 
aber einwandfrei an dem Port. Sogar mit demselben Kabel.

von Thomas Z. (usbman)


Lesenswert?

wie gesagt ich hab dein USB nur kurz überflogen kann also nicht viel 
darüber sagen. Eie ist denn das Buffersetup gemacht?
Du hast warscheinlich gesehen, dass wir das komplette Setup Packet in 
eine variable kopieren. Was ich sagen kann ist dass obiger VCP code 
problemlos enumeriert. das ist vielfach von verschiedenen Leuten hier im 
Forum getestet worden. Da gibts einige Threats zu. Die Enum war nie ein 
Problem.

Das wValue feld bei dir kann ich mir auch nicht erklären.

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> wie gesagt ich hab dein USB nur kurz überflogen kann also nicht viel
> darüber sagen. Eie ist denn das Buffersetup gemacht?
> Du hast warscheinlich gesehen, dass wir das komplette Setup Packet in
> eine variable kopieren. Was ich sagen kann ist dass obiger VCP code
> problemlos enumeriert. das ist vielfach von verschiedenen Leuten hier im
> Forum getestet worden. Da gibts einige Threats zu. Die Enum war nie ein
> Problem.
>
> Das wValue feld bei dir kann ich mir auch nicht erklären.

Das Funktioniert bei mir ähnlich. Sobald ein Setup Paket eintrudelt wird 
es in eine "last setup packet" Variable gespeichert. Dann wird geschaut 
was es ist.

Bei Device deskriptor wird der Deskriptor gesendet und anschließend auf 
ein ACK gewartet.

Bei der adresse wird erstmal gar nichts gemacht sondern direkt in die 
Status stage gewechselt (ZLP In auf EP0).

Sobald dann der von dir beschriebene Interrupt kommt, wird geschaut, ob 
es eine Status stage war und was das letzte Setup paket war. Wenn das 
was gerade gesendet wurde eine Status IN stage war und das letzte Setup 
paket ein SET_ADDRESS war, dann wird die Adresse umgebogen.

Deswegen verstehe ich das alles ja auch nicht. Es sieht ganz richtig 
aus.


Um nochmal auszuholen: Beim STM32F4 sagt ST:
> Endpoint initialization on SetAddress command
> This section describes what the application must do when it receives a 
SetAddress command in a SETUP packet.
> 1.Program the OTG_FS_DCFG register with the device address received in the 
SetAddress command
> 2.Program the core to send out a status IN packet

Hier schreibt ST, dass man die Adresse vor der status stage setzen soll. 
Das ist komplett gegen mein Verständis von USB. Funktioniert aber. Wenn 
man die Adresse nach der Status stage setzt geht das nicht.

Leider zeigt mir Wireshark die SET_ADDRESS commands nicht an. Sonst 
könnte ich da mal mitsniffen...ICh glaube ich code einfach mal selber 
einen USB Treiber und schaue mal, ob ich in die selben Probleme laufe..

von Thomas Z. (usbman)


Lesenswert?

M. H. schrieb:
> Hier schreibt ST, dass man die Adresse vor der status stage setzen soll.
> Das ist komplett gegen mein Verständis von USB.

Den F407 hab ich noch auf meiner Todo Liste.

Ich kenne aber USB Cores wo das genauso wie beschrieben gemacht werden 
muss.
Der FX2 von Cypress ist da ein Beispiel. Die haben ein Schattenregister 
dafür was dann automatisch ins Adressregister überträgt.

Die ST USB Cores ind ziemlich seltsam um es mal freundlich auszudrücken. 
Man merkt dass die einfach einen IP core schlecht angeflanscht haben, 
noch dazu mit viel zu wenig USB Mem für die Buffer

von M. Н. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Die ST USB Cores ind ziemlich seltsam um es mal freundlich auszudrücken.
> Man merkt dass die einfach einen IP core schlecht angeflanscht haben,
> noch dazu mit viel zu wenig USB Mem für die Buffer

Ja. Habe beruflich Kontakt zu ST aus anderen Gründen und habe wegen dem 
F4 mal gefragt. Er konnte mir leider nur sagen, dass das kein eigener 
Core von ST ist und man dementsprechend nicht reinschauen kann, warum da 
so viele Sachen komisch sind. Soweit ich mich erinnere ist das IP von 
Synopsis.

Ich habe mal dem Typen geschrieben, von dem ich den USB Code kopiert 
habe. Vielleicht hat der ja ne Idee... Ich verweifel hier komplett...

Ein nettes FPGA Projekt für die Zukunft wäre vielleicht mal ein USB 
sniffer. USB ist ja ansich nicht sooo sehr Voodoo. Aber ich falle jedes 
Mal komplett auf die Schnautze.

Danke aber für die Vorschläge. Ich hoffe irgendjemand hat noch die 
zündende Idee...

von Stefan F. (Gast)


Lesenswert?

Da wird mir langsam klar, warum die Nucleo-Board den USB Port gar nicht 
nutzen/demonstrieren. Stattdessen setzen diese Baords auf einen externen 
USB-UART Adapter (als Bestandteil vom ST-Link).

von M. Н. (Gast)


Lesenswert?

Hallo zusammen. Ich habe nun eine weitere Erkenntnis gewonnen:

Wenn ich nach dem Empfang des Setup Pakets für Set address einen 
Breakpoint platziere und dort nach circa einer halben Sekunde auf 
"Continue" klicke, dann enumeriert alles einwandfrei.

Ich habe nun zu Testzwecken ein hartes Delay von ca 0.6 Sekunden 
eingefügt. Das Gerät enumeriert nun in 9/10 Fällen.

Kann sich das jemand erklären? Ich bin absolut ratlos.

von Thomas Z. (usbman)


Lesenswert?

M. H. schrieb:
> Kann sich das jemand erklären? Ich bin absolut ratlos.

Das sieht nach einem Protokolfehler aus. Ich mache bei SetAddress() 
gleich ein Ack()
1
void OnSetup(void)
2
{
3
    uint8_t request; 
4
    //bool requestError = true; reject all setup packets by default
5
    ReadControlBlock(&CMD.SetupPacket.bmRequestType, sizeof(TSetupPacket));
6
    request = CMD.SetupPacket.bRequest;
7
    if (IsStandardRequest()) 
8
    {
9
        trace("isStandardRequest\n");
10
        switch (request)
11
        {
12
           case USB_SET_ADDRESS:
13
                trace("SET_ADDRESS\n");
14
                ACK();
15
                return;
16
    ....

von temp (Gast)


Lesenswert?

Ich hab jetzt nicht den ganzen Thread gelesen, aber einen kurzen 
Hinweis. Genau diese Stelle hatte ich dazumal im Code von W.S. gefixt. 
Der hatte versucht das mit einem Delay zu lösen. Stefan hat das 
inzwischen in seinem Code übernommen. Such da mal nach "DeviceAddress". 
Nachdem die Adresse vom Host kommt merke ich mir die, sende das ACK 
zurück und erst im nächsten Interrupt wird die Adresse in das Register 
geschrieben. Macht man das zu früh gehts in die Hose.
Ich weiss nicht ob das jetzt dein Problem löst oder ob ich das falsch 
interpretiere, es kam mir nur so bekannt vor.

von M. Н. (Gast)


Lesenswert?

temp schrieb:
> Ich hab jetzt nicht den ganzen Thread gelesen, aber einen kurzen
> Hinweis. Genau diese Stelle hatte ich dazumal im Code von W.S. gefixt.
> Der hatte versucht das mit einem Delay zu lösen. Stefan hat das
> inzwischen in seinem Code übernommen. Such da mal nach "DeviceAddress".
> Nachdem die Adresse vom Host kommt merke ich mir die, sende das ACK
> zurück und erst im nächsten Interrupt wird die Adresse in das Register
> geschrieben. Macht man das zu früh gehts in die Hose.
> Ich weiss nicht ob das jetzt dein Problem löst oder ob ich das falsch
> interpretiere, es kam mir nur so bekannt vor.

Danke für deinen Beitrag. Das läuft bereits alles so.

1) Es kommt das Setup Paket mit Adresse
2) Es wird ein ACK gesendet
3) In interrupt (ACK ging raus): Adresse wird ins Register übernommen

Das klappt aber nicht wirklich.

Jetzt läuft es so:

1) Es kommt das Setup Paket mit Adresse
2) Es wird hart 0,6 s geartet
3) Es wird ein ACK gesendet
4) In interrupt (ACK ging raus): Adresse wird ins Register übernommen


Das klappt jetzt besser. Aber auch nicht zuverlässig. Irgendwas anderes 
muss flasch sein, was da irgendwie das Protokoll total verwurstet. 
Leider kann ich den USB Verkehr nicht mitsniffen. Wireshark zeigt nicht 
alles an.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Genau diese Stelle hatte ich dazumal im Code von W.S. gefixt.

Das erklärt, warum ich gestern das diffuse Gefühl hatte, das wir das 
schon einmal hatten.

M. H. schrieb:
> Das klappt jetzt besser. Aber auch nicht zuverlässig.

Ich kann dir versichern, dass es ohne delay zuverlässig funktioniert, 
wenn man sonst keine anderen relevanten Fehler im Ablauf hat.

von Thomas Z. (usbman)


Lesenswert?

ob mit dem Delay wie im Originalcode von WS oder oder so wie es temp 
später gefixt hat, mit dem SetAddress hatte der Code nie ein Problem. 
Enum klappte immer. Das Delay war auch nie 0.6s lang. Wenn die obige 
Sequenz nicht funktioniert würde ich mir das Ack näher anschauen.

von Philip S. (phs)


Lesenswert?

M. H. schrieb:
> Kann sich das jemand erklären? Ich bin absolut ratlos.

Ohne Logic Analyzer Trace vom Bus ist‘s natürlich Spekulation... aber:

Das Ganze deutet ja irgendwie auf ein Timing Problem hin.

Ich denke der Linux Kernel wird den SetAdress Request wiederholen wenn 
vom Device keine Reaktion kommt. Könnte also sein, dass Du mit dem Delay 
zufällig zur richtigen Zeit einen Retry vom Host bedienst.

Du hast geschrieben, dass Du den USB Code unverändert kopiert hast. Hast 
Du das Timing sonstwie verändert, z.B. durch andere Interrupts, die den 
USB IRQ verzögern? Oder machst Du evtl. im IRQ Handler noch andere 
Sachen, welche die Laufzeit verlängern, z.B. Debug Traces?

Bedenke, dass für den SetAdress Request spezielle Timing Anforderungen 
gelten.

In diesem Zusammenhang noch ein Hinweis: Der F103 USB Core hat m.M.n. 
eine Race Condition zw. einem Status OUT (Host ACK an Device) und dem 
nächsten SETUP Packet. Laut USB Standard muss ein SETUP Packet immer 
ge-ACK-t werden. So lange aber der CTR_Rx IRQ von der Status OUT Stage 
noch aktiv ist, wird die Hardware das SETUP Packet ignorieren. Das kann 
den Host schon mal verwirren.

Ich erwähne das deshalb: Der Linux Kernel scheint zunächst die ersten 
Bytes des Device Descriptors zu lesen, erst dann wird das SetAdress 
gemacht. Vielleicht fängt das Problem schon dort an?

Wie gesagt: Letzlich Spekulation ohne LA Trace. Vielleicht sind es aber 
doch Gedankenanstöße, die Dich weiter bringen.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Philip S. schrieb:
> Ich erwähne das deshalb: Der Linux Kernel scheint zunächst die ersten
> Bytes des Device Descriptors zu lesen

Das macht nicht nur Linux so. Der ersre GetDesriptor(Device) findet auf 
der Addresse 0 statt und dient im Prinzip dazu Ep0Size zu ermitteln. 
EP0Size kann  8 16 32 oder 64 Bytes haben.

Die Enumererierung läuft so ab:

- UsbReset
- UsbGetDescriptor(Device) mit wlenght=8 (linux) oder wLength=0x40 (win)
- UsbReset
- UsbGetDescriptor(Device)
- UsbGetDescriptor(Config) mit (wLength=9)
- UsbGetDescriptor(Config) mit (wLength=wTotalLength)
- UsbGetDescriptor(String)
....
- UsbSetConfig(cfgValue)

zusätzlich sind zumindest unter Win noch Suspend /Resume drin.

: Bearbeitet durch User
von Philip S. (phs)


Lesenswert?

Thomas Z. schrieb:
> Der ersre GetDesriptor(Device) findet auf
> der Addresse 0 statt und dient im Prinzip dazu Ep0Size zu ermitteln.

Interessant, macht ja Sinn, so hatte ich das noch gar nicht gesehen.

macOS schickt als erstes den SetAddress, liest dann die ersten 8 Bytes 
des Device Descriptors und fordert dann den Device Descriptor mit der 
vom Device gemeldeten Länge an.

Das ist jedenfalls was mein Device sieht; mein LA läuft unter macOS 
nicht.

von temp (Gast)


Lesenswert?

Vor ein paar Wochen lief hier ein Thread, da wurden schon bei der 
Takterzeugung Fehler gemacht, die sich so auswirkten, dass mit der 
Taktsynchronisierung ueber SOF alles noch schlimmer wurde. Wenn du 
sagst, der Code geht bei dem Projekt wo du es her hast, dann würde ich 
sowas auch im Auge behalten. Ohne den Takt wirklich mal zu messen würde 
ich nicht weiter machen.

von temp (Gast)


Lesenswert?


von M. Н. (Gast)


Lesenswert?

Guten Tag zusammen,

ich habe das Problem nun "gelöst". Ich habe den Code aus dem Internet in 
die Tonne gekloppt und es selbst gemacht. Mehr als die Enumerierung 
steht zwar noch nicht, aber diese klappt ohne Probleme.

IMHO, macht der Code aus dem Netz genau das Gleiche. Aber irgendein 
Detail muss anders sein.

Bei weiteren Problemen melde ich mich.

Vielen Dank für die Hinweise, auch wenn sie nicht zum Ziel geführt 
haben.

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.