Forum: Mikrocontroller und Digitale Elektronik Verständnissfrage USB-Kommunikation


von Rangi J. (rangi)


Lesenswert?

Hallo Forum,

ich benötige mal Hilfe bei eine USB-Host-Implementation. Ich habe hier 
einen STM32F4xx und damit verbunden einen FTDI FT232.
Jetzt habe ich den USB-Host Core aus den Beispielen von ST und den 
Linux-Treiber vom FTDI zusammengebaut und erfolgreich zum laufen 
bekommen. Ich kann den FTDI konfigurieren (Baudraten, Handshake, etc.) 
und erfolgreich Daten abrufen und senden.
Zum Senden verwende ich die "USBH_BulkSendData(...)"-, zum Empfangen die 
"USBH_BulkReceiveData(...)"-Funktionen. Empfangen geht auf diese Weise 
mit Pollen der Daten, ich rufe zyklisch die Empfangsroutine auf und wenn 
etwas dinne ist, werden Daten weiter an die nächst höhere Schicht 
gereicht.

Jetzt kommt das Problem, wenn ich versuche dieses Polling alle 10ms zu 
machen, gibt es ein variable Verzögerung. Also der Interrupt, der den 
Abschluss der Aktion anzeigt kommt viel zu spät. Polle ich langsam 
(>20ms) vergeht eine Zeit von 26µs vom Starten bis zum Interrupt 
(CHH-Interrupt). Polle ich schneller vergehen zwischen 3ms und 16ms bis 
der Interrupt kommt.
Frage: was blockiert denn hier? Ist das bei Bulk-Transfer immer so, dass 
eine gewisse Wartezeit eingehalten werden muss? Kann mir jemand 
erklären, was genau hier auf dem Bus passiert dass zu dem o.g. Verhalten 
führen kann?

Danke

von Jim M. (turboj)


Lesenswert?

Der FT232 hat doch einen variablen FIFO, der könnte die beobachtete 
Verzögerung erklären. Die Idee dahinter ist die Bytes vom UART zu 
sammeln und in einer größeren Bulk Transaktion zu verarbeiten anstatt 
viele kleine Transaktionen zu verwenden - letzteres würde den Host 
stärker belasten.

Im Windows Treiber ist das eintellbar. Schau Dir mal die Linux Source 
genau an, dort müsste es eigentlich auch einstellbar sein.

von Rangi J. (rangi)


Lesenswert?

Mein FT232 hat 256 bytes Fifo. Mit aktiviertem Hardware-Handshake konnte 
ich den Buffer füllen und auch sehen, wann er voll war. Dann kann man 
die Daten auslesen.
Bei 115200 Bd sind sie 256 Bytes in etwas mehr als 20ms voll.
Ich wollte wenn ich Daten gelesen hatte, gleich nochmal abfragen und 
schnell auslesen. Erst wenn keine Daten mehr kommen wollte ich auf einen 
langsamen Takt wechseln. Dabei ist mir dann aufgefallen dass es nicht 
wirklich schnell gelesen wurde. Durch Messung bin ich dann darauf 
gekommen, dass der Interrupt sehr lange auf sich warten lässt.

Kann der USB Client denn die Kommunikation verzögern?

von Jim M. (turboj)


Lesenswert?

Rangi J. schrieb:
> Kann der USB Client denn die Kommunikation verzögern?

Selbstverständlich. Er braucht auf das (Bulk)IN-Token nur ein NAK zu 
senden. Der FTDI Chip wird das vermutlich solange machen, bis entweder 
der FIFO voll genug oder ein Timout aufgetreten ist.

von Rangi J. (rangi)


Angehängte Dateien:

Lesenswert?

So, ich habs kurzerhand einfach mal aufm PC gesnifft. Hier kann man die 
Polling-Zeit einstellen. Initial stand das auf 16ms und tatsächlich 
wurde auch alle 16ms ein "URB_BULK in" Transfer ausgelöst. Beim 
Umstellen auf 5ms eben dann alle 5ms.
Und das ganze ohne Verzögerungen oder Wartezeiten. Der FTDI hat artig 
alle 5ms geantwortet. Das hat bei mir z.B. nicht geklappt.

Und jetzt hab ich nochwas gesehen: (Beim diesem Sniff hatte ich Glück, 
denn die Zeit war genau auf 0 beim Start)
Im Bild Zeile 196 sind Daten enthalten. Der folgende Transfer erfolgt 
nicht 10ms später, sondern 31ms. Danach geht es wieder alle 10ms weiter. 
Wie kann ich mir das erklären? Und es kann hier nicht daran liegen, das 
286 Bytes übertragen wurden. 286 Bytes @ 12MHz dauern ca. 0,5ms

von Nosnibor (Gast)


Lesenswert?

Rangi J. schrieb:
> Im Bild Zeile 196 sind Daten enthalten. Der folgende Transfer erfolgt
> nicht 10ms später, sondern 31ms. Danach geht es wieder alle 10ms weiter.
> Wie kann ich mir das erklären? Und es kann hier nicht daran liegen, das
> 286 Bytes übertragen wurden. 286 Bytes @ 12MHz dauern ca. 0,5ms

Da hat der FTDI das gleiche gemacht wie vorher schon am STM32:
Solange keine Daten in der FIFO sind, sofort "nix da" geantwortet.
Die ersten paar Bytes auch gleich mitgeschickt.
Und dann den USB-Transfer hingehalten, das soll sich schließlich lohnen.

Am PC ist so ein Verhalten oft praktisch, denn es reduziert 
Interruptlast und Taskwechsel. Vernünftigerweise sollte man das aber 
konfigurieren können. Vor allem, wann der FTDI damit wieder aufhört, 
sonst hält er nach dem letzten Byte auf der Leitung den PC noch 30ms 
hin, während die Gegenseite auf die Antwort wartet.

von Rangi J. (rangi)


Lesenswert?

@Nosnibor: das ist aber unlogisch. Das "warten" auf mehr Daten sollte 
aber aufhören, wenn der Puffer voll ist. Das passiert aber nicht. Im 
Gegenteil, dadurch kommt es zum Datenverlust, der Puffer läuft über.
Ich hab nochwas komisches gesehen. Beim Transfer mit Windows sind 
Transferlängen von 270 Byte (vermutlich mehr) möglich (oder werde ich 
hier vom USBPcap verschaukelt?). Beim STM32 hat mir aber der 
End-Point-Descriptor gesagt nur 64Bytes maximal möglich sind 
(in_ep_size=0x40, out_ep_size=0x40).

Ich habs mal manuell auf 128 gesetzt, aber das funktioniert nicht, dann 
kommt ein Timeout in der ISR.

von Rangi J. (rangi)


Lesenswert?

So, jetzt hatte ich mal wieder Zeit diesem Thema zu widmen:
Es gibt eine Erkenntnis. Ich muss dem FTDI mit einem Befehl einen 
Latency-Timer einstellen. Dieser wirkt sehr merkwürdig, denn ich kann 
den FTDI nicht auslesen, solange dieser Timer nicht abgelaufen ist, auch 
wenn (und ich betone, selbst wenn) Daten im Puffer sind und sogar wenn 
der Puffer überläuft. Man muss den Timer dann am besten auf ein Wert 
stellen, in dem dann alle möglichen Daten reinpassen.
Der Wert des Timers ist ein Byte, 1 = 1ms.
Bei 0 kann ich immer auslesen, macht aber nur dann sinn, wenn die 
Applikation das Auslesen künstlich verlangsamt.

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.