Forum: PC-Programmierung Effizient auf COM-Schnittstelle schreiben


von SpacerX (Gast)


Lesenswert?

Hi,

ich habe hier ein USB-Gerät, welches als CDC-Device arbeitet (d.h. es 
taucht im System als COMx bzw. /dev/ttyACMx auf).

Dieses Gerät erwartet Datenpakete, welche immer nur aus ein paar Bytes 
bestehen.

Wenn solche Daten per Ethernet übertragen werden, dann ist es sinnvoll, 
diese zu sammeln und erst ab einer bestimmten Paketgröße zu senden.

Wie ist das jetzt bei so einem USB-CDC-Device? Ist es da - wie bei einer 
echten seriellen Schnittstellenhardware - egal ob ich die Daten jeweils 
einzeln absende oder ist es wie bei Ethernet schneller, den Krempel zu 
sammeln und immer größere Pakete auf einen Rutsch durchzuschicken?

Ich kann es leider nicht mal eben so ausprobieren, da die entsprechenden 
Änderungen in der Software doch etwas größer sind, deswegen die Frage.

Danke!

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

USB überträgt die Daten in Pakete.

"Im Vergleich zu den früheren Lösungen bietet USB deutlich höhere 
Datenübertragungsraten. Die Daten werden jedoch in Paketen übertragen, 
für manche zeitkritische Anwendungen ist es deshalb weniger geeignet – 
etwa bei mit nur wenigen Bytes belegten Paketen, die die 
Übertragungsrate senken, oder wenn das Sammeln von Bytes zum Füllen 
eines Pakets die Übertragung verzögern würde." 
[https://de.wikipedia.org/wiki/Universal_Serial_Bus#Einsatzgebiete_des_USB]

Mit freundlichen Grüßen
Guido

von SpacerX (Gast)


Lesenswert?

OK...gibt's eine Möglichkeit herauszufinden, wie große diese Pakete 
sind? Bei meiner Netzwerkschnittstelle weiß ich, dass die Gegenseite mit 
1460 Nutzlast arbeitet.

von Peter II (Gast)


Lesenswert?

Die Frage ist was du dir davon erhoffst?

Durch das Sammeln von mehr Daten für ein Paket steigt die Latenz noch 
weiter. Dafür wird der Overhead kleiner.

Was ist das Ziel der Aktion?

von Guido C. (guidoanalog)


Lesenswert?

Hallo,

SpacerX schrieb:
> OK...gibt's eine Möglichkeit herauszufinden, wie große diese Pakete
> sind? Bei meiner Netzwerkschnittstelle weiß ich, dass die Gegenseite mit
> 1460 Nutzlast arbeitet.

da kann ich Dir leider nicht weiterhelfen.
Hier http://www.beyondlogic.org/usbnutshell/usb3.shtml#USBPacketTypes 
steht einiges, vielleicht hilft Dir dies weiter.

Mit freundlichen Grüßen
Guido

von SpacerX (Gast)


Lesenswert?

Peter II schrieb:
> Durch das Sammeln von mehr Daten für ein Paket steigt die Latenz noch
> weiter. Dafür wird der Overhead kleiner.

Genau das ist mein Ziel: durch geringeren Overhead mehr Daten in 
kürzerer Zeit übertragen. Die Latenz ist dabei zweitrangig.

von Steffen R. (steffen_rose)


Lesenswert?

SpacerX schrieb:
> Peter II schrieb:
>> Durch das Sammeln von mehr Daten für ein Paket steigt die Latenz noch
>> weiter. Dafür wird der Overhead kleiner.
>
> Genau das ist mein Ziel: durch geringeren Overhead mehr Daten in
> kürzerer Zeit übertragen. Die Latenz ist dabei zweitrangig.

Unter der Annahme, dass dein USB Bus bisher nicht voll ausgelastet ist, 
erhöht das Sammeln nicht den Durchsatz. Du hast höchstens weniger USB 
Interrupte auf deinem Gerät und häufig lassen sich die gesammelten Daten 
leichter verarbeiten.

von Sven B. (scummos)


Lesenswert?

Für Bulk Endpoints ist die Paketgröße im Deskriptor angegeben. Meist 
sind das 512 Byte.

Soweit ich das überblicke wird der Treiber buffern, wenn du schnell 
genug Daten nachschiebst. Im Zweifel probier es aus (Wireshark hilft). 
Natürlich ist es trotzdem effizienter, wenn du nicht für jedes Byte 
einzeln write() aufrufst.

von Jim M. (turboj)


Lesenswert?

Sven B. schrieb:
> Für Bulk Endpoints ist die Paketgröße im Deskriptor angegeben. Meist
> sind das 512 Byte.

Bei CDC würde ich eher 64 Byte erwarten, das ist auch das Maximum für 
Full Speed. Allerdings lohnen sich eventuell auch größere Transfers.

SpacerX schrieb:
> Wie ist das jetzt bei so einem USB-CDC-Device? Ist es da - wie bei einer
> echten seriellen Schnittstellenhardware - egal ob ich die Daten jeweils
> einzeln absende oder ist es wie bei Ethernet schneller, den Krempel zu
> sammeln und immer größere Pakete auf einen Rutsch durchzuschicken?

Problem: Es ist sowohl vom Host als auch vom Device abhängig.
Zwar erhöhen größere Transfers in aller Regel den Durchsatz, aber man 
sollte trotzdem immer mit dem konkreten Device testen - es könnte sich 
ja an großen Paketen "verschlucken" - Pufferüberlauf.

von Steffen R. (steffen_rose)


Lesenswert?

Die Durchsatzerhöhung kommt dadurch zustande, dass man der Bulktransfer 
eine größere Datenmenge "in einem Rutsch" übertragen kann. Hat man diese 
Datenmenge jedoch nicht, erhöht dies die Latenz. Die frei werdende 
Kapazität auf dem USB Bus steht anderen Anwendungen zur Verfügung. Der 
eigene Gesamt-Durchsatz wird nicht erhöht, sondern statt mehrerer 
kleiner Bulktransfers, von denen jede ms einer angestoßen werden kann 
wird ein großer nach vielen ms durchgeführt.

Speziell beobachte ich dies bei Anwendungen, welche eigentlich für die 
RS232 geschrieben wurden und nun mit der virtuellen COM Schnittstelle 
genutzt werden.

von Pandur S. (jetztnicht)


Lesenswert?

>Genau das ist mein Ziel: durch geringeren Overhead mehr Daten in
kürzerer Zeit übertragen. Die Latenz ist dabei zweitrangig.

Das geht so nicht. Wenn man groessere Mengen zB 1MByte + uebertragen 
will, ist ueblicherweise die Latenz das Problem, speziell wenn mit 
Bestaetigungen gearbeitet wird. Wenn also ueber die serielle 
Schnittstelle viele Daten schnell uebertragen werden sollen. muss die 
Blockgroesse rauf, aber vom originalen Protokoll. Die Blockgroesse kann 
man adaptiv gestalten, dass die Blocke immer laenger werden solange 
keine Retries erfolgen muessen.

Dabei sollte man die Restriktionen beachten. Ein 16bit CRC kann nur 
2^16bit schuetzen. Also 8kbyte. Bei groesseren Bloecken muss auf einen 
laengeren CRC gewechselt werden. Allenfalls verwendet man auch 
Feedforward Error Correction, dh. einen ECC.

Des weiteren kann man das ACK, dh die Bestaetigung, verzoegern, muss 
dafuer aber Zwischenspeichern. Und muss das kaputte Packet nach dem 
Retry noch einfuegen koennen.
So erreicht man dann maximalen Durchsatz, kann den Kanal buendig 
belegen.

von Jim M. (turboj)


Lesenswert?

Oder D. schrieb:
> Ein 16bit CRC kann nur 2^16bit schuetzen. Also 8kbyte.

Selten so wirres Zeugs gelesen. Erstmal ist der CRC unabhängig von der 
Anzahl der Bytes über die gerechnet wird - bei 16 Bit CRC wird halt 
einer von 64k (Mehrbit-) Fehlern nicht erkannt. Außerdem sind 2^16 = 
65536 und nicht nur 8192.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Jim M. schrieb:
> Außerdem sind 2^16 = 65536 und nicht nur 8192.

Genau hinsehen. 8192 Byte sind 2^16 Bit.

von Noch einer (Gast)


Lesenswert?

> es taucht im System als COMx bzw. /dev/ttyACMx

Auf der PC-Seite musst du dir gar keine Gedanken machen. Das 
Betriebssystem kümmert sich selbst um die ideale Paketgröße. Die 
USB-Treiber und das TCP/IP über dem Ethernet erzeugen selbst die 
optimale Paketgröße aus dem Datenstrom.

Ganz anders sieht es aus, wenn du das Device baust. Hier musst du dir 
Gedanken über die Puffergröße machen. Du rechnest aus, 512 Byte wären 
ideal, aber dein MC hat gar nicht so viel RAM.

von Peter II (Gast)


Lesenswert?

Noch einer schrieb:
> Auf der PC-Seite musst du dir gar keine Gedanken machen. Das
> Betriebssystem kümmert sich selbst um die ideale Paketgröße.

nein. Woher soll es denn wissen ob man niedrige Latenz oder hohen 
Durchsatz will?

Die ideale größe ist aber davon abhängig. Nicht umsonst gibt es Flags 
wie TCP_NODELAY.

von Markus F. (mfro)


Lesenswert?

Schickt man ein einzelnes Byte über den USB-Bus an ein CDC-Device, hat 
man (mindestens) 8 Bytes Overhead. Jedem Nutzdatenpaket muß ein 
Setup-Paket (das sagt, welches Gerät auf dem Bus man meint und was man 
von dem erwartet) vorausgehen. Und das ist nun mal 8 Bytes lang.

Den "optimalen" Datendurchsatz dürfte man bei Full-Speed mit 64 Bytes 
Nutzdaten und bei High-Speed mit 512 Bytes Nutzdaten erreichen (das sind 
die jeweils maximalen Paketgrößen für Bulk-Transfers).

Das setzt natürlich voraus, daß der Treiber auch wirklich Bulk-Transfers 
macht.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Peter II schrieb:
> Die ideale größe ist aber davon abhängig. Nicht umsonst gibt es Flags
> wie TCP_NODELAY.

Das gibt's hauptsächlich, damit man mit TCP auch irgendwie noch Dinge 
hinkriegt, für die es eigentlich nicht geeignet ist.

von Sven B. (scummos)


Lesenswert?

Noch einer schrieb:
> Ganz anders sieht es aus, wenn du das Device baust. Hier musst du dir
> Gedanken über die Puffergröße machen. Du rechnest aus, 512 Byte wären
> ideal, aber dein MC hat gar nicht so viel RAM.

Die USB-Endpoints haben ihre eigenen physikalischen Speicherbereiche zum 
Senden und Empfangen. Controller mit integriertem USB 2.0 haben mehr als 
genug RAM um 512 Byte irgendwo hin zu senden.

von SpacerX (Gast)


Lesenswert?

Was für ein wirres Durcheinander. Um das mal auf den Punkt zu bringen: 
Guido C hat recht, alles andere in diesem Thread reicht dann von "genau 
so richtig" bis "völliger Quatsch".

Ich habe den Transfer jetzt hostseitig umgestellt. Statt meine 3 bis 10 
Byte großen Kommandos jedes mal sofort auf den Weg zu bringen, sammele 
ich die Daten jetzt und sende sie erst ab, wenn mindestens 1024 Bytes 
zusammen gekommen sind. Das dann abgesendete Datenpaket ist ebenfalls 
immer genau 1024 Bytes groß und damit in jedem Fall ein ganzzahliges 
Vielfaches der in Frage kommenden Puffergrößen.

Ergebnis: bei großen Datentransfers ist die Übertragung um ca. den 
Faktor 10 schneller (nicht exakt gemessen, nur grob mit vorherigen 
Transferzeiten verglichen).

Also findet bei CDC-Devices eine paketweise Übertragung mit 
offensichtlich fester Paketgröße statt.

von SpacerX (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Genau hinsehen. 8192 Byte sind 2^16 Bit.

Ja, aber vermutlich nur im inneren eines schwarzen Loches oder nahe der 
Lichtgeschwindigkeit. Ansonsten sind und bleiben 2^16 = 65535.

von SpacerX (Gast)


Lesenswert?

Tippfehler, natürlich 65536

von Christian R. (supachris)


Lesenswert?

Ja, Bit und Byte kann man schon schwer auseinander halten. Bei uns hat 
ein Byte aber meistens noch 8 Bit.

von c-hater (Gast)


Lesenswert?

SpacerX schrieb:

> OK...gibt's eine Möglichkeit herauszufinden, wie große diese Pakete
> sind?

Natürlich. Man schaut einfach in den Standard, da steht das doch glatt 
schwarz auf weiss drinne. Tipp: CDC benutzt Bulk-Transfers für den 
Payload, also schaut man nach der maximalen Größe von Bulk-Transfers. 
Und diese hängt nun wiederum vom "Speed-Grade" des Gerätes ab. Auch das 
steht in dem Standard. Man muß ihn nur einfach mal lesen...

Du musst also zuerst herausfinden, ob es sich um ein Full-, High- oder 
Super- oder Super+- Speed-Gerät handelt (Low-Speed-Geräten sind 
Bulk-Transfers aus unerfindlichen Gründen vom Standard her grundsätzlich 
nicht erlaubt).

Allerdings beschränken sich real existierende CDC-Geräte wohl in aller 
Regel auf Full-Speed. In Einzelfällen mögen auch High-Speed-CDC-Geräte 
vorkommen. Mir persönlich ist allerdings nie eins über den Weg gelaufen. 
Soll heissen: du kannst Full-Speed mehr oder weniger als gegeben für ein 
CDC-Gerät ansehen...

von Steffen R. (steffen_rose)


Lesenswert?

c-hater schrieb:
> Allerdings beschränken sich real existierende CDC-Geräte wohl in aller
> Regel auf Full-Speed. In Einzelfällen mögen auch High-Speed-CDC-Geräte
> vorkommen. Mir persönlich ist allerdings nie eins über den Weg gelaufen.
> Soll heissen: du kannst Full-Speed mehr oder weniger als gegeben für ein
> CDC-Gerät ansehen...

Da bei USB HS CDC aller 125µs ein Transfer ausgelöst werden kann, 
bekommt man hier bei wenig Daten die Latenz besser in den Griff und das 
Interface verhält sich ähnlicher zu einer realen RS232.

Aber dies war dem TO nicht so wichtig.

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.