Forum: Mikrocontroller und Digitale Elektronik USB übergeordnetes Protokoll


von Maxe (maxemaxe)


Lesenswert?

Hallo allerseits,

bin gerade dabei mich in die USB-Kommunikation einzuarbeiten, zwischen 
einem Mikrocontroller STM32F103 und dem PC, dort mit LibUSB. Ich bin 
auch schon so weit, dass ich Pakete zu und von einem Control-Endpoint 
und Bulk-Endpoint übertragen kann. Noch nicht ganz klar ist mir 
allerdings, wie ich die Endpoints geschickt für meine Anwendung nutze.

Der Mikrocontroller soll als Datenlogger funktionieren, geloggte Daten 
dann per USB an den Computer übertragen werden und auch eine 
Konfiguration von PC-Seite aus soll möglich sein (Kanäle, 
Logging-Intervall, Dauer...). Ich denke für die Konfigurationen und 
Statusabfragen benutze ich einfach einen Control-Endpoint (DefaultCEP?) 
und verwende dann unterschiedliche Werte in bRequest z.B. je nach 
Datentyp und übertrage die Werte in wValue oder in einem Datenblock.

Wie gehe ich dann aber bei größeren Datenmengen vor, also bspw wenn ich 
die geloggten Daten übertragen möchte, der Bulk-Transfer hat ja keine 
"Parameter" wie bRequest, wValue usw? Schickt man vorher eine Anfrage an 
einen Control-Endpoint, der die Bulk-Übertragung vorbereitet? Oder 
bastelt man sich das im Bulk-Packet z.B. am Anfang der Daten selber 
zusammen?

Über Control-Endpoints lassen sich ja auch Datenblöcke übertragen, warum 
dann überhaupt noch Bulk-Endpoints?

Vielen dank schonmal!

: Bearbeitet durch User
von Martin M. (capiman)


Lesenswert?

Hier würdest "etwas mehr" Info finden:

https://usb.org/document-library/usb-20-specification

von Maxe (maxemaxe)


Lesenswert?

Wie man ein eigenes USB-Gerät konkret anspricht ist doch nicht Teil der 
Spezifikation?

von Florian L. (muut) Benutzerseite


Lesenswert?

Sinnvollerweise spricht dein Gerät das Protokoll einer gut definierten 
Geräteklasse wie CDC oder Speicherstick. Dann sind Treiber auf 
verschiedenen Plattformen bereits vorhanden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Florian L. schrieb:
> Sinnvollerweise spricht dein Gerät das Protokoll einer gut definierten
> Geräteklasse wie CDC oder Speicherstick.

Letzteres wäre "Mass Storage Class" (MSC). Ist aber erstens nicht ganz 
trivial, denn als Protokoll darüber muss man einen nennenswerten Teil 
der SCSI-Spezifikation implementieren, außerdem ist sowas nur für 
statische Daten gut. Der Grund ist: ein Host, der ein MSC einbindet, hat 
über den Speicher die volle Kontrolle und darf beispielsweise beliebig 
Daten im Cache behalten. Dass sich die Daten "unter seinen Füßen" 
dynamisch ändern (wie es bei Logdaten typisch der Fall wäre), ist dabei 
nicht vorgesehen.

Angesichts der Aufgabenstellung klingt mir CDC (Communication Device 
Class) durchaus auch angebracht, zumal mittlerweile nun endlich sogar 
Windows damit "aus der Dose raus" klar kommt und einen Klassentreiber 
hat. Je nach Anwendungsfall kann man die Daten dabei auch komplett in 
ASCII austauschen und dann auf dem Host für die Tests ein normales 
Terminalprogramm benutzen.

Da CDC früher bei Windows nicht als Klassentreiber ohne weiteres 
vorhanden war, sind viele Leute auch auf ein Human Interface Device 
(HID) ausgewichen. Es ist zwar völlig widersinnig, was dabei alles zu 
einem "Human Interface" wurde (beispielsweise sind die Programmiergeräte 
für ARM Cortex-M so standardisiert), aber dafür brauchte man eben keine 
extra Treiber.

Der Control Endpoint ist nur für die Steuerung da, nicht für den 
eigentlichen Datenaustausch. Er ist der einzige, der in beiden 
Richtungen benutzt werden kann, und für die einzelnen Klassen hat er 
recht genau spezifizierte Steuersequenzen, die man implementieren muss.

von Thomas Z. (usbman)


Lesenswert?

Maxe schrieb:
> Über Control-Endpoints lassen sich ja auch Datenblöcke übertragen, warum
> dann überhaupt noch Bulk-Endpoints?

Wegen der Geschwindigkeit. Für Control Transfers sind 10% der Bandbreite 
(1.2 MBit max) bei Full Speed vorgesehen. Selbst 0 Bytes Nutzdaten 
besteht ein Control Transfer aus einem 8 Byte Setup  Paket (out) + 
Status (in) + Overhead. Trotzdem kann man mit Control Only Devices 
einiges machen. Ich habe damit z.B schon FW Updates realisiert.

Wenn du mit Bulk Transfers arbeiten willst musst du das ein Protokoll 
implementieren. Max Durchsatz erreichst du wenn du immer volle 64 Bytes 
überträgst. Jeder Short Transfer verlangsamt die Sache. Unter optimalen 
Bedingungen erreicht man etwa 13 Bulk Transfers pro Frame. Das dürfte 
aber mit dem F103 nur schwer machbar sein. (Double Buffer?)
Welches Protokoll du bei Bulk verwendest liegt an dir. Du kannst ja mal 
das MSC Bulk only Protokoll anschauen oder die USB Midi Kodierung 
anschauen.

: Bearbeitet durch User
von Purzel H. (hacky)


Lesenswert?

Hier scheint ein Controller mit USB vorgegeben zu sein. Um einfach etwas 
zu loggen moeglicherweise ueberzogen. Allenfalls ist ein USB-UART etwas 
einfacher. Denn es ist ja nicht nur die Controllerseite, sondern auch 
die PC Seite. Man muss isch nur um das Protokoll kuemmern, der USB Teil 
ist schon da.
Allenfalls gibt's schon eine UART Impmenentation fuer den F103

Bei einem USB UART sind die Treiber schon Teil des Betreibssystems. Bei 
der gezeigten Loesung noch nicht. Soweit mir bekannt, muss man mit etwas 
Pech bei jedem neuen Windows Anpassungen am Treiber vornehmen.

War aber trotzdem interessant von der unterliegenden Struktur zu hoeren.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Purzel H. schrieb:
> Bei einem USB UART sind die Treiber schon Teil des Betreibssystems. Bei
> der gezeigten Loesung noch nicht.

Wenn er ein CDC implementiert, dann ist der Klassentreiber mittlerweile 
(seit Windows 10) mittlerweile sogar in Windows angekommen – alle 
anderen Betriebssysteme konnten das schon 10 Jahre früher "aus der Dose 
raus".
Ist also eher kein Argument. Beispiele für CDC sollte es für die STM 
auch geben, das muss man sich also nicht komplett neu von den Hacken 
ablaufen.

Irgendwelche privaten Protokolle ("vendor specific") würde ich 
allerdings auch nicht implementieren, wenn es nicht unbedingt sein muss. 
Da der TE etwas von erfolgreichen Experimenten mit libusb schreibt, 
vermute ich, dass er gar kein Windows hat. Damit wäre das 
Treiberargument eh hinfällig, selbst für private Protokolle.

von Maxe (maxemaxe)


Lesenswert?

Danke für die Antworten!

Florian L. schrieb:
> Sinnvollerweise spricht dein Gerät das Protokoll einer gut definierten
> Geräteklasse wie CDC oder Speicherstick.

Jörg W. schrieb:
> Angesichts der Aufgabenstellung klingt mir CDC (Communication Device
> Class) durchaus auch angebracht,[...]

So wie ich das verstehe stellt die CDC-Klasse nur eine paket- oder 
byteweise Punkt-zu-Punkt-Verbindung dar, ich müsste also wieder eine 
Kommunikationsschicht drüberbauen. Da würde ich dann lieber direkt in 
USB etwas eigenes machen und die Setup-Daten bei der Übertragung nutzen.

Florian L. schrieb:
> Dann sind Treiber auf
> verschiedenen Plattformen bereits vorhanden.

Es scheint, dass LibUSB-Treiber bei aktuellen Systemn auch vorhanden 
sind (WinUSB unter Windows). Unterstützt wohl nicht alles, was unter USB 
möglich wäre, hier aber ausreichend.

Jörg W. schrieb:
> Der Control Endpoint ist nur für die Steuerung da, nicht für den
> eigentlichen Datenaustausch. Er ist der einzige, der in beiden
> Richtungen benutzt werden kann, und für die einzelnen Klassen hat er
> recht genau spezifizierte Steuersequenzen, die man implementieren muss.

Du meinst den Default Control Endpoint? Bei meinen Versuchen haben auch 
andere Endpoints in beide Richtungen funktioniert, vielleicht habe ich 
dich aber auch falsch verstanden.
Was die Klassen angeht, würde ich ja keine vorgegebene verwenden, 
sondern für bDeviceClass den Wert 0xFF wählen, also eine 'eigene' 
Klasse.



Thomas Z. schrieb:
> Maxe schrieb:
>> Über Control-Endpoints lassen sich ja auch Datenblöcke übertragen, warum
>> dann überhaupt noch Bulk-Endpoints?
>
> Wegen der Geschwindigkeit. Für Control Transfers sind 10% der Bandbreite
> (1.2 MBit max) bei Full Speed vorgesehen. Selbst 0 Bytes Nutzdaten
> besteht ein Control Transfer aus einem 8 Byte Setup  Paket (out) +
> Status (in) + Overhead. Trotzdem kann man mit Control Only Devices
> einiges machen. Ich habe damit z.B schon FW Updates realisiert.
>

> Wenn du mit Bulk Transfers arbeiten willst musst du das ein Protokoll
> implementieren.
Bereitet man den Bulk-Transfer dann sinnvollerweise mit einem 
Control-Transfer vor, also überträgt darüber bspw. die 'Bedeutung' des 
nachfolgenden Bulk-Transfers und die Menge der Daten? Oder baut man das 
eher in das Bulk-Paket direkt mit ein? Ich denke beides sollte 
prinzipiell gehen.

> Welches Protokoll du bei Bulk verwendest liegt an dir. Du kannst ja mal
> das MSC Bulk only Protokoll anschauen oder die USB Midi Kodierung
> anschauen.

OK, ich schau mir das mal an. "Bulk only" heißt dann vermutlich, dass 
dort kein Control-Endpoint für die Metadaten der Bulk-Transfers 
verwendet wird?

> Max Durchsatz erreichst du wenn du immer volle 64 Bytes
> überträgst. Jeder Short Transfer verlangsamt die Sache. Unter optimalen
> Bedingungen erreicht man etwa 13 Bulk Transfers pro Frame. Das dürfte
> aber mit dem F103 nur schwer machbar sein. (Double Buffer?)

Die Geschwindigkeit spielt am Schluss wahrscheinlich auch nicht die 
große Rolle, schneller wie eine Serielle soll es aber schon sein.


Purzel H. schrieb:
> Hier scheint ein Controller mit USB vorgegeben zu sein. Um einfach etwas
> zu loggen moeglicherweise ueberzogen. Allenfalls ist ein USB-UART etwas
> einfacher.

Klar, das wäre einfacher, aber hier gehts ja speziell um USB.

von Harald K. (kirnbichler)


Lesenswert?

Jörg W. schrieb:
> Wenn er ein CDC implementiert, dann ist der Klassentreiber mittlerweile
> (seit Windows 10) mittlerweile sogar in Windows angekommen

Der Klassentreiber ist in Windows auch schon immer* enthalten gewesen, 
nur aus irgendwelchen komplett hirntoten Gründen brauchte man zur 
Nutzung eine zum jeweiligen Gerät passende *.inf-Datei, die bei den 
letzten paar Windows-Generationen auch noch mit einer *.cat-Datei 
signiert sein musste, was einem das Selbsterstellen verunmöglichte.

Aus der langen Liste der strunzdebilen Fehlentscheidungen im Hause 
Microsoft war das eine besonders erfreuliche.

Wie gesagt, der eigentliche Treiber ist schon immer vorhanden gewesen 
(usbser.sys)

*) genauer: Seit Windows 2000.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Maxe schrieb:

> Jörg W. schrieb:
>> Angesichts der Aufgabenstellung klingt mir CDC (Communication Device
>> Class) durchaus auch angebracht,[...]
>
> So wie ich das verstehe stellt die CDC-Klasse nur eine paket- oder
> byteweise Punkt-zu-Punkt-Verbindung dar, ich müsste also wieder eine
> Kommunikationsschicht drüberbauen.

Serialisierer gibt's wie Sand am Meer.

> Da würde ich dann lieber direkt in
> USB etwas eigenes machen und die Setup-Daten bei der Übertragung nutzen.

Würde ich nicht machen. Extrawürste sind immer teuer. Aber mach, wenn du 
denkst.

> Es scheint, dass LibUSB-Treiber bei aktuellen Systemn auch vorhanden
> sind (WinUSB unter Windows).

WinUSB ist was anderes als libusb. Du musst mit sowas wie Zadig dann das 
Gerät explizit auf libusb zuweisen. Wenn du dagegen WinUSB nimmst, hast 
du die libusb-OS-Abstraktion nicht mehr, die hat ihr eigenes API.

(Letztlich haben die anderen OSe auch wieder ein OS-abhängiges API unter 
der libusb drunter, aber bei denen muss man nicht diesen 
Entweder-oder-Zirkus veranstalten.)

> Du meinst den Default Control Endpoint? Bei meinen Versuchen haben auch
> andere Endpoints in beide Richtungen funktioniert, vielleicht habe ich
> dich aber auch falsch verstanden.

Ist meiner Meinung nach nicht garantiert außer für den default control 
EP.

> Die Geschwindigkeit spielt am Schluss wahrscheinlich auch nicht die
> große Rolle, schneller wie eine Serielle soll es aber schon sein.

Ist die Frage, was "eine Serielle" für dich ist. :-) Schneller als 9600 
Bd wirst du auch mit CDC allemal, auch schneller als 115200 Bd. Seriell 
gibt's aber inzwischen auch gern mit 1 oder 2 MBaud (Ankopplung von MCUs 
über FTDI zum Beispiel).

Harald K. schrieb:
> Wie gesagt, der eigentliche Treiber ist schon immer vorhanden gewesen
> (usbser.sys)

Aber eben nicht bequem nutzbar, so wie das alle anderen OSe die ganze 
Zeit schon angeboten haben.

Am Ende haben die Leute dann HID gemacht, weil Microsoft ja dort 
gezwungen war, einen offenen Klassentreiber anzubieten – macht sich 
schlecht, wenn man für den Anschluss von Maus oder Tastatur extra erst 
noch ein .inf File installieren muss …

von Thomas Z. (usbman)


Lesenswert?

Maxe schrieb:
> So wie ich das verstehe stellt die CDC-Klasse nur eine paket- oder
> byteweise Punkt-zu-Punkt-Verbindung dar, ich müsste also wieder eine
> Kommunikationsschicht drüberbauen.

Eine solche Kommunikationsschicht brauchst du in jedem Fall, auch wenn 
du dein eigenes Ding machst. Letztendlich ist CDC ja auch nur 2 x Bulk 
ohne irgendwelche Filter. Die Com Schnittstelle entsteht erst viel 
weiter oben in der Treiberschicht. Bautrate und ser. Interface brauchst 
du nicht mal zu implementieren. Dann gehts auch schneller.
Es existiert hier im Forum Code (ursprünglich von W.S.) der das auch für 
den F103 demonstriert. Im OS sind das dann nur noch ReadFile / WriteFile 
Aufrufe.

von Maxe (maxemaxe)


Lesenswert?

Jörg W. schrieb:
> Würde ich nicht machen. Extrawürste sind immer teuer. Aber mach, wenn du
> denkst.

Deswegen frag ich ja hier. Wahrscheinlich ist es am Besten, mal den Code 
von einem OpenSource-Projekt anzuschauen. Stichworte gab es ja schon.

>> Es scheint, dass LibUSB-Treiber bei aktuellen Systemn auch vorhanden
>> sind (WinUSB unter Windows).
>
> WinUSB ist was anderes als libusb. Du musst mit sowas wie Zadig dann das
> Gerät explizit auf libusb zuweisen. Wenn du dagegen WinUSB nimmst, hast
> du die libusb-OS-Abstraktion nicht mehr, die hat ihr eigenes API.

LibUSB kann wohl WinUSB nutzen. Ich habe auch Zadig benutzt, die 
WinUSB-Erkennung soll aber auch über einen speziellen Deskriptor 
funktionieren.

> Ist die Frage, was "eine Serielle" für dich ist. :-) Schneller als 9600
> Bd wirst du auch mit CDC allemal, auch schneller als 115200 Bd. Seriell
> gibt's aber inzwischen auch gern mit 1 oder 2 MBaud (Ankopplung von MCUs
> über FTDI zum Beispiel).

Mir gings ja nicht um CDC, dass das schnell ist, ist klar.


Thomas Z. schrieb:
> Eine solche Kommunikationsschicht brauchst du in jedem Fall, auch wenn
> du dein eigenes Ding machst.
Ich dachte eben man benutzt dafür die Request-Parameter. Aber 
anscheinend ist das eher für 'offizielle' Anfragen üblich, also von 
definierten Geräteklassen.

> Es existiert hier im Forum Code (ursprünglich von W.S.) der das auch für
> den F103 demonstriert. Im OS sind das dann nur noch ReadFile / WriteFile
> Aufrufe.

Danke, da such ich auch mal danach.

von Thomas Z. (usbman)


Lesenswert?

Maxe schrieb:
> LibUSB kann wohl WinUSB nutzen. Ich habe auch Zadig benutzt, die
> WinUSB-Erkennung soll aber auch über einen speziellen Deskriptor
> funktionieren.

https://www.mikrocontroller.net/articles/USB-Tutorial_mit_STM32#Konfiguration_der_PC-Seite

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.