Forum: Mikrocontroller und Digitale Elektronik USB CDC mit CUBE und SW STM32


von Hans-Georg L. (h-g-l)


Lesenswert?

Mein DDS-Ad9910 Board aus China ist angekommen und ich würde es gerne 
mit einem STM32F103 ansteuern. Dazu habe ich mit CubeMX und SW STM32 ein 
Projekt mit USB-CDC generiert. Beide Programme sagen sie wären auf dem 
neuesten Stand. Das Projekt kompiliert und die SPI und I2C Schnitstelle 
funktionieren. Das Ansteuerprogramm dazu läuft unter Windows 7 und ich 
schicke im Moment zum Testen Strings über USB an den STM32F103 und gebe 
das empfangene Paket in "CDC_Receive_FS" direkt an das Display über I2C 
weiter. An den STM32F103 hängt noch ein Nucleo64 über SWD zum 
Programmieren und Debuggen. Der STM32F103 meldet sich im Gerätemanager 
als Virtueller COM Port, lässt sich öffen und das USB Monitorprogramm 
zeigt an das richtig enumeriert wird und meine Strings abgeschickt 
werden. Manchmal funktioniert es für ein oder zwei Strings aber dann 
spätestens hängt sich der STM32F103 auf. Debuggen funktioniert überhaupt 
nicht da wird das Device nicht mal erkannt.
Alles was ich bisher im Internet und hier gelesen habe ist entweder 
älter und trifft nicht auf den generierten Quellcode zu.
Hier liest man immer wieder das Die HAL Probleme hat.
Stimmt das auch noch für die aktuelle Version ?.
Oder ist an der Geschichte den USB Stack grösser machen was dran ?

Den falschen Pullup Widerstand an der D+ Leitung habe ich übrigends bei 
dem China Bluepill Board von 10k auf 1,5k geändert daran sollte es also 
auch nicht liegen.

von Hans-Georg L. (h-g-l)


Lesenswert?

Im generierten Code sind die Sende/Empfangsbuffer auf 4 gesetzt nach 
erhöhen auf 64 funktionierts ....
Man muss nur noch erraten das uint8_t* Buf ein Zeiger auf UserRxBufferFS 
ist. Wenn der Buffer kleiner als das Packet ist wird er scheinbar 
gnadenlos überbügelt ....

Generierter Code "usbd_cdc_if.c":
1
#define APP_RX_DATA_SIZE  4
2
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
3
4
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
5
{
6
  /* USER CODE BEGIN 6 */
7
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
8
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
9
10
  return (USBD_OK);
11
  /* USER CODE END 6 */ 
12
}

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hans-Georg L. schrieb:
> Debuggen funktioniert überhaupt
> nicht da wird das Device nicht mal erkannt.
Das ist normal, bei den Standard Requests gibt es enge Timeouts. Ist die 
Enumeration aber erstmal vollständig, kann man das Device durchaus 
anhalten - dann kommen nur noch Interrupts, wenn Nutzdaten übertragen 
wurden.

Hans-Georg L. schrieb:
> Wenn der Buffer kleiner als das Packet ist wird er scheinbar
> gnadenlos überbügelt ....
Richtig, das muss auch so sein, denn ein Usb Device muss immer dazu in 
der Lage sein, Pakete in der Größe wMaxPacketSize aus dem Endpoint 
Deskriptor zu empfangen. Wenn man der Hardware im USB_COUNTn_RX Register 
eine kleinere als die max. Paketgröße einstellt, wird gar nichts mehr 
empfangen (Gerät sendet immer NAK).

Um ein bisschen Werbung zu machen: Ich habe unter 
USB-Tutorial mit STM32 auch eine CDC-Implementierung mit 
detaillierter Erläuterung, die ich grad noch ausbaue...

von Hans-Georg L. (h-g-l)


Lesenswert?

Niklas G. schrieb:
> Hans-Georg L. schrieb:
>> Wenn der Buffer kleiner als das Packet ist wird er scheinbar
>> gnadenlos überbügelt ....
> Richtig, das muss auch so sein, denn ein Usb Device muss immer dazu in
> der Lage sein, Pakete in der Größe wMaxPacketSize aus dem Endpoint
> Deskriptor zu empfangen. Wenn man der Hardware im USB_COUNTn_RX Register
> eine kleinere als die max. Paketgröße einstellt, wird gar nichts mehr
> empfangen (Gerät sendet immer NAK).
>
Das sollten doch auch die Entwickler der HAL und CubeMX wissen .....

Vielleicht kann dein Tutorial denen auch helfen ;-)

Ich werde es auch mal lesen aber im Moment will ich erst mal mein AD9910 
Board zum laufen bringen. Optimieren kann man immer noch.

von Hans-Georg L. (h-g-l)


Lesenswert?

Mal weiter geforscht ..,
Bei der Konfiguration der Endpoints und Descriptoren werden die beiden 
Konstanten CDC_DATA_FS_IN_PACKET_SIZE und CDC_DATA_FS_OUT_PACKET_SIZE 
benutzt.

Deshalb ist es am geschicktesten die auch zu verwenden und ich habe bei 
mir direkt das CubeMX template entsprechend gefixed. Unter Windows zu 
finden unter:
C:\Program 
Files\STMicroelectronics\STM32Cube\STM32CubeMX\db\templates\usbd_cdc_if_ 
c.ftl

Wenn man unbedingt auch High Speed CDC machen will kann man das auch 
noch mit den Konstanten CDC_DATA_HS_IN_PACKET_SIZE und 
DC_DATA_HS_OUT_PACKET_SIZE   und #ifdef erweitern.

@ Niklas Gürtler
Ich habe mal dein Tutorial überflogen ...
STM32 HAL Code habe ich direkt nicht gefunden und unter Windows benutze 
ich:
 CreateFile(portName,  .... );
Keine usblib, keine winusb, kein extra Teiber, nix ...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hans-Georg L. schrieb:
> STM32 HAL Code habe ich direkt nicht gefunden und unter Windows benutze
> ich:
Ja das war Absicht, es ging darum die HAL zu vermeiden, um ein besseres 
Verständnis für die Abläufe zu bekommen. Eigentlich ist das gar nicht 
so kompliziert, braucht nur etwas an Verständnis und Vorarbeit, aber 
die 4 Abstraktionsebenen in der HAL fördern die Lesbarkeit nicht 
besonders...

Hans-Georg L. schrieb:
> CreateFile(portName,  .... );
> Keine usblib, keine winusb, kein extra Teiber, nix ...
Ja, funktioniert aber eben nur mit virtuellen Serial-Ports. Das 
Bestimmen des "portName" ist schon das erste Problem, weil man dem nicht 
so wirklich ansehen kann, welcher Port welches Gerät ist (siehe z.B. 
Beitrag "Zuweisung COM Port zu USB Gerät" ). Die Nutzung von 
libusb+WinUSB ist unwesentlich komplizierter und vermeidet dieses und 
andere Probleme. Dafür kann man so ggf. Software nutzen die auf alte 
Geräte mit Serial-Port ausgelegt ist.

Beitrag #5222952 wurde von einem Moderator gelöscht.
von Hans-Georg L. (h-g-l)


Lesenswert?

Niklas G. schrieb:
> Hans-Georg L. schrieb:
>> CreateFile(portName,  .... );
>> Keine usblib, keine winusb, kein extra Teiber, nix ...
> Ja, funktioniert aber eben nur mit virtuellen Serial-Ports. Das
> Bestimmen des "portName" ist schon das erste Problem, weil man dem nicht
> so wirklich ansehen kann, welcher Port welches Gerät ist (siehe z.B.
> Beitrag "Zuweisung COM Port zu USB Gerät" ). Die Nutzung von
> libusb+WinUSB ist unwesentlich komplizierter und vermeidet dieses und
> andere Probleme. Dafür kann man so ggf. Software nutzen die auf alte
> Geräte mit Serial-Port ausgelegt ist.

Natürlich funktioniert CreateFile auch mit Hardware Comports es gibt 
noch gnügend Maschinen mit Windows NT4,CE und XPEmbedded die wunderbar 
damit laufen.
Wenn ich Informationen über ein Device möchte benutze ich die setupapi 
von Windows.

von Stefan F. (Gast)


Lesenswert?

> Um ein bisschen Werbung zu machen: Ich habe unter
> USB-Tutorial mit STM32 auch eine CDC-Implementierung mit
> detaillierter Erläuterung, die ich grad noch ausbaue...

Großartig, endlich mal etwas, das nicht von der HAL abhängt. Das muss 
ich mir mal anschauen, wenn ich Zeit habe. Vor einer Woche wäre es 
besser gewesen, aber jetzt ist mein Urlaub zu ende. Jedenfalls kommt das 
in meine Bookmarks. Ich hoffe, der Artikel setzt keine Detail-Kenntnisse 
zu USB voraus.

von Niklas Gürtler (Gast)


Lesenswert?

Hans-Georg L. schrieb:
> Natürlich funktioniert CreateFile auch mit Hardware Comports

Ja natürlich. Ich meinte, es funktioniert nicht mit USB Geräten, welche 
nicht als COM Port definiert sind. Der virtuelle COM Port ist schon eine 
Krücke, die man nicht unbedingt braucht... libusb_open statt CreateFile 
ist jetzt auch nicht viel schlimmer. Über libusb hat man genauere 
Kontrolle über die USB Transfers, kann z.B. Control Requests senden.

Stefan U. schrieb:
> Großartig, endlich mal etwas, das nicht von der HAL abhängt
So war das gedacht ;-)

Stefan U. schrieb:
> Ich hoffe, der Artikel setzt keine Detail-Kenntnisse zu USB voraus.
Ich habe mich bemüht alles nötige kurz zu erläutern. Wenn dennoch etwas 
unverständlich ist, kannst du ja Bescheid geben.

von Mitlesa (Gast)


Lesenswert?

Stefan U. schrieb:
> Großartig, endlich mal etwas, das nicht von der HAL abhängt.

Dafür hängt es jetzt an C++ und Klassen-Programmierung. Keine
guten Voraussetzungen für eine schnelle und einfache
Implementierung. Manche Leute die sich das antun wollen
werden damit nicht glücklich werden. Ich sehe nicht ein dass
man das dadurch wieder verkompliziert. Wenn ich so etwas
kapseln möchte dann geht das auch mit regulären C-Mitteln,
ganz gut, man muss nicht gleich mit Kanonen auf Spatzen
schiessen. Ich als Geschwindigkeits-Fanatiker habe noch
Bedenken ob durch die Klassen-Implementierung da nicht ein
paar (zig) Mikrosekunden verloren gehen (weiss es aber nicht).
Gut, die Verwendung der HAL-Strukturen ist auch nicht von
Effizienz geprägt.

Ich habe aber nichts gegen dieses ausgezeichnete Tutorial
und die Implementierung an sich.

von Stefan F. (Gast)


Lesenswert?

Das C++ Einzug in die Mikrocontroller Programmierung gefunden hat, 
sollte man nicht einfach weg ignorieren. Fortschritt ist nur möglich, 
wenn man ihn zulässt.

Genauso gut könntest du dich beklagen, dass das Tutorial nicht in BASCOM 
geschrieben wurde oder in was-weiss-ich welcher Programmiersprache.

Überlege mal: Sogar Arduino nutzt C++. Das wurde für totale Anfänger 
konzipiert. Und es hat Erfolg, sogar richtig viel davon.

von Mitlesa (Gast)


Lesenswert?

Stefan U. schrieb:
> Genauso gut könntest du dich beklagen, dass das Tutorial nicht in BASCOM
> geschrieben wurde oder in was-weiss-ich welcher Programmiersprache.

Nö. Ich sage nur dass sich die USB Implementierung verkompliziert.
Und es ist eine alte Programmier-Weisheit dass für eine
Geschwindigkeits-optimierte Programmierung die untersten Levels
möglichst effizient arbeiten sollen. Genau deswegen würde ich auch
immer HAL vermeiden wo es nötig ist.

Stefan U. schrieb:
> Überlege mal: Sogar Arduino nutzt C++. Das wurde für totale Anfänger
> konzipiert. Und es hat Erfolg, sogar richtig viel davon.

Das hat deswegen Erfolg weil 99.99% aller (Arduino-) Benutzer von
der Klassen-Programmierung absolut nichts sehen ausser Klassen-
Instanzierung und Methoden aufrufen die im Tutorial stehen.

von Hans-Georg L. (h-g-l)


Lesenswert?

Mitlesa schrieb:
>
> Dafür hängt es jetzt an C++ und Klassen-Programmierung. Keine
> guten Voraussetzungen für eine schnelle und einfache
> Implementierung. Manche Leute die sich das antun wollen
> werden damit nicht glücklich werden. Ich sehe nicht ein dass
> man das dadurch wieder verkompliziert. Wenn ich so etwas
> kapseln möchte dann geht das auch mit regulären C-Mitteln,
> ganz gut, man muss nicht gleich mit Kanonen auf Spatzen
> schiessen. Ich als Geschwindigkeits-Fanatiker habe noch
> Bedenken ob durch die Klassen-Implementierung da nicht ein
> paar (zig) Mikrosekunden verloren gehen (weiss es aber nicht).
> Gut, die Verwendung der HAL-Strukturen ist auch nicht von
> Effizienz geprägt.
>
Mit C++ Metatemplate Programmierung wird alles während der Compilezeit 
berechnet und das ist schneller als die C Implementierung. Die HAL z.b. 
verschwendet dafür Ram und Rechenzeit. Schau dir mal KAVASIR an. 
Allerdings ist das keine leichte Kost und nichts für C+++ Anfänger.
Beispiel: Das setzen von Bits in Registern. Du hast einzelne bits die 
während der Laufzeit verschoben werden und dann verodert und ins 
Register geschrieben werden.
KAVASIR macht diese Bitschieberei während der Compilezeit. Du tauscht 
also längere Compilezeit gegen kürzere Laufzeit und hast eine wesendlich 
bessere Typsicherheit weil jedes einzelne Bit seine Attribute hat. Der 
Compiler meckert dich z.b. an wenn du versuchst ein readonly Bit zu 
schreiben usw.
Ich habe KAVSIR allerdings auch noch nicht real verwendet und kenne auch 
kein Projekt.

von Stefan F. (Gast)


Lesenswert?

Oh Mann, freu dich doch über den tollen Artikel!
Und zeige diese Freude, indem du solche Lapalien einfach für Dich 
behältst.

Wenn eine Frau Dich fragt "Und, wie sehe ich aus?" dann antwortest du 
doch auch nicht "Super, aber ich kann deine Periode riechen".

Es ist ja jetzt nicht so, dass C++ hier ein großes Problem wäre.

Ganz im Gegenteil, jeder der in den vergangenen 20 Jahren Programmieren 
in einer Schule/Uni gelernt hat, ist mit Objektorientierter 
Programmierung vertraut. C wird heute hingegen kaum noch gelehrt.

Schreib es halt um, wie es Dir passt, und veröffentliche deine Variante 
daneben als Alternative!

von Hans-Georg L. (h-g-l)


Lesenswert?

@Niklas
Ich möchte dein Tutorial auf keinem Fall kritisieren ich habe nur bei 
der Programmierung für Windows eine andere Ansicht.

von Mitlesa (Gast)


Lesenswert?

Stefan U. schrieb:
> Oh Mann, freu dich doch über den tollen Artikel!

Ich hoffe du bist des Lesens eines gesamten Beitrags mächtig.
Hier noch einmal ein Auszug den du offensichtlich übersehen hast.

Mitlesa schrieb:
> Ich habe aber nichts gegen dieses ausgezeichnete Tutorial
> und die Implementierung an sich.


Stefan U. schrieb:
> Und zeige diese Freude, indem du solche Lapalien einfach für Dich
> behältst.

Das Thema Meinungsfreiheit scheint dich nicht zu begeistern?
Dann lieber so herumlabern wenn einem die Argumente ausgehen.

von Niklas Gürtler (Gast)


Lesenswert?

Mitlesa schrieb:
> Dafür hängt es jetzt an C++ und Klassen-Programmierung

Es war so klar dass das kommt... Die OOP ist seit 30 Jahren so 
ziemlich das beliebteste Paradigma, wird von den meisten Sprachen 
unterstützt, an allen Unis gelehrt und sollte damit so ziemlich jedem 
bekannt sein. Ich hatte sogar versucht, es erst prozedural zu machen, 
und das Resultat war nicht so schön. Daher fand ich es sehr sinnvoll, 
die einzelnen Teile in Klassen zu kapseln, und nicht 1000 einzeln 
herumschwirrende Funktionen wie in der HAL zu haben. So sollte es 
deutlich übersichtlicher sein. Niemand hindert dich, das Tutorial in C 
ohne Klassen durchzuarbeiten - schreibe statt class halt struct, und 
schau ob der Code besser wird...

Mitlesa schrieb:
> Ich sehe nicht ein dass
> man das dadurch wieder verkompliziert.
Ich finde, es wird weniger kompliziert weil immer klar ist, was wozu 
gehört.

Mitlesa schrieb:
> ob durch die Klassen-Implementierung da nicht ein
> paar (zig) Mikrosekunden verloren gehen (weiss es aber nicht).
Ich habe absichtlich etwas auf Effizienz verzichtet (insbesondere mit 
Hinblick auf Speicher), denn die steht in einem Tutorial mehr so an 
dritter Stelle. Wenn man den USB Teil begriffen hat, kann man das immer 
noch optimieren. Wenn alle 3 COM Ports unter Volllast laufen ist der CPU 
Load immer noch weit unter 1%...

Mitlesa schrieb:
> Ich habe aber nichts gegen dieses ausgezeichnete Tutorial
> und die Implementierung an sich.
Na danke ;-)

Mitlesa schrieb:
> Und es ist eine alte Programmier-Weisheit dass für eine
> Geschwindigkeits-optimierte Programmierung die untersten Levels
> möglichst effizient arbeiten sollen.

Eine andere Weisheit ist, dass man erstmal übersichtlich programmieren 
soll, messen (!) soll ob und wo es zu langsam ist, und nur wo nötig 
optimieren soll.

Übrigens wäre z.B. eine derart komfortable und gleichzeitig effiziente 
Zusammenstellung der USB Deskriptoren in C m.W. nicht möglich, 
insbesondere die UTF-16-Strings. Das wird z.B. in den ST Beispielen mit 
HAL zur Laufzeit umgerechnet - ineffizient und unflexibel, kann 
nämlich nur ASCII.

Hans-Georg L. schrieb:
> Mit C++ Metatemplate Programmierung wird alles während der Compilezeit
> berechnet
Ist aber auch mit Vorsicht zu genießen, das wird schnell sehr 
kompliziert.

Hans-Georg L. schrieb:
> Ich möchte dein Tutorial auf keinem Fall kritisieren ich habe nur bei
> der Programmierung für Windows eine andere Ansicht.

Danke... schau dir das libusb Beispiel einfach mal an, so schlimm ist 
das nicht ;-) und so ganz nebenbei geht der Code dann auch unter Linux.

von Hans-Georg L. (h-g-l)


Lesenswert?

Niklas Gürtler schrieb:

> Hans-Georg L. schrieb:
>> Ich möchte dein Tutorial auf keinem Fall kritisieren ich habe nur bei
>> der Programmierung für Windows eine andere Ansicht.
>
> Danke... schau dir das libusb Beispiel einfach mal an, so schlimm ist
> das nicht ;-) und so ganz nebenbei geht der Code dann auch unter Linux.

Ich schreibe das für mich und für Windows7 und usblib hat mir vor Jahren 
mal den Rechner lahmgelegt weil es sich alles was sich usb nennt unter 
den Nagel gerissen hat und nichts mehr lief. Natürlich keine 
Deinstallation und keine Warnung dabei und ich habe etliche Zeit 
verbraten bis ich alles wieder aus der Registry hatte und das mitten in 
einem Projekt. Für komplexere USB Sachen nehme ich dann lieber WinUsb.

von LSB (Gast)


Lesenswert?

Niklas G. schrieb:

> Um ein bisschen Werbung zu machen: Ich habe unter
> USB-Tutorial mit STM32 auch eine CDC-Implementierung mit
> detaillierter Erläuterung, die ich grad noch ausbaue...

Wieviel kByte/s darf man denn eigentlich von so einem kleinen STM32F103 
erwarten?

Macht die Übertragungsrichtung einen Unterschied?

von Niklas Gürtler (Gast)


Lesenswert?

Hans-Georg L. schrieb:
> usblib hat mir vor Jahren mal den Rechner lahmgelegt weil es sich alles
> was sich usb nennt unter den Nagel gerissen hat
libusb hat sich stark weiterentwickelt. Man braucht den Filter Driver 
nicht mehr installieren, man muss überhaupt nichts mehr mit Admin 
Rechten machen, somit kann es auch nichts mehr kaputt machen ;-) es 
greift einfach nur auf WinUSB (oder eine der Alternativen) zu.

Hans-Georg L. schrieb:
> Für komplexere USB Sachen nehme ich dann lieber WinUsb.
Kann man natürlich auch, aber dann ist's nicht mehr portabel.

LSB schrieb:
> Wieviel kByte/s darf man denn eigentlich von so einem kleinen STM32F103
> erwarten?
Hab's jetzt nicht genau ausprobiert, aber ich denke bei anständiger 
Programmierung (z.B. nutzen des HW Doppel Puffers, nicht im Tutorial 
abgedeckt) sollte man FullSpeed schon auslasten können. Fragt sich 
natürlich, wohin mit so vielen Daten!

LSB schrieb:
> Macht die Übertragungsrichtung einen Unterschied
Eher nicht, funktionieren beide quasi gleich.

von Stefan F. (Gast)


Lesenswert?

> Ich habe aber nichts gegen ... die Implementierung an sich.
> Ich sehe nicht ein dass man das dadurch wieder verkompliziert.
> Das Thema Meinungsfreiheit scheint dich nicht zu begeistern?

Ah ja.

von Jim M. (turboj)


Lesenswert?

LSB schrieb:
> Wieviel kByte/s darf man denn eigentlich von so einem kleinen STM32F103
> erwarten?

Unter optimalen Bedinungen (da zählt der PC ebenfalls) sind die 
1MByte/sec von USB Full speed drin.

Man muss aber relativ große Puffer benutzen.

In die Host->µC Richtung schafft man sehr oft die Weiterverarbeitung der 
Daten nicht mit voller Geschwindigkeit, bzw. hat nicht den RAM für 
größere Puffer frei.

von Stefan F. (Gast)


Lesenswert?

Kannst du deinen Code so umschreiben, dass er mit C++ 11 zufrieden ist? 
Ich frage, weil die System Workbench for STM32 noch kein C++ 17 
unterstützt. Auch nicht, wenn ich den Dialekt manuell einstelle.

(Was mich ein bisschen wundert, denn der Compiler hat die Version 6.3.1)

von Hans-Georg L. (h-g-l)


Lesenswert?

Niklas Gürtler (erlkoenig) hat doch extra einen eigenen Thread dafür 
aufgemacht. Ich finde da ist die Diskussion über das Tutorial und den 
Code dazu besser aufgehoben.

Beitrag "USB-Tutorial mit STM32"

@stefan
Du kannst doch ISO C++ 1y einstellen das entspricht C++14 und da ist die 
Arbeit mit constexpr einfacher wie mit C++11.

von Stefan F. (Gast)


Lesenswert?

> Ich finde da ist die Diskussion über das Tutorial und den
> Code dazu besser aufgehoben.

Ja, ich gehe dort hin.

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.