Forum: Mikrocontroller und Digitale Elektronik Messwerte per USB auf PC: Geschwindigkeit?


von Borislav B. (boris_b)


Lesenswert?

Hallo!
Ich habe vor Messwerte vom Mikrocontroller (STM32) über die USB 2.0 
Schnittstelle an den PC zu senden. So weit funktioniert auch alles, aber 
nun versuche die Geschwindigkeit etwas zu erhöhen.

Der Sendecode sieht zur Zeit so aus:

SendByte(b);
b++;
waitMs(1000);

Es werden also zyklisch die Zahlen von 0 bis 255 an den PC gesendet, 
jeweils im Sekundentakt. Empfangen wird das ganze über ein Terminal 
Programm (Stichwort virtueller COM Port).

Wenn ich nun die Sendegeschwindigkeit erhöhe, kann ich bis zu 1ms delay 
runtergehen. Kleinere Werte sorgen dann dafür, dass nicht mehr alle 
Zahlen ankommen (es fehlen zwischendurch einfach welche).

Nun mein Frage:
Woran könnte das liegen? Es kann ja nicht sein, dass ein USB 2.0 nur 
1000 Byte pro Sekunde schafft, oder? Das Ding ist ja eigentlich bis 480 
MBit spezifiziert, wenn ich mich recht erinnere...

Gruß,
Boris

von astroscout (Gast)


Lesenswert?

Ich kenne deinen Mikrocontroller jetzt nicht genau, aber die 450 MBit 
sind lediglich die theoretisch höchste Datenrate, die mit USB 2.0 
erreicht werden kann.
Das heißt jedoch nicht, dass dein Mikrocontroller diese Geschwindigkeit 
auch wirklich erreichen kann!

Mal als Anregung (ich bin mir nicht ganz sicher, ob das geht):
Vielleicht kannst anstatt immer genau eine festgelegte Zeit zu warten, 
solange warten, wie der Mikrocontroller zum übertragen eines Bytes 
benötigt. Evtl. wird bei deinem Mikrocontroller dann ein Flag gesetzt, 
das anzeigt, ob er noch am senden ist. Das müsste man allerdings im 
Datenblatt mal recherchieren.

von Julian O. (juliano)


Lesenswert?

Meines Wissens nach ist es ziemlich unsinnig per USB einzelne Bytes zu 
übertragen. Der STM müsste eigentlich intern einen Buffer haben (512 
Byte?). Es sollte sinnvoller sein erst diesen Buffer zu füllen und dann 
am Stück zu senden

von Borislav B. (boris_b)


Lesenswert?

Aber USB ist doch eine serielle Schnittstelle. Da sollte es doch keinen 
unterschied machen, ob die Daten aus dem Buffer seriell weggesendet 
werden, oder ob ich manuell in meiner Schleife seriell sende?

von Jörg S. (joerg-s)


Lesenswert?

Boris B. schrieb:
> Woran könnte das liegen? Es kann ja nicht sein, dass ein USB 2.0 nur
> 1000 Byte pro Sekunde schafft, oder? Das Ding ist ja eigentlich bis 480
> MBit spezifiziert, wenn ich mich recht erinnere...
USB 2.0 kann 480MBit. Das heisst aber nicht das das Gerät das auch 
macht. Ich bin zwar kein Experte für die STM32, aber soweit ich weiss 
kann der (wie glaub ich alle Cortex M3) nur Full-Speed, also 12 MBit.

von Christian R. (supachris)


Lesenswert?

Außerdem ist das Protokoll bei USB paket-orientiert. Wenn du nur ein 
Byte schickst, ist das total ineffizient. Sinnvollerweise sollte man 
einen ganzen Block in der Größe des Endpoint Buffers schicken. Bei USB 
2.0 HighSpeed erreicht man die maximale Geschwindigkeit von etwa 40MB/s 
im BULK Modus nur, wenn man immer die Pakete voll ausnutzt (512 Byte) 
und so schnell anliefern kann, dass der Controller einen Microframe mit 
10 bis 11 vollen Paketen voll packen kann. Bei 10 Paketen zu je 512 Byte 
pro MicroFrame erreicht man 512 x 10 x 8000 = 40960000 Byte/s 
Datendurchsatz. Mit schnellen Controllern wie z.B. dem Cypress FX2 ist 
das zu schaffen. Der FT2232H kann das wohl mit aktuellem Treiber 
mittlerweile auch.

von Nico (Gast)


Lesenswert?

> Außerdem ist das Protokoll bei USB paket-orientiert. Wenn du nur ein
>
> Byte schickst, ist das total ineffizient.

Genau so schaut es aus, was du zur Zeit machst ist für jedes einzelne 
Byte ein eigenes Datenpaket zu schnüren mit entsprechendem overhead! Du 
solltest die Größe deines Endpoint-Buffers ausnutzen und dann erst 
senden.

Aber warum verwendest du überhaupt ein Delay? Frage doch die 
entsprechenden Flags ab oder nutze wenn es das gibt entsprechende 
Interrupts, wenn die Buffer wieder frei sind. Damit bist du auch an der 
max. Geschwindigkeit und musst nicht ausprobieren wie weit du mit deinem 
Delay runter kannst.

von Hc Z. (mizch)


Lesenswert?

USB ist nicht einfach eine serielle Schnittstelle.  USB ist ein Bus mit 
vielen Teilnehmern und einem komplizierten Protokoll, das in 
1-ms-Intervallen abläuft.  Genau diese Intervallfrequenz hast Du soeben 
entdeckt (1 kHz).  In diesem Abstand pollt, vereinfacht gesagt, der 
USB-Host seine Teilnehmer.  Haben die dann nur 1 Byte abzuliefern, wird 
in einem Intervall nur dieses übertragen.

Du hast noch ein Problem:  Du sendest fortlaufende Byte-Werte und 
schreibst, dass bei Überschreitung der 1 kHz welche fehlen.  In diesem 
Fall müsste aber Deine Senderoutine blockieren, bis sie ihr Byte 
losgeworden ist (und so den Durchsatz beschränken).  Dass Werte verloren 
gehen, weil sie zu schnell kommen, darf in einer sauberen Senderoutine 
nicht passieren. Sie muss den Flaschenhals nach hinten durchreichen.

Idealerweise würde die Senderoutine, wenn ein Byte noch nicht abgesendet 
ist und ein neues kommt, das Paket vergrößern.  Kann sie das nicht, muss 
sie blockieren, um Datenverlust wie Deinen zu verhindern.

von Michael K. (michael007)


Lesenswert?

auf welche Geschwindigkeit hast Du denn überhaupt deinen COM Port 
eingestellt?

von Borislav B. (boris_b)


Lesenswert?

Danke für den vielen Input :-)
Ihr habt da einige wichtige Aspekte aufgezeigt, die mir bisher nicht 
bewusst waren. Ich werde dann mal versuchen zu puffern und größere 
Pakete zu versenden. Warum die Senderoutine nicht blockiert, werde ich 
mir auch mal anschauen.

@Michael:
Der COM-Port steht momentan auf 115200 Baud. Das müsste ja eigentlich 
schnell genug sein... (~14.000 Byte/s?)

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.