Forum: Mikrocontroller und Digitale Elektronik STM32 USB Übertragungsproblem mit Code von S.F.


von Alex (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Community!

Ich hab seit längerem eine Hardware mit einem kleinen STM32F042 zum 
Datenerfassen via USB (VCP) laufen.
Über den USB werden kleine Datenpakete (Messwerte, wenige Bytes) etwa im
Sekundentakt übertragen. Zu Konfigurationszwecken gibt es auch
ein paar Parameter die über Terminal eingestellt werden können. Ist aber
alles nicht Zeitkritisch.
Hab mit eurer (vor allem mit W.S. und Stefan Frings Hilfe, deren Code 
ich auch verwende (VIELEN DANK !!!!!!)) den USB hinbekommen.

Beitrag "STM32 USB init problem mit Kompaktcode von W.S."

Jetzt hab ich wieder ein Problem, bei dem ich nicht weiterkomme:

Ich hab mehrere von diesen USB-Datenerfassungsmodulen gebaut, und hab 
schon mehrmals beobachtet, dass manche Exemplare komisches Verhalten 
zeigen, wenn man vom PC Befehle zum STM schickt.

Aktuell hab ich ein Exemplar, das reagiert einfach garnicht auf Befehle.
Reproduzierbar auf verschiedenen PCs, Win7, Win10, Linux.
Die Daten vom STM kommen im Sekundentakt zum PC wie sie sollen (ist 
default).
Hab mit wireshark die Pakete von einem 'guten' (Bild links) und dem 
'schlechten' (Bild rechts) Modul aufgenommen.
Ich sende vom Host aus jeweils den Befehl 'stop<CRLF>', beim 
'schlechten' Modul wird offenbar das Paket nochmals gesendet aber nicht 
mehr bestätigt. Die Datenpakete kommen munter weiter, während beim 
'guten' das Senden gestoppt wird.

An was könnte das liegen?

Viele Grüße,
Alex

von Alex (Gast)


Lesenswert?

Ich hab mir die Pakete (und den Unterschied) mal genauer angesehen. In 
dem ACK-Paket sind bei dem nicht funktionierenden STM zwei Bytes 
verändert, die beim anderen gleich bleiben:
1
Der 'schlechte' :
2
0000   1b 00 a0 a9 44 98 0f de ff ff 00 00 00 00 09 00   ....D...........
3
0010   00 01 00 05 00 02 03 06 00 00 00 73 74 6f 70 0d   ...........stop.
4
0020   0a                                                .
5
Antwort:                             VV       VV
6
0000   1b 00 a0 a9 44 98 0f de ff ff 04 00 00 c0 09 00   ....D...........
7
0010   01 01 00 05 00 02 03 00 00 00 00                  ...........
8
9
Der 'gute' :
10
0000   1b 00 60 07 77 95 0f de ff ff 00 00 00 00 09 00   ..`.w...........
11
0010   00 01 00 06 00 02 03 06 00 00 00 73 74 6f 70 0d   ...........stop.
12
0020   0a                                         .
13
Antwort
14
0000   1b 00 60 07 77 95 0f de ff ff 00 00 00 00 09 00   ..`.w...........
15
0010   01 01 00 06 00 02 03 00 00 00 00                  ...........
Leider bin ich (mangels C-Erfahrung) offenbar nicht in der Lage, in der 
usb.c von S.F. den Codeteil zu finden, der dieses ACK erzeugt.
Hat schon mal jemand so ein Problem gehabt?

von Alex (Gast)


Lesenswert?

Was sind das für Daten in dem Paket?

Am Anfang des Pakets sollte ja das PID-Byte gesendet werden, bei dem die 
4 LSBs invers zu den 4 MSBs sind. Das ist aber bei 0x1b garnicht der 
Fall.

Auch ist am Ende kein CRC bzw. EOF angehängt.
Damit zeigt Wireshark offenbar die reinen nettoDaten.
Aber warum ist das dann in den AXK-Paketen auch drinnen?
Die sollten ja keine Daten beinhalten.

Sämtliche erklärungen in der USB-Literatur die ich bisher durchgekaut 
habe, beschäftigens sich nur mit dem Paketaufbau rund um die Daten.
Das passt für mich hinten und vorne nicht zusammen...

von Stefan F. (Gast)


Lesenswert?

Im Februar/März 2020 wurde hier ein Problem im Puffer diskutiert.
Beitrag "USB CDC von Stefan Frings und WS"

Ich hatte mich mangels technischem Verständnis aus der Diskussion 
weitgehend heraus gehalten, aber am Ende den Lösungsvorschlag in meinen 
Code übernommen. Allerdings hatte ich seit dem keinen konkrete 
Anwendungsfall dafür, er ist also nur sehr oberflächlich getestet.

Die Version auf meiner Homepage ist vom 12.03.2020, danach habe ich 
nichts mehr verändert. http://stefanfrings.de/stm32/stm32f1.html#usb

von Alex (Gast)


Lesenswert?

Hallo Stefan,

Den thread hab ich schon gefunden, allerdings nicht im Detail 
durchgearbeitet.
Ich hab aber im Zuge der Fehlersuche das Projekt auf deine neue Version 
umgestellt. Das hat aber am Verhalten nichts verändert.

Ich würde daher sagen, dass es unwahrscheinlich ist, dass das ein Bug in 
deiner neuen Version ist.

Danke und LG,
Alex

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Ich würde daher sagen, dass es unwahrscheinlich ist, dass das ein Bug in
> deiner neuen Version ist.

Es könnte allerdings dennoch ein alter Bug in dem Code sein. Oder ein 
Seiteneffekt von einem Fehler der ganz woanders versteckt ist.

Wenn dir da jemand helfen kann, dass wohl am ehesten Niklas G. 
Allerdings hat der wenig Freude am Code von W.S.

Vielleicht ist es besser, die Cube HAL zu benutzen oder das Ganze auf 
dem Beispiel von Niklas neu auf zu bauen. Der hilft dir dann bestimmt 
gerne weiter. 
https://www.mikrocontroller.net/articles/USB-Tutorial_mit_STM32

von Thomas Z. (usbman)


Lesenswert?

Eine Erklärung warum das Packet im Fehlerfall doppelt kommt wäre zum 
Beispiel ein falsch gesetztes ToggleBit beim Transfer. Das sollte dann 
aber immer auftreten und nicht nur bei einzelnen Devices.

Beschreibe doch Mal was du auf rs232 Ebene verschickst, bzw wie die 
Messpackete aussehen.

von Alex (Gast)


Lesenswert?

Die Pakete sind extrem simpel
Daten zum Host:
'Sensor1: 24.32°C<RCLF>'
So ein Datum kommt etwa alle Sekunden.

Daten vom Host:
'stop<CRLF>' stoppt die Messungen
'start<RCLF>' startet sie wieder

Es gibt noch einige Zusatzbefehle zu Konfiguration usw., aber das spielt 
hier eigentlich keine Rolle.

Entscheiden ist, das auf ein 'stop<CRLF>' offenbar eine fehlerhafte 
Antwort folgt, und das Paket dann nochmal gesendet wird.
Das wird dann aber vom STM ignoriert.

Wenn ich nicht aus dem Terminalprogramm (HTerm) sende, sondern z.B. aus 
Matlab (Messdatenauswertung), dann erkennt das Programm am PC das das 
Senden nicht möglich war.
Der PCseitige Treiber kriegt das also mit.

Alex

von Alex (Gast)


Lesenswert?

ersetze Tippfehler RCLF -> CRLF

von Peter Z. (hangloose)


Lesenswert?

Ich verwende den STM32CubeMX HAL USB Code.
Sehr einfach zum einbinden und funktioniert in meinem Fall
ohne Probleme.

von Alex (Gast)


Lesenswert?

Am Anfang hatte ich auch die HAL CDC in Verwendung, allerdings braucht 
die leider sehr viel Speicher, weshalb ich auf die schlankere 
Implementierung von W.S./S.F. gewechselt habe.

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> Entscheiden ist, das auf ein 'stop' offenbar eine fehlerhafte Antwort
> folgt, und das Paket dann nochmal gesendet wird.
> Das wird dann aber vom STM ignoriert.

nun tatsächlich ist es so, dass der Out Ep zb auf NAK stehen könnte dann 
würde der Host das einfach etwas später noch mal probieren.

Dieser 2te Transfer dürfte dann mit STALL beantwortet werden.
Begründung: Ein dauerhaftes NAK würde in einem Timeout enden, d.h. du 
würdest viel mehr Outs sehen.

Probier mal aus was danach passiert. Sende einfach deinen stop nochmal. 
Falls der EP auf STALL steht dürfte nichts mehr ankommen.

Sind  GetFeature/SetFeature und GetStatus für deine EPs korrekt 
implementiert?

von dummschwaetzer (Gast)


Lesenswert?

Taktprobleme? USB soll ja zimlich zeitkritisch sein. Wie erzeugen deine 
STM32F042 den internen USB-Takt?

von Alex (Gast)


Lesenswert?

Hallo Thomas Z.
Gute Idee, hatte ich noch nicht näher untersucht.

Wenn ich den Befehl wiederhole, wird er tatsächlich nicht mehr 
geschickt.
Wenn ich dann den VCP schließe kommt ein Bulk-Out Paket von EP2 (#2194), 
von dem ich vermute, dass es zu dem Paket #1909 gehört. Ist das 
plausibel?

Wenn ich den VCP erneut öffne, und den Befehl erneut schicke, wird er 
nur 1mal gesendet, beim Wiederholen nicht mehr. Beim Schließen kommt 
wieder ein Paket:
1
+ VPC öffnen
2
+ Befehl senden
3
#       time         src      dst     len   info
4
1907    43.156065    host     1.9.2   33    URB_BULK out 'befehl'
5
1908    43.156174    1.9.2    host    27    URB_BULK out
6
1909    43.156207    host     1.9.2   33    URB_BULK out 'befehl'
7
8
+ Befehl nochmal senden
9
<kein traffic>
10
+ VCP schließen
11
#       time         src      dst     len   info
12
2194    59.853448    1.9.2    host    27    URB_BULK out
13
14
+ VCP öffnen
15
+ Befehl senden
16
#       time         src      dst     len   info
17
2341    79.436340    host     1.9.2   33    URB_BULK out 'befehl'
18
19
+ Befehl nochmal senden
20
<kein traffic>
21
22
+ VCP schließen
23
#       time         src      dst     len   info
24
2372    87.408990    1.9.2    host    27    URB_BULK out

Was ich mit dieser Info jetzt anfange, weiß ich allerdings nicht 
wirklich.



Taktproblem würd ich ausschließen, weil
1) die Übertragung an sich ja funktioniert.
2) Takt wird mit CRS auf den USB synronisiert.

Alex

von Thomas Z. (usbman)


Lesenswert?

Da ist irgendwas im Buffer Code was blockiert. Stefan liegt da mit 
seiner Vermutung schon richtig.
Besorg dir mal UsbCV bei usb.org. Das Tool ist zwar etwas wackelig aber 
hilfreich. Zumindest die Chapter9 Tests sollten ohne Fehler oder 
Warnings durchlaufen. Ich selbst setze den Code von WS nicht ein, hab 
den deshalb nur überflogen. Ich benutze meine eigenen Implementation 
bzw. auf ARM den 3fach Code von Niklas.

von Alex (Gast)


Lesenswert?

Moin Thomas,

mit UsbCV werd ich testen (sicherheitshalber auf einem anderen Rechner, 
das Installationsprogramm warnt deutlich davor, dass man sich damit 
Keyboard/Maus vom System wegschießen kann).

Weist du, wie diese Pakete aufgebaut sind?
Bzw. wo es dazu eine überschaubare Doku gibt?
Was ist in den (ersten) 24 Bytes des Pakets drinnen?

Alex

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Mal meine fehlergkorrigierte Version von W.S.' Code probiert?

https://github.com/Erlkoenig90/WSusb

Es ist ziemlich umständlich ASCII-Befehle in USB-Pakete einzupacken. 
Wäre es nicht einfacher, SETUP-Pakete mit den richtigen Codes über den 
Control Endpoint zu schicken? Das lässt sich auch leichter verarbeiten 
und spart das Parsen.

Ansonsten würde ich auf ein Softwareproblem tippen. Breakpoint in den 
USB-IRQ setzen und schauen was beim Empfang des Pakets passiert bzw. die 
Empfangs-Routine durchsteppen.

Sonst kann ich natürlich nur empfehlen, meinen USB-Code zu verwenden, 
der hat solche Probleme bisher nicht...

von Alex (Gast)


Lesenswert?

Hallo Niklas,

deine Version kannt ich bisher nicht, werd ich aber definitiv versuchen 
einzubauen.

Das mit den ASCII-Befehlen hat den simplen Grund, ohne irgendeine 
spezielle Software auf der PC-Seite auszukommen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Das mit den ASCII-Befehlen hat den simplen Grund, ohne irgendeine
> spezielle Software auf der PC-Seite auszukommen.

Damit macht man es sich aber letztlich komplizierter. Mit der direkten 
Ansteuerung des USB-Protokolls z.B. per libusb erspart man sich eine 
Menge Fehlerpotential. Dass die Befehle wie 'stop<CRLF>' als ein 
USB-Paket ankommen ist ja auch keineswegs gesagt, der Host-Treiber für 
CDC-ACM kann die Texte beliebig zerstückeln oder puffern.

PS: Wieso muss man die Messung überhaupt stoppen können? Man könnte auch 
die USB-Standby-Funktionalität implementieren, sodass der Host das Gerät 
zum Energie sparen abschalten kann, es aber ansonsten einfach immer 
läuft.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> das Installationsprogramm warnt deutlich davor, dass man sich damit
> Keyboard/Maus vom System wegschießen kann).

Die Warnung betrifft vor allem PCs bei denen Maus und KB über USB 
angeschlossen ist. Das Tool schaltet den Hostcontroller in einen spez. 
Test Mode weshalb danach keines der am Host angeschlossenen Geräte 
normal funktioniert. Danach werden je nach Auswahl diverse Kommandos 
abgesetzt und die Ergebnisse ausgewertet. Beim Beenden wird dann der der 
HostController wieder zurückgeschaltet. Auf einem Laptop sollte es kein 
Problem geben da Maus und KB üblicherweise nicht an USB hängen.

Ich versuche damit gerade ein MSC Device spec konform zu bekommen. Deine 
Frage zu den 24 Bytes kann ich nicht beantworten, glaube aber dass das 
irgendwelche Pointer (urb, Sequenznummern usw) sind, die nichts mit den 
Ep buffern zu tun haben.

von Thomas Z. (usbman)



Lesenswert?

hier mal 2 Beispiele für solche reports von UsbCV. Die stammen von 
meinem Compound Device was MSC und VCP können wird.

: Bearbeitet durch User
von Alex (Gast)


Lesenswert?

Hab jetzt mal schnell das usbCV auf einem 'guten' und dem 'schlechten' 
STM durchlaufenlassen. Hab zuvor die usb.c auf die Neue Version von 
Niklas umgemünzt.

Sowohl mit der alten Software (von S.F.) als auch mit der neuen von 
Niklas kommt ein Fehler beim
Halt Endpoint Test.

Für mich ergibt sich daraus die Vermutung, dass es an der Anpassung an 
meinen STM32F042-Controller liegt.



Zum ASCII:
- der USB Treiber darf die Befehle zerpflücken (tut er auch), das macht 
aber nix.
- Das device muss ohne spezielle Treiber auf verschiedenen Plattformen 
unkompliziert laufen -> VCP ist die beste Möglichkeit dafür.
- das 'stop' ist nur ein möglicher Befehl, und Befehle braucht es für 
die Funktionalität die ich benötige.

Alex

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> - Das device muss ohne spezielle Treiber auf verschiedenen Plattformen
> unkompliziert laufen -> VCP ist die beste Möglichkeit dafür.

Bei Verwendung von libusb braucht es keine Treiber.

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> Sowohl mit der alten Software (von S.F.) als auch mit der neuen von
> Niklas kommt ein Fehler beim
> Halt Endpoint Test.

Dann gibt es einen Bug beim Get/SetFeature bzw GetStatus liefert nicht 
das erwartete Ergebnis. (STALL oder 0). Das hatte ich schon weiter oben 
angesprochen.

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Für mich ergibt sich daraus die Vermutung, dass es an der Anpassung an
> meinen STM32F042-Controller liegt.

Falls du in der Nähe von Düsseldorf wohnst könnte ich dir das Nucleo 
L073 Board ausleihen, mit dem ich damals getestet hatte.

von Alex (Gast)


Lesenswert?

Danke für euren Input Leute, ich komm nicht hinterher :-)

+ Zum Thema VCP / libUsb:
So wie die Devices jetzt sind, kann ich sie ohne Beschreibung oder 
sonstiger Info jemandem (z.B. einem Studenten) in die Hand drücken, und 
der kann damit was anfangen. Alles was er dazu braucht ist ein 
Terminalprogramm. Und das kriegt erfahrungsgemäß jeder hin. Mit allen 
anderen Lösungen muss auf dem Host-System irgendetwas 
implementiert/installiert werden. Und dieses irgendwas wird sich im Lauf 
der Zeit ändern. Damit hab ich permanent Support-Aufwand, den ich nicht 
haben will. Bei einem VCP ist das nicht nötig. Daher ist das aus meiner 
Sicht die beste Lösung.


+ Halt Endpoint Test
Der sollte eigentlich mit dem Code von Niklas (und auch S.F. Version von 
W.S. code) funktionieren.
Um auszuschließen, dass das an meinen Zusatzfunktionen liegt, werd ich 
morgen mal eine Minimalversion auf dem STM32F042 laufen lassen und den 
Test damit wiederholen.

Die Anpassungen an den Controller hat sich bei mir auf UMEM_SHIFT=0 und 
die USB_IRQ_NUMBER=31 beschränkt. Hab ich da ev. was übersehen?


+ Das Übertragungsproblem
Ist möglicherweise von dem Halt Endpoint Problem unabhängig, weil der 
Halt Endpoint Test auch bei jenen Modulen fehlschlägt, die für mich 
einwandfrei funktionieren.
Das Suchen dieses Fehlers ist auch etwas knifflig, weil ich das nicht 
auf einer anderen Hardware nachstellen kann.
(Danke Stefan für das großzügige Angebot, aber ich sitz in Österreich 
;-))


> Dann gibt es einen Bug beim Get/SetFeature bzw GetStatus liefert nicht
> das erwartete Ergebnis. (STALL oder 0). Das hatte ich schon weiter oben
> angesprochen.

Ich bin nicht sicher, ob ich das richtig interpretiere, aber in

void DoGetStatus(void)

hab ich folgende Zeile gefunden:
1
if ((EP == logEpCtrl) || (EP == logEpInt) || (EP == logEpBulkIn) || (EP == logEpBulkIn))

Sollte da vielleicht einer der Bulks ein BulkOut sein?


Alex

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Die Anpassungen an den Controller hat sich bei mir auf UMEM_SHIFT=0 und
> die USB_IRQ_NUMBER=31 beschränkt. Hab ich da ev. was übersehen?

UMEM_FAKEWIDTH vielleicht? Obwohl: Wenn irgendeiner der 
Konfigurationsparameter falsch wäre, würde wahrscheinlich gar nichts 
funktionieren.

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> hab ich folgende Zeile gefunden:
> if ((EP == logEpCtrl) || (EP == logEpInt) || (EP == logEpBulkIn) || (EP
> == logEpBulkIn))
>
> Sollte da vielleicht einer der Bulks ein BulkOut sein?

Genau so ist es.. Macht ja nicht soviel Sinn den gleichen Ep 2 mal 
abzufragen. Die Frage ist halt auch ob in den logxxx wirklich Stall 
conditions gespeichert sind. Mein eigener Code ist an der Stelle 
wesentlich aufwändiger.

Ob das allerdings bei deinem Übertragungsproblem hilft ist fraglich.

von temp (Gast)


Lesenswert?

Alex schrieb:
> 2) Takt wird mit CRS auf den USB synronisiert.

Du hast keinen Quarz dran? Dann wäre es das erste was ich probieren 
würde dem ganzen einen Quarz zu spendieren. Noch dazu wenn manche deiner 
Module gehen und ander nicht oder nicht immer. Das schreit ja förmlich 
nach Ursachen bei denen Toleranzen(oder jitter) eine Rolle spielen. Und 
wenn es nur darum geht andere Ursachen auszuschließen.
Ich benutze den Grundcode mit vielen STM32F103, STM32F3x3, STM32L151 ...
Oft als USB-CAN Interface mit SLCAN. Das entspricht ja so in etwa dem 
was du machst, nur mit viel mehr Last.
Gut den F042 hatte ich noch nicht. Aber immer mit Quarz.
Und es kann bei Taktproblemem ja durchaus sein, dass die Richtung zum PC 
funktioniert und die ander nicht(immer).

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Alex schrieb:
> Bei einem VCP ist das nicht nötig. Daher ist das aus meiner
> Sicht die beste Lösung.

Bei Serial-Ports kommt auch Support-Aufwand:
- Welchen Port soll ich auswählen?
- Welche Baudrate und welches Frame-Format wähle ich aus?
- Was mache ich wenn der Linux ModemManager an neu angeschlossene 
Serial-Ports automatisch Nachrichten sendet weil es sie für ein Modem 
hält?
- Wie verhindere ich dass Windows das Serial-Gerät als serielle Maus 
erkennt?
- Soll ich das Echo ein/ausschalten?
- Welchen Zeilenumbruch soll ich verwenden?

Und ja, auch Fangfragen sind Aufwand ;-)

Alex schrieb:
> Mit allen
> anderen Lösungen muss auf dem Host-System irgendetwas
> implementiert/installiert werden.

Ein Programm, welches mittels libusb und WinUSB auf Geräte zugreift, die 
als WinUSB deklariert sind, braucht keinerlei 
Installation/Konfiguration. Gerät anschließen, Programm draufkopieren & 
starten, fertig. Weniger Aufwand als ein Terminalprogramm (Port-Auswahl 
usw.). Unter Linux brauchts die WinUSB-Deklaration natürlich nicht, da 
geht es einfach so, aber sie stört auch nicht.

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Ein Programm, welches mittels libusb und WinUSB auf Geräte zugreift, die
> als WinUSB deklariert sind, braucht keinerlei
> Installation/Konfiguration. Gerät anschließen, Programm draufkopieren &
> starten, fertig. Weniger Aufwand als ein Terminalprogramm (Port-Auswahl
> usw.). Unter Linux brauchts die WinUSB-Deklaration natürlich nicht, da
> geht es einfach so, aber sie stört auch nicht.

Da magst du zwar Recht haben, nur spielt das für die Probleme hier keine 
Rolle. Im Gegenteil, dann hätten wir gleich mehrerer Baustellen 
gleichzeitig.
Es macht sicher auch einen gewaltigen Unterschied ob das ganze in die 
Großserie geht oder eine kleine Individuallösung ist. Und nicht jeder 
dringt so tief in die USB Materie ein um eine neue Gerätekategorie auf 
der Controllerseite zu implementieren. Deshalb ist ja VCP so beliebt, 
weil man  am reinen USB-Code nichts ändern muss. Es ist schließlich auch 
immer eine Frage des Zeitaufwandes.

von temp (Gast)


Lesenswert?

Ach noch ein Nachtrag. libusb unter Windows ist in meinen Augen eine 
Seuche. Vor allem wenn die Geräte mal mit einer Software und dem 
direkten Windowstreiber spielen soll, und eine andere Software nur 
libusb kann. Dann heißt es jedes mal die Treiber umkonfigurieren. 
Schlimmer geht nimmer. Gerade erst wieder für j-link und OpenOCD 
festgestellt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Es ist schließlich auch
> immer eine Frage des Zeitaufwandes.

Richtig, der ganze Entwicklungsaufwand zur Paket-Anfang/Ende-Erkennung, 
Parsen, ASCII-Formatierung, Pufferung zwischen einzelnen USB-Paketen 
entfällt wenn man keinen VCP nutzt.

USB direkt zu nutzen ist viel einfacher - man hat direkt das Konzept von 
Paketen und kann einfache Transaktionen simpel per SETUP-Paket auf dem 
Control-Channel abhandeln. Wenn man wenig Datenrate hat (wenige Bytes 
etwa im Sekundentakt?) würde es sogar reichen alles per Control Channel 
zu machen, wenn das Gerät nicht selbstständig senden können muss.

Bei mir im Studium hat ein Prof das übrigens genau so gemacht - einen 
PID-Regler auf einem USB-fähigen Mikrocontroller implementiert, der vom 
PC aus per USB mit einer eigenen Anwendung parametrisiert werden konnte. 
Hat super funktioniert.

temp schrieb:
> Vor allem wenn die Geräte mal mit einer Software und dem
> direkten Windowstreiber spielen soll, und eine andere Software nur
> libusb kann.

Für einen VCP hätte man auch keinen eigenen Windows-Treiber, daher keine 
vergleichbare Situation.

temp schrieb:
> Dann heißt es jedes mal die Treiber umkonfigurieren.
> Schlimmer geht nimmer.

Für die libusb+WinUSB Kombination braucht es keine Treiber-Installation 
oder Konfiguration. Windows lädt automatisch den WinUSB-Treiber und es 
funktioniert direkt.

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Für die libusb+WinUSB Kombination braucht es keine Treiber-Installation
> oder Konfiguration. Windows lädt automatisch den WinUSB-Treiber und es
> funktioniert direkt.

Wenn ich meinen j-link in der Segger- oder Crossworks-IDE benutzen will, 
wird der normale jlink-Treiber verwendet. Will ich das Teil unter 
OpenOCD benutzen, muss ich das Gehampele mit Zadig machen damit das 
geht. Danach gehen die IDEs nicht mehr. Das ist Mist. Vor allem weil ich 
bei der Umschalterei seit sehr, sehr langer Zeit mal wieder einen 
Bluescreen gesehen habe.

Was mache ich falsch?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Was mache ich falsch?

Die J-Link Firmware gibt sich nicht als WinUSB Device aus, verwendet 
einen "normalen" Windows-Treiber, und OpenOCD verwendet wohl kein 
WinUSB. Blöd, aber nicht relevant für diesen Thread, weil man für das 
eigene Gerät sowieso keinen normalen Treiber implementieren würde und 
man problemlos den WinUSB-Deskriptor einbauen kann.

Bei Verwendung eines VCP würde man auch keinen eigenen Windows-Treiber 
einbinden der auf Basis des RS232-Protokoll ein eigenes API zu Verfügung 
stellt (geht das überhaupt?) und dann abwechselnd eine Anwendung 
verwenden welche den Port direkt anspricht.

Der normale Windows-Treiber hat den Vorteil dass mehrere Anwendungen 
gleichzeitig drauf zugreifen können (das nutzen die Segger-Tools ja 
auch), aber das geht beim VCP auch nicht.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

temp schrieb:
> Was mache ich falsch?

gar nichts.
Ich stimme mit dir überein, dass Libusb unter Win eher suboptimal ist. 
Win hatte sehr lange Zeit einfach kein Konzept für einen Usermode 
Treiber. Das würde dann durch WinUsb behoben, leider viel zu spät. 
Deshalb hat sich WinUsb bis heute nicht so richtig durchgesetzt. Ich bin 
ehrlich gesagt froh, dass es Zadig gibt.

Ich bin aber auch mit Niklas der Meinung, dass das Kombo Libusb für 
Linux, WinUsb für Win die flexiblere Lösung ist. Unter Win funktioniert 
WinUsb fast wie ein Klassentreiber. Der Anwender braucht sich nie mehr 
um Treiber Installationen kümmern. Das ist VCP ja auch noch unter W7 
immer noch ein Problem.

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Blöd, aber nicht relevant für diesen Thread

Naja, du hattest damit angefangen libusb ins Spiel zu bringen, was für 
diesen Thread ja auch nicht relevant ist. Und ich habe dir nur darauf 
geantwortet, dass ich lieber bei VCP bleibe als mit libusb zu hantieren.

Ich denke wir belassen es dabei und warten mal ob Alex seine Probleme 
lösen kann oder nicht. Ein völlig neuer Ansatz bringt ihn da sicher 
nicht weiter.
Zumal ich bei den STM32F042 mit 32k Flash auch öfters an die Grenzen 
kommen und der verwendete Code hier kleiner ist als alle anderen Libs.

Was noch sehr klein ist ist der USB Teil vom hid-Bootloader:
https://github.com/Serasidis/STM32_HID_Bootloader

Basierend auf dem Code von W.S. habe ich hier auch schon mal ein 
Midi-Interface implementiert:
Beitrag "STM32 USB-MIDI"

Auch dabei kam es zu keinen Problemen die mit denen von Axel zu 
vergleichen waren. Ich denke so lange nicht das Gegenteil bewiesen ist, 
wird der Fehler beim Takt oder einer anderen Stelle liegen aber nicht 
beim Code von W.S., S.F. oder N.G.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Naja, du hattest damit angefangen libusb ins Spiel zu bringen, was für
> diesen Thread ja auch nicht relevant ist.

Ich finde es relevant, weil die libusb+WinUSB Kombo für solche einfachen 
Selbstbau-Geräte perfekt ist.

temp schrieb:
> Und ich habe dir nur darauf
> geantwortet, dass ich lieber bei VCP bleibe als mit libusb zu hantieren.

Aber mit einem Argument welches sich auf normale Windows-Treiber bezieht 
und nicht auf die vorgeschlagene libusb+WinUSB Lösung.

temp schrieb:
> Ein völlig neuer Ansatz bringt ihn da sicher
> nicht weiter.

Ein Ansatz welcher ohne die VCP-Bastelei (insb. mit der davon benötigten 
Pufferverwaltung) und ohne W.S.' Implementation davon auskommt könnte 
ihn durchaus weiter bringen.

von Johannes S. (Gast)


Lesenswert?

der JLink bringt doch einen GDB Server mit, ist OOCD da überhaupt nötig?

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Der normale Windows-Treiber hat den Vorteil dass mehrere Anwendungen
> gleichzeitig drauf zugreifen können (das nutzen die Segger-Tools ja
> auch), aber das geht beim VCP auch nicht.

Was soll da auch sinnvolles dabei rauskommen?

Thomas Z. schrieb:
> Ich bin aber auch mit Niklas der Meinung, dass das Kombo Libusb für
> Linux, WinUsb für Win die flexiblere Lösung ist. Unter Win funktioniert
> WinUsb fast wie ein Klassentreiber. Der Anwender braucht sich nie mehr
> um Treiber Installationen kümmern. Das ist VCP ja auch noch unter W7
> immer noch ein Problem.

Das will ich ja nicht mal in Abrede stellen. Jedenfalls nicht solange 
alle! Programme die es für das jeweilige Gerät gibt diesen Weg benutzen. 
So wie beim SDR-Stick, da stört mich das auch nicht.

Es wäre schön, wenn jemand für den Code von W.S. (oder folgende) mal ein 
Beispiel veröffentlichen würde das den von euch vorgeschlagenen Weg 
benutzt.
So wie ich mit dem MIDI-Beispiel. Danke schon im Voraus an den der es 
macht.

von temp (Gast)


Lesenswert?

Johannes S. schrieb:
> der JLink bringt doch einen GDB Server mit, ist OOCD da überhaupt nötig?

Nein, natürlich nicht. Das war nur ein Beispiel.

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Ein Ansatz welcher ohne die VCP-Bastelei (insb. mit der davon benötigten
> Pufferverwaltung) und ohne W.S.' Implementation davon auskommt könnte
> ihn durchaus weiter bringen.

So wie der Code von W.S. jetzt bei S.F. steht ist er nicht so schlecht, 
dass man ständig davon abraten muss. Deine C++ Implementierung ist auch 
nicht der letzte Schrei und mir persönlich viel zu aufgebläht. Aber was 
soll's, jeder hat seine eigenen Vorlieben und macht seine eigenen 
Erfahrungen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Es wäre schön, wenn jemand für den Code von W.S. (oder folgende) mal ein
> Beispiel veröffentlichen würde das den von euch vorgeschlagenen Weg
> benutzt.

Also einfach nur das Einbauen des WinUSB-Deskriptors und das Entfernen 
des CDC-ACM-Deskriptors? Der PC-Seite ist es egal ob es W.S.' oder mein 
Code ist.

temp schrieb:
> Was soll da auch sinnvolles dabei rauskommen?

Genau so viel wie bei der Idee, dass OpenOCD nicht den J-Link-Treiber 
nutzt. Warum auch immer das so ist...

temp schrieb:
> Das war nur ein Beispiel.

Ein Beispiel wie man etwas auf Basis von Technologie X schlecht umsetzt 
ist kein Grund Technologie X nicht zu nutzen...

temp schrieb:
> So wie der Code von W.S. jetzt bei S.F. steht ist er nicht so schlecht,
> dass man ständig davon abraten muss.

Ich finde das Grundkonzept, mit blockierenden Funktionen 
USB-Datentransfers zu machen ziemlich fragwürdig. Wenn sich da etwas 
verheddert mit anderen Interrupts in der Anwendung ist es gut möglich, 
dass das Programm stecken bleibt. Die Originalversion hat auch einen 
fragwürdigen C-Stil und diverse Bugs; ob es davon nicht noch mehr gibt 
weiß man nicht...

temp schrieb:
> Deine C++ Implementierung ist auch
> nicht der letzte Schrei und mir persönlich viel zu aufgebläht.

Sie blockiert immerhin nicht die main()-Schleife. Was daran aufgebläht 
sein soll weiß ich nicht.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Ich hab mir jetzt nochmal den Code von WS in der Version von Niklas 
näher angesehen. Ich bin mir ziemlich sicher, dass zumindest OnGetStatus 
() im Falle der Enpoints (case 0x82:) keine korrekten Antworten liefert.
Der Requests sollte ja den Zustand des EPs liefern. 1 für STALL 0 für 
UNSTALL.
Der Code liefert aber für gültige Endpoints immer STALL, und wegen des 
copypaste Fehlers beim BulkoutEP immer UNSTALL.
Ich werde versuchen dafür einen Patch einzustellen auch wenn Git noch 
nicht so mein Ding ist.

Ich bin aber immer noch der Meinung, dass dieser Bug nicht ursächlich 
für die Probleme des TO ist

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Ich finde das Grundkonzept, mit blockierenden Funktionen
> USB-Datentransfers zu machen ziemlich fragwürdig. Wenn sich da etwas
> verheddert mit anderen Interrupts in der Anwendung ist es gut möglich,
> dass das Programm stecken bleibt. Die Originalversion hat auch einen
> fragwürdigen C-Stil und diverse Bugs; ob es davon nicht noch mehr gibt
> weiß man nicht...

In ein paar Punkten muss ich dir widersprechen. Es ist nicht das 
Grundkonzept mit blockierenden Funktionen zu arbeiten. Der reine 
USB-Teil arbeitet wie bei dir auch interruptgetrieben. Anderenfalls wäre 
eine main-loop nötig, die es
aber nicht gibt. Die einzige Stelle in der das blockieren kann ist die

bool UsbCharOut(char c)

und die ist ja wohl dem User-Code zuzurechnen und hier nur ein Beispiel. 
Und dass sie blockiert ist da auch nicht nötig, das kann jeder handhaben 
wie er will.

Das mit den Bugs weiß man bei deinem Code auch nicht, und der C-Stil ist 
ja wohl Ansichtssache. Ob dein Code außer für dich für jedermann sofort 
verständlicher ist?

Niklas G. schrieb:
> Also einfach nur das Einbauen des WinUSB-Deskriptors und das Entfernen
> des CDC-ACM-Deskriptors? Der PC-Seite ist es egal ob es W.S.' oder mein
> Code ist.
Und genau das ist schon die Stelle, wo viele scheitern. Die wollen so 
eine Lib benutzen ohne die Deskriptoren jemals verstanden zu haben. Und 
weil das so ist, wird noch so oft VCP verwendet.

Jetzt ist hier aber für mich Schluss mit allen Diskussionen die sich 
nicht mehr um das eigentliche Problem drehen.

von W.S. (Gast)


Lesenswert?

Also Leute, nun habt ihr schon etwa 7 Tage lang hier herumdiskutiert und 
alles sonstige wie Libusb, Zadig, und sonstwas genannt.

Führt das zu etwas? Nö.

Und auch die Ansichten von Niklas: "USB direkt zu nutzen ist viel 
einfacher - man hat direkt das Konzept von Paketen..." sind hier 
überhaupt nicht zielführend, denn das wäre dann eben kein virtueller 
COM-Port mehr, sondern etwas ganz anderes.

Also merkt doch mal, daß der Sinn eines virtuellen COM-Portes eben genau 
darin besteht, daß man eine asynchrone Einzelzeichen-Verbindung von 
einer App auf dem PC bis hin zu einer anderen "App" (sprich Firmware) 
auf einem anderen gerät haben kann, OHNE daß sich die beiden Apps 
darum scheren müßten, wie die Daten zwischendurch transportiert werden. 
Das ist sache des OS und das OS soll das eben so tun, daß die Verbindung 
funktioniert, ohne daß die Apps sich um deren interne Details kümmern 
müssen.

So und wenn ich das hier lese:

Alex schrieb:
> Aktuell hab ich ein Exemplar, das reagiert einfach garnicht auf Befehle.
> Reproduzierbar auf verschiedenen PCs, Win7, Win10, Linux.
> Die Daten vom STM kommen im Sekundentakt zum PC wie sie sollen (ist
> default).

..dann kommt mir der Gedanke, daß die Richtung PC-->µC irgendwie gestört 
ist. Folglich würde ich an einen freien UART des µC mal etwas 
dranhängen, einen anderen Port des PC zum Beispiel, und im µC den 
Datenstrom vom USB-Treiber her auf diesen UART ausgeben, damit man mal 
sehen kann, was da denn  so ankommt. Und das ohne irgendwelche Debugger, 
Usbsniffer etc. und nur mittels der normalen Firmware, damit möglichst 
nichts an unvorhergesehenen Beeinflussungen passieren kann. Dann dürfte 
man ja wohl weiter sehen und dem Problem etwas näher kommen.

Alex schrieb:
> Ich hab mehrere von diesen USB-Datenerfassungsmodulen gebaut, und hab
> schon mehrmals beobachtet, dass manche Exemplare komisches Verhalten
> zeigen, wenn man vom PC Befehle zum STM schickt.

Gegenfrage: hast du in deine Firmware einen kleinen Kommandointerpreter 
eingebaut? Also etwas, das aus den hereinkommenden Einzelzeichen eine 
Kommandozeile aufbaut (und die Zeichen echot) und diese nach einen CR 
oder wenn der Puffer dafür voll ist dann auswertet? Und wenn da etwas 
unverständliches drin steht, einen Fehlertext zurückschickt? Wäre wohl 
hilfreich.


Nochwas:

Alex schrieb:
> hab ich folgende Zeile gefunden:...

Ja, das ist wohl dieses hier (in DoGetStatus):
1
  ...
2
    case 0x82:          /* für einen Endpoint */
3
         if ((EP==logEpCtrl)   ||
4
             (EP==logEpInt)    ||
5
             (EP==logEpBulkIn) ||
6
             (EP==logEpBulkIn))  Buf[0] = 1;
7
         break;
und das ist offensichtlich ein uralter Schreibfehler, der offenbar noch 
niemandem (mich eingeschlossen) aufgefallen ist. Ja, der steht auch 
bei Niklas drin. Ich bin mir aber nicht sicher, ob diese Sequenz 
überhaupt benötigt wird. Vielleicht sollte mal jemand anderes den 
Quelltext nach etwaigen weiteren derartigen Schusselfehlern durchsuchen.

Noch ein Wort zu Niklas' Version: Ich finde es bedenklich, unschön und 
unüberlegt, bei jeder Gelegenheit von der Anwendungsebene aus am 
Interrupt herumzuschalten. Das ist Programmieren mit dem Schmiedehammer. 
Die Cortexe sind 32 Bit Maschinen und da sind Zugriffe auf die Indizes 
allesamt atomar und eine jede Seite ändert NICHTS an dem Index, der ihr 
nicht gehört. Folglich ist all dieses DisableUsbIRQ() etc. nicht 
erforderlich. Auch mit anderen Dingen (UsbActive(), UsbTxFlush()) hat 
sich dieser Treiber vom Prinzip des COM-Ports entfernt und kann in der 
Firmware nicht mehr wirklich genau so wie ein UART benutzt werden. Mir 
wäre das wichtig, aber wer es partout anders halten will, mag es halt 
tun.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Folglich ist all dieses DisableUsbIRQ() etc. nicht
> erforderlich.

Dankeschön. Ich habe das eingebaut weil einige Leute darauf bestanden 
dass es nötig sei, aber auch ich bin immer noch der Meinung, dass das 
Quatsch war. Ich nehme das wieder raus.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

W.S. schrieb:
> Noch ein Wort zu Niklas' Version: Ich finde es bedenklich, unschön und
> unüberlegt, bei jeder Gelegenheit von der Anwendungsebene aus am
> Interrupt herumzuschalten. Das ist Programmieren mit dem Schmiedehammer.

Der eigentliche Fehler ist es, aus der main-Schleife heraus auf die 
Kommunikation zuzugreifen. Würde man das in Interrupts machen, hätte man 
das Problem nicht.

W.S. schrieb:
> Folglich ist all dieses DisableUsbIRQ() etc. nicht
> erforderlich.

In meinem Code werden unter der Interruptsperre jeweils mehrere 
Bedingungen verknüpft. z.B. bei:
1
/* liefert true, wenn noch ein Zeichen in den Tx-Buffer passt */
2
bool UsbTxReady(void)
3
{
4
    DisableUsbIRQ ();
5
    bool res = configurationSet && !suspended && ((txw + 1) & (txLen - 1)) != txr;
6
    EnableUsbIRQ ();
7
8
    return res;
9
}

Ohne die Interruptsperre könnte zwischen dem Auslesen von 
configurationSet und txw o.ä. ein Interrupt kommen.

Bei Sachen wie:
1
/* liefert true, wenn Tx-Buffer leer ist */
2
bool UsbTxEmpty(void)
3
{
4
  DisableUsbIRQ ();
5
    bool res = (txw == txr);
6
    EnableUsbIRQ ();
7
    return res;
8
}
kann es sogar sein dass die Interruptsperre unnötig ist; ich war ehrlich 
gesagt zu faul mir das ganz genau für alle Fälle zu überlegen. Wenn du 
mir genau aufschlüsseln kannst dass das wirklich in allen Funktionen 
unnötig ist, kann ich das übernehmen. Man muss ja auch beachten dass die 
Auslese-Reihenfolge der Variablen (hier: txw und txr) nicht garantiert 
ist.

Da das ganze sowieso sehr ineffizient ist (jedes Zeichen einzeln im FIFO 
verarbeiten), macht das Ein/Aus-Schalten den Braten auch nicht fetter.

W.S. schrieb:
> und kann in der
> Firmware nicht mehr wirklich genau so wie ein UART benutzt werden

Kann deiner auch nicht, wenn der Host den Port deaktivieren/aktivieren 
können ohne das Programm zu blockieren soll (wie im alten Thread 
gewünscht). Code der mit deiner Lib funktioniert müsste auch mit meiner 
korrigierten Version funktionieren.

W.S. schrieb:
> Also merkt doch mal, daß der Sinn eines virtuellen COM-Portes eben genau
> darin besteht, daß man eine asynchrone Einzelzeichen-Verbindung von
> einer App auf dem PC bis hin zu einer anderen "App" (sprich Firmware)
> auf einem anderen gerät haben kann,

Hier ist aber keine Einzelzeichen-Übertragung gewünscht, sondern mehrere 
Zeichen lange Pakete. Und die machen es wieder komplizierter, weil man 
Paket-Anfang/Ende erkennen muss usw. Und da USB rein zufällig ein Modell 
für Transaktionen und Datenpakete schon beinhaltet, macht es viel mehr 
Sinn, das einfach zu nutzen, als das in einen Einzel-Zeichen-Strom zu 
abstrahieren und da wieder Pakete hinein zu definieren.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Zur Info: Die Variable "suspended" wurde erst später (nicht von W.S.) 
hinzugefügt. Dass man dort eine Interrupt-Sperre Sinn macht hatte er 
wohl deswegen nicht auf dem Schirm.

von temp (Gast)


Lesenswert?

Schön dass alle Krieger versammelt sind...

Niklas G. schrieb:
> Der eigentliche Fehler ist es, aus der main-Schleife heraus auf die
> Kommunikation zuzugreifen. Würde man das in Interrupts machen, hätte man
> das Problem nicht.

Sorry aber das tut schon weh. Wo ist denn das ein Problem? Diesen Teil 
muss doch sowieso jeder an seine Applikation anpassen und damit die 
UsbCharOut().
Und je nachdem was ich will, breche ich nach einem Timeout ab, oder 
gleich, oder oder oder. Und wenn jemanden das mit dem char zu wenig ist, 
dann muss man da ein wenig optimieren. Aber das hat rein gar nichts mit 
dem USB-Grundcode zu tun.
Ich glaube fast du bist auch so ein typischer Programmierer für den alle 
Räder eckig sind die sie nicht selbst erfunden haben.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Wo ist denn das ein Problem?

(Blockierender) I/O-Code in der main()-Schleife ist nicht für 
Nebenläufigkeit skalierbar. Da gehören höchstens rechenintensive Dinge 
hin. Alles andere handelt man im jeweiligen Interrupt ab.

temp schrieb:
> Ich glaube fast du bist auch so ein typischer Programmierer für den alle
> Räder eckig sind die sie nicht selbst erfunden haben.

Rein zufällig ist sowohl die USB-Peripherie als auch ST's eigene Library 
komplett darauf ausgelegt, asynchron aus ISRs heraus benutzt zu werden.

von Stefan F. (Gast)


Lesenswert?

Jeder kann und darf den Code so weit aufblähen, wie er es braucht. Ich 
halte die Kritik an diesem Punkt es für unnötige Ablenkung vom Thema.

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Rein zufällig ist sowohl die USB-Peripherie als auch ST's eigene Library
> komplett darauf ausgelegt, asynchron aus ISRs heraus benutzt zu werden.

Das ist doch hier auch der Fall. Mir scheint du hast den Code überhaupt 
nicht verstanden. Ansonsten zeig die Stellen konkret auf die du dich 
beziehst. Das wird langsam lächerlich mit dir.

Wo soll den der USB Interrupt her wissen wann es etwas zum senden gibt? 
Und wenn ich was senden will ist es mir in der Regel nicht egal ob der 
USB-Teil das annimmt oder nicht? Und wie man damit umgeht, wenn etwas 
nicht gesendet werden konnte, das kannst du ruhig dem Anwender 
überlassen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Mir scheint du hast den Code überhaupt
> nicht verstanden.

Genau, deswegen hab ich auch W.S.'s Bugs beheben können, die er seit 
Jahren nicht gefunden hat.

temp schrieb:
> Wo soll den der USB Interrupt her wissen wann es etwas zum senden gibt?

Schau einfach in meinen Code und in mein Tutorial, da ist alles genau 
erläutert.

von J. -. (Gast)


Lesenswert?

Nun habe ich den Code von W.S. auch mal probiert. Danke auch an Stefan 
Frings, der auf seiner Webseite nützliche Erklärungen dazu 
bereitstellt.#
Ich habe 2h investiert und beschlossen, die andere Variante vom 
MCD-Application-Team mit ca. 20 Files aus meiner Bibliothek 
rauszuschmeissen und künftig die von W.S. zu nehmen, weil sie stabiler 
läuft.
Beim Verlassen von UsbSetup() prüfe ich mit UsbActive() noch ein paar 
ms, ob das Kabel drinsteckt bzw. USB bereit ist, und ansonsten war da 
nichts mehr dran zu ändern. Wobei ich mit der SPL programmiere und die 
ganzen Linkerscripts und Assemblerfiles nicht brauchte.
Neu war mir auch, daß man die GPIOs PA11/12 für USB gar nicht mit 
Alternate Function bzw. als In/Output vorbelegen muß.

von temp (Gast)


Lesenswert?

Jürgen S. schrieb:
> Ich habe 2h investiert und beschlossen, die andere Variante vom
> MCD-Application-Team mit ca. 20 Files aus meiner Bibliothek
> rauszuschmeissen und künftig die von W.S. zu nehmen, weil sie stabiler
> läuft.

Ja so ist es auch in der Regel. Warum das bei Axel Probleme machte weiß 
keiner, aber auch nicht ob eine andere Implementierung läuft. Der 
Verdacht liegt immer noch auf Hardware bzw. Takt.
Klar einen Schönheitspreis gewinnt der Code nicht, muss er aber auch 
nicht. Dafür ist er aber auch von keiner weiteren Lib abhängig und auch 
von keiner Headerorgie wo es je nach Umgebung an allen Ecken und Enden 
klemmen könnte.

von Bernd N. (_bn_)


Lesenswert?

Niklas G. schrieb:
> Genau, deswegen hab ich auch W.S.'s Bugs beheben können, die er seit
> Jahren nicht gefunden hat.

Wer hier den Hintergrund verstehen will sollte den folgneden Thread 
lesen:
Beitrag "USB CDC von Stefan Frings und WS"

Ich kann bestätigen das Niklas die Bugs gefixed hat und den Code nun 
auch bereitgestellt hat. Das geht immer wieder in anderen Folge Threads 
verloren.

Warum führt das eigentlich hier immer zu Streit ?

Wie dem auch sei, hat ja mit dem Thema nix zu tun. Jedenfalls verwende 
ich Niklas Version seit einem Jahr ohne irgendwelche Probleme.

von temp (Gast)


Lesenswert?

Bernd N. schrieb:
> Ich kann bestätigen das Niklas die Bugs gefixed hat und den Code nun
> auch bereitgestellt hat

Dann lest euch nochmal die Threads durch von wem die Bugs mit dem Nops 
beseitigt wurden. Da war kein Niklas im Spiel.
Niklas hat seinen Anteil insgesamt, aber nicht nur er.

von Bernd N. (_bn_)


Lesenswert?

temp schrieb:
> Niklas hat seinen Anteil insgesamt, aber nicht nur er.

Das ist mir durchaus klar.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Dann lest euch nochmal die Threads durch von wem die Bugs mit dem Nops
> beseitigt wurden. Da war kein Niklas im Spiel.

Die Set-Adress-Korrektur war in der Version, die ich von W.S. übernommen 
hatte, schon drin. Ich hatte das aber viel früher genau so schon in 
meinem eigenen USB-Code gemacht.

Jürgen S. schrieb:
> Beim Verlassen von UsbSetup() prüfe ich mit UsbActive() noch ein paar
> ms, ob das Kabel drinsteckt bzw. USB bereit ist

Das stammt auch von mir...

Bernd N. schrieb:
> Warum führt das eigentlich hier immer zu Streit ?

Weil gewisse Leute hier gerne stänkern:

W.S. schrieb:
> Das ist Programmieren mit dem Schmiedehammer.

temp schrieb:
> Sorry aber das tut schon weh. Wo ist denn das ein Problem?

temp schrieb:
> Ich glaube fast du bist auch so ein typischer Programmierer für den alle
> Räder eckig sind die sie nicht selbst erfunden haben.

temp schrieb:
> Das wird langsam lächerlich mit dir.

von J. -. (Gast)


Lesenswert?

Niklas G. schrieb:
> Das stammt auch von mir...
Wie auch der gute USB-Artikel, bei dem man aber wirklich tief einsteigen 
muß, um es zu verstehen. Ich hab's versucht und dann beschlossen, daß 
ich USB nicht wirklich verstehen muß - es soll nur funktionieren :).
Ich nehme an, daß in den Dateien auf stefanus Seite 
(STM32F103_usb_test.zip) auch Deine Verbesserungen eingeflossen sind. 
Danke Dir deshalb nochmal extra, und W.S. natürlich ebenfalls.

von Stefan F. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Ich nehme an, daß in den Dateien auf stefanus Seite
> (STM32F103_usb_test.zip) auch Deine Verbesserungen eingeflossen sind.

Ja sind sie. Und zum Teil wieder heraus geflossen. Die unnötigen 
Interrupt-sperren habe ich gerade wieder entfernt und der oben genannte 
Tippfehler ist jetzt auch korrigiert.

http://stefanfrings.de/stm32/index.html

von arduinohasse (Gast)


Lesenswert?

Ok, wenn wir schon mal dabei sind möchte ich den Klappstuhl begraben und 
auf etwas anderes hinweisen.

In der InitEndpoints() wird am Ende das FLAG für den 1ms Frameinterrupt 
SOFM mit gesetzt:
1
  USB_CNTR =
2
        CTRM |             /* Int bei ACKed Paketen in oder out */
3
        RESETM |            /* Int bei Reset */
4
    SUSPM | WKUPM | ESOFM | SOFM; /* Int bei 1 ms Frame */

Im Interrupthandler selbst wird aber so gut wie nichts gemacht:
1
  if (I & SOF) /* Start of Frame, alle 1 ms */
2
    {
3
    //trace("SOF\n");
4
    USB_ISTR = ~SOF; /* Int löschen */
5
    suspended = false;
6
    //  OnEpBulkIn();  /* immer mal nachschauen... */
7
    }

Das Rücksetzten des Flags "suspended" an dieser Stelle ist in meinen 
Augen nicht nötig.
Auf alle Fälle scheit mir der 1ms Interrupt nicht nötig zu sein. Bei mir 
geht das auch ohne und deshalb habe ich das SOFM flag auch nicht 
gesetzt.

Eventuell ist das ja auch die Ursache für Probleme die manche haben. Ich 
weiss ja nicht, was passiert wenn anderweitige höher priorisierte 
Interrups so blöd programmiert sind dass sie viel länger dauern.

von temp (Gast)


Lesenswert?

sorry, hatte noch was falsches im Namen stehen. Der letzte Beitrag kam 
von
"temp"

von Stefan F. (Gast)


Lesenswert?

Der Code ist vielfach erprobt und auch beim TO funktioniert er auf 
einigen Modulen. Das stinkt gewaltig nach einem Hardwarefehler oder 
schlechter Taktversorgung.

Man könnte zur gegenprobe einfach mal mein simples Beispielprogramm 
laufen lassen, wo der µC jede Sekunde "Hallo" an den PC sendet. Wenn das 
klappt, dann probiert man die umgekehrte Richtung.

Wenn eins davon scheitert, liegt mit Sicherheit ein Hardwarefehler vor. 
Ich schätze zu 80%, dass es ein Hardwarefehler ist und <5%, dass es ein 
Fehler in usb.c ist.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich denke, ihr könnt aufhören, über mutmaßliche Softwarefehler in den
> beiden USB Dateien zu spekulieren. Lasst ihn zuerst mal die Hardware und
> die Taktversorgung untersuchen.

gleiche Meinung und auch schon ein paar mal kommuniziert.

Wäre trotzdem schön wenn jemand die Sache mit dem 1ms Interrupt mal 
gegenchecken kann.
Sowas muss man ja nicht unbedingt sein wenn es nicht benötigt wird. Und 
schon gar nicht mit so einer Wiederholrate.

von W.S. (Gast)


Lesenswert?

temp schrieb:
> Schön dass alle Krieger versammelt sind...

Ach nö, als Krieger empfinde ich mich nicht.

Aber mal ne Überlegung zum COM-Port als solchem, egal ob nun virtuell 
oder sonstwie:
1. Wenn nix hereinkommt, dann kommt eben nix herein und sowas wie 
CharAvail() kann nichts anderes melden als "false". Und das sowohl dann, 
wenn das Kabel ab ist als auch wenn der Sender nix sendet.
2. Wenn der Empfänger nicht eingeschaltet ist oder das Kabel ab ist oder 
sonstwo die Übertragung unterbrochen ist, dann sendet der COM-Port die 
Daten ins Nirwana. Er merkt das nicht einmal!

So - und nun sollten wir mal dran denken, ob und wie so ein virtueller 
COM-Port sich denn benehmen sollte. Ich hab damals danach getrachtet, 
daß der USB-Comport sich möglichst genau wie ein gewöhnlicher Comport 
benehmen soll, aber ich hatte mich nicht getraut, die Sendedaten einfach 
so ins Nirvana zu schicken, wenn sie partout nicht vom Host abgeholt 
werden.

Stattdessen hatte ich - obwohl das für einen richtigen Comport eher 
unüblich ist - sowas wie UsbTxReady() und UsbTxEmpty() eingebaut, damit 
sich ggf. das übergeordnete Programm erstmal davon überzeugen kann, ob 
es die Daten, die es senden will, auch loswerden kann. Und wenn nicht, 
dann kann es der Treiber auch nicht richten, dann muß eine andere Stelle 
in der Firmware entscheiden, was zu tun ist.

Vielleicht - als Anregung - könnte man das Verhalten eines echten 
Comports hier nachempfinden: wenn kein Usb-Timertick kommt oder wenn 
nach etwa 10 ms noch immer nix abgeholt worden ist, dann sollte man den 
EpBulkIn eben stallen und alle bis dato aufgelaufenen Bytes ins Nirvana 
befördern. Das würde so etwa dem Verhalten eines echten Comports 
entsprechen. Ob sich sowas gut macht, wäre auszuprobieren, ich wage da 
keine Vorhersage.

Niklas G. schrieb:
> Bei Sachen wie:/* liefert true, wenn Tx-Buffer leer ist */
> bool UsbTxEmpty(void)
> {
>   DisableUsbIRQ ();
>     bool res = (txw == txr);
>     EnableUsbIRQ ();
>     return res;
> }
> kann es sogar sein dass die Interruptsperre unnötig ist; ich war ehrlich
> gesagt zu faul mir das ganz genau für alle Fälle zu überlegen.

Letzteres hätte ich aber als selbstverständlich erachtet.
Zur Sache: Die Seite, die den Ringpuffer befüllt, besitzt den 
Füll-Index. Die seite, die den Ringpuffer entleert, besitzt den 
Entleer-Index.
Was passiert nun, wenn du in obigem Code feststellst, daß der Puffer 
nicht leer ist und der Interrupt direkt nach dem EnableUsbIRQ() den 
Puffer leert? Dann kehrt die Funktion eben mit "ist nicht leer" zurück, 
obwohl der Puffer bereits leer ist. Kurzum: das Disable/Enable nützt 
überhaupt nichts.
Bei allen anderen Tests verhält es sich genaus so: Wenn man testet, ob 
denn noch Platz für ein Byte frei ist, dann ist es unerheblich, ob ein 
mittendrin hereinrauschender Interrupt noch weitere 64 Plätze frei 
gemacht hat. Und wenn man im Inputpuffer nachfragt, ob ein Byte drin 
ist, dann ist es unerheblich, ob ein Interrupt mittendrein noch weitere 
64 Bytes dazupackt.

Nochwas zu dem elenden Streit wegen der "Nops" und der Trampelschleife: 
Das ist GCC-spezifisch (der Keil macht es richtig) und es ist eigentlich 
herzlich nebensächlich. Eigentlich geht es ja nur darum, ein paar 
Mikrosekunden zu schinden, bis daß der Host das ACK-Paket abgeholt hat, 
damit man sofort danach auf die zugeteilte Adresse umschalten kann. Ich 
wollte damals nicht eine bedingte Warteschleife schreiben, a la
 while (Paket noch nicht abgeholt) do warten;
um schlichtweg jegliches Blockieren zu vermeiden. Das ist alles. 
Natürlich kann man - aus heutiger Sicht - auch den Zustand des 
ACK-Paketes abfragen, sagen wir mal 10 mal oder 20 mal und sobald es 
abgeholt ist die Schleife vorzeitig verlassen. Das wäre wohl die 
sauberste Lösung.


temp schrieb:
> Wo soll den der USB Interrupt her wissen wann es etwas zum senden gibt?
> Und wenn ich was senden will ist es mir in der Regel nicht egal ob der
> USB-Teil das annimmt oder nicht?

Ähem.. das ist ein tieferes Problem. Es gibt immer einen 
Sammel-Interrupt und in einem Statusregister steht, welcher Teil der 
Hardware einen Service benötigt. Aber ein Service-Bit für den EpBulkIn 
gibt es nur dann, wenn der Host einen zuvor hereingereichten Datenblock 
gelesen hat. Der ganze "Interrupt" kann NICHT und NIEMALS wissen, ob 
irgendwo Daten zum senden an den Host bereitstehen. Das ist die Krux. 
Verstehe mal, daß das Int-Bit für den zuständigen Endpoint nur dafür da 
ist, daß dieser weiß, daß sein letztes Paket angekommen ist.

Das sagt NICHTS aus darüber, ob es in dem µC noch weitere Daten zum 
senden gibt. Ich hatte damals den Timer-Service Interrupt des USB dazu 
benutzt, um nachzuschauen, ob es Sendedaten gibt und ggf. deren 
Absendung zu veranlassen - vorausgesetzt, es ist nicht grad schon eine 
Übertragung angesagt. Aber diesen Mechanismus zum eigenständigen 
Wieder-in-Gang-kriegen der Transmission µC-->PC scheint man hier nicht 
verstanden zu haben. Dabei ist das essenziell! Entweder der 
USB-Interrupt regelt das selber (er wird sich garantiert NICHT selbst 
unterbrechen) - oder man muß es eben aus der mainloop heraus anstoßen.
Letzteres ist deutlich gefährlicher, weil man genau dabei damit rechnen 
muß, daß man durch einen Interrupt unterbrochen wird ODER eine grad 
laufende Hardwarefunktion unterbricht oder diese beeinflußt und dabei 
eine Fehlfunktion bei irgendwas wie z.B. Toggelbit oder bereits 
gefüllten Puffer nochma befüllen oder falsche Länge etc. auslöst. Immer 
dran denken, daß die SIE ein durchaus komplexer eigener Prozessor ist.
So etwas muß man vorher bedenken.

W.S.

von temp (Gast)


Lesenswert?

W.S. schrieb:
> Nochwas zu dem elenden Streit wegen der "Nops" und der Trampelschleife

Der Hauptgrund war ja noch nicht mal das Wegoptimieren der Nops sondern, 
dass sie im Interrupthandler überhaupt nötig waren. Das wurde damals in 
diesem Thread behandelt und gelöst und ist im aktuellen Stand auch so:

Beitrag "Re: STM32F303 CAN und USB gleichzeitig"

Trotzdem auch an dich die Frage: Wie siehts du die Notwendigkeit des 1ms 
Interrupts von dem ich ein paar Beiträge vorher gesprochen habe?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Ja sind sie. Und zum Teil wieder heraus geflossen. Die unnötigen
> Interrupt-sperren habe ich gerade wieder entfern

Die von mir ausgebauten Funktionen UsbCharOut, UsbTxFlush, UsbTxReady, 
UsbActive, UsbGetChar brauchen die Interrupt-Sperre definitiv. Die da 
auszubauen ist... nicht so clever.

arduinohasse schrieb:
> Auf alle Fälle scheit mir der 1ms Interrupt nicht nötig zu sein.

Der war bei W.S.' Code nur "nötig" weil er den SOF-Interrupt zum 
Absenden missbraucht hat. Kann man aber nach meinen bzw. temp's 
Korrekturen deaktivieren.

W.S. schrieb:
> Eigentlich geht es ja nur darum, ein paar
> Mikrosekunden zu schinden, bis daß der Host das ACK-Paket abgeholt hat,
> damit man sofort danach auf die zugeteilte Adresse umschalten kan

Das ist halt schon völlig verkehrt. Man setzt die Adresse einfach 
nachdem das ACK gesendet wurde. Dann funktioniert alles perfekt und man 
braucht das dumme NOP gar nicht erst. Auch wenn das mit dem GCC 
natürlich auch ginge. Das haben "temp" und ich unabhängig voneinander 
hinbekommen und es funktioniert sauber, ist also definitiv die bessere 
Lösung als so ein Delay.

W.S. schrieb:
> Was passiert nun, wenn du in obigem Code feststellst, daß der Puffer
> nicht leer ist und der Interrupt direkt nach dem EnableUsbIRQ() den
> Puffer leert? Dann kehrt die Funktion eben mit "ist nicht leer" zurück,
> obwohl der Puffer bereits leer ist. Kurzum: das Disable/Enable nützt
> überhaupt nichts.

Das war klar. Aber was passiert wenn der Interrupt genau in die Mitte 
der Funktion zuschlägt? Bei deinen Original-Funktionen ist die Sperre 
wohl tatsächlich nicht nötig. Wie gesagt, ich hatte keine Lust das 
auszutüfteln. Meine erweiterten Funktionen brauchen die Sperre, weil auf 
mehrere Variablen zugegriffen wird.

W.S. schrieb:
> Aber diesen Mechanismus zum eigenständigen
> Wieder-in-Gang-kriegen der Transmission µC-->PC scheint man hier nicht
> verstanden zu haben.

Das ist eine Zweckentfremdung des SOF-Pakets. Du hast es nicht 
verstanden.

W.S. schrieb:
> Letzteres ist deutlich gefährlicher,

Funktioniert bei mir aber perfekt, ohne die bis 1ms Verzögerung. Die 
Interruptsperre entfällt wie gesagt sowieso, wenn man die gesamte 
Architektur sauber asynchron in Interrupts packt. Mein eigener Code 
kommt ohne aus.

von Stefan F. (Gast)


Lesenswert?

Niklas G. schrieb:
> Die von mir ausgebauten Funktionen UsbCharOut, UsbTxFlush, UsbTxReady,
> UsbActive, UsbGetChar brauchen die Interrupt-Sperre definitiv. Die da
> auszubauen ist... nicht so clever.

Ich nehme mir die Freiheit, das anders zu sehen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich nehme mir die Freiheit, das anders zu sehen.

Aus echtem Interesse - wie gehst du so etwas an? Gehst du jede einzelne 
Zeile der genannten Funktionen durch, überlegst wie der Compiler sie 
umordnen könnte, überlegst ganz genau was passiert wenn welcher 
Interrupt genau wo dazwischen kommt und dann was macht? Eine Zeile 
welche 3 Variablen ausliest hat ja schon 6 Möglichkeiten, wie der 
Compiler sie umsetzt. Stellst du einen Entscheidungsbaum auf, was bei 
welcher Umsetzung passiert? Wie lange hast du für die Analyse dieses 
Programms gebraucht? Was passiert z.B. wenn UsbGetChar ClearBuffer 
aufruft, und genau zwischen Lesen & Schreiben des EPnR ein Interrupt 
kommt?

Niklas G. schrieb:
> Kann man aber nach meinen bzw. temp's
> Korrekturen deaktivieren.

... ist doch Quatsch, denn:

arduinohasse schrieb:
> Das Rücksetzten des Flags "suspended" an dieser Stelle ist in meinen
> Augen nicht nötig.

Wo soll man es denn sonst zurücksetzen? Wenn der Host das Gerät aktiv 
halten bzw. reaktivieren will, aber keine Daten sendet/empfängt, kommt 
sonst kein anderer Interrupt.

von Stefan F. (Gast)


Lesenswert?

Niklas G. schrieb:
> Aus echtem Interesse - wie gehst du so etwas an? Gehst du jede einzelne
> Zeile der genannten Funktionen durch, überlegst wie der Compiler sie
> umordnen könnte, überlegst ganz genau was passiert wenn welcher
> Interrupt genau wo dazwischen kommt und dann was macht?

So ungefähr.

> Eine Zeile welche 3 Variablen ausliest hat ja schon
> 6 Möglichkeiten, wie der Compiler sie umsetzt.

Erstens sind es nur 2 Variablen und eine Konstante und zweitens spielt 
es für die Entscheidung keine Rolle, ob der Interrupt dazwischen funkt.

W.S. hat bereits in diesem und in früheren Threads mehrfach versucht, 
dir zu erklären, warum es da keine Probleme gibt. Ich stimme ihm voll 
zu. Wenn du das nicht verstehst, dann lass es halt. Die Welt geht nicht 
davon unter, weder durch deine noch anderer Leute Irrtümer.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> W.S. hat bereits in diesem und in früheren Threads mehrfach versucht,
> dir zu erklären, warum es da keine Probleme gibt.

W.S. hat erklärt, warum es in seinem Code keine Probleme gibt. Niklas' 
Code sieht an den genannten Stellen anders aus. Wenn mehrere Variablen 
hintereinander atomar geändert werden müssen, ist eine Sperre 
unausweichlich.

: Bearbeitet durch Moderator
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Frank M. schrieb:
> W.S. hat erklärt, warum es in seinem Code keine Probleme gibt. Niklas'
> Code sieht an den genannten Stellen anders aus. Wenn mehrere Variablen
> hintereinander atomar geändert werden müssen, ist eine Sperre
> unausweichlich.

Danke, der Erste der es versteht. In UsbTxReady sind es sogar 4 
Variablen, d.h. 24 Möglichkeiten es zu kompilieren.

von Stefan F. (Gast)


Lesenswert?

Frank M. schrieb:
> W.S. hat erklärt, warum es in seinem Code keine Probleme gibt. Niklas'
> Code sieht an den genannten Stellen anders aus. Wenn mehrere Variablen
> hintereinander atomar geändert werden müssen, ist eine Sperre
> unausweichlich.

Ja das sehe ich ein. Bei seinen hinzugefügten Code.

Aber bei den Teilen, die von W.S. kommen werden keine Interruptsperren 
gebraucht.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Aber bei den Teilen, die von W.S. kommen werden keine Interruptsperren
> gebraucht.

Das habe ich vorhin auch schon geschrieben.

Niklas G. schrieb:
> kann es sogar sein dass die Interruptsperre unnötig ist; ich war ehrlich
> gesagt zu faul mir das ganz genau für alle Fälle zu überlegen.

Du hast die Sperren aber auch in meinen erweiterten Funktionen entfernt.

von Stefan F. (Gast)


Lesenswert?

Niklas G. schrieb:
> Du hast die Sperren aber auch in meinen erweiterten Funktionen entfernt.

Korrekt erkannt, ich habe es auch schon wieder bereut. Während wir hier 
diskutierten hatte ich das bereits in Arbeit. Wenn du magst kannst du 
nochmal kontrollieren, ich habe die ZIP Files gerade nochmal 
aktualisiert.

Die Interrupt-Sperren um deine Codeabschnitte sind wieder drin.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Wenn du magst kannst du
> nochmal kontrollieren

In UsbCharOut, UsbTxReady, UsbActive, UsbGetChar fehlt es vermutlich 
weiterhin an Sperren. Habe keine Lust das wie beschrieben detailliert 
aufzudröseln ob man die irgendwo einsparen kann; ist schließlich eine 
Mikrooptimierung, wenn man wirklich Rechenleistung einsparen wollte 
sollte man nicht jedes Zeicheln einzeln verarbeiten sondern ganze 
Pakete.

von Stefan F. (Gast)


Lesenswert?

Niklas G. schrieb:
> In UsbCharOut, UsbTxReady, UsbActive, UsbGetChar fehlt es vermutlich
> weiterhin an Sperren.

Das musste ja kommen. Niklas, ich weiß deine Hilfe zu schätzen. Du hast 
hier von dem ganzen ganzen USB Kram von uns allen am meisten Ahnung.

Aber bitte akzeptiere, dass man sich auch mal irren kann. Ich weis auch 
nicht, wie es dir erklären soll. Letztendlich müsste ich dazu erneut die 
Erklärungen von W.S. wiederholen, die er schon mehrfach wiederholt hat. 
Das führt zu nichts.

> wenn man wirklich Rechenleistung einsparen wollte
> sollte man nicht jedes Zeicheln einzeln verarbeiten sondern ganze
> Pakete.

Irgendwas ist immer. In diesem Fall ist der Code halt doof designt (wie 
du meinst). Immerhin funktioniert er für andere gut genug. Du musst ihn 
nicht mögen, du kannst dir ja was anderes programmieren. Es bringt 
nichts, immer wieder auf diesem Punkt herum zu reiten.

Können wir jetzt bitte Ruhe geben und dem TO weiter helfen, falls er 
sich noch traut, sich wieder zu melden?

von Stefan F. (Gast)


Lesenswert?

An Alex,
du hast wahrscheinlich gemerkt, dass hier wieder eine hitzige Diskussion 
um alte Wunden ausgebrochen ist. Das war vielleicht mal wieder nötig, 
hat jedoch mit deinem konkreten Problem sehr wahrscheinlich nichts zu 
tun. Schau du erst einmal, ob die Hardware und Taktversorgung OK ist.

Du hast geschrieben, dass du den HSI48 Oszillator verwendest und das 
Clock Recovery System (CRS) aktiviert hast. Vielleicht ist da etwas 
schief gelaufen. Falls du von meinem Beispiel für STM32 L0 abgeguckt 
hast: Bei dem geht das vielleicht anders, als bei deinem F0.

von Alex (Gast)


Lesenswert?

Hallo Leute,

ich sehe ihr habt euch ja prächtig amüsiert!
Danke für deine Achtsamkeit Stefan, sie gereicht dir zu Ehre!

Ohne alle Beiträge voll gelesen und verstanden zu haben, ich sehe das 
Thema USB ist relativ komplex und es gibt nicht 'die eine richtige' 
Lösung. Die Diskussion find ich aber sehr wichtig, so kommt immer mal 
wieder Bewegung in die Sachen. Ich bin ein Freund hitziger Debatten und 
daher nicht abgeschreckt und ich würde jedem von euch sofort ein Bier 
ausgeben!

Ich hab gestern leider überhaupt keine Zeit gefunden um an meinem 
Problem weiter zu tüfteln. Einzig die Zeile mit dem BulkIn -> BulkOut 
hab ich eben noch ausprobiert und wie erwartet hat das aber keinen 
Effekt.


Zu möglichen Taktproblemen / Hardware-Ursache:

Einer meiner ersten Ansätze war es (nach der Suche nach Lötfehlern) den 
Takt zu prüfen.
Der STM läuft auf dem RC-Oszillator, was ja für USB eigentlich ein 
KO-Kriterium ist.
ST hat dem Chip aber dieses Clock-Recovery-System verpasst, das den 
Oszillator nachjustiert, so dass er mit den SOF-Paketen synchronisiert 
wird. Das funktioniert auch, jittert allerdings ein wenig rum. Wurde 
aber von ST genau für solche Anwendungsfälle gemacht und ich gehe davon 
aus, dass es die Anforderungen von USB erfüllt.
Initialisiert hab ich das wie in den Manuals (oder einer Appnote, 
erinnere mich nicht genau, ist zu lange her) von ST beschrieben. Der 
Jitter kommt in erster Linie daher, dass die Anpassungsschritte wohl 
etwas grob sind, und nur alle Millisekunden nachretunt wird.

Ich hab auf einem Pin mal einen Takt von ca. 600kHz erzeugt und mit dem 
Oszi 4 der Module verglichen.
Eine Auffälligkeit des 'schlechen' Moduls hab ich so nicht gefunden, 
intensivere Tests mit Counter hab ich aber nicht gemacht. Grund war 
folgende Überlegung:

Wenn es wirklich der Takt ist, müsste dann nicht die Übertragung in 
beide Richtungen Probleme bereiten? Immerhin läuft der Transfer von 
Daten zum PC auch *wochenlang !!* problemlos, und das braucht ja auch 
die ACK-Pakete in die andere Richtung.
Das die Probleme völlig reproduzierbar immer nur beim BULK-OUT auftreten 
macht die CLK-These für mich unplausibel.

Andererseits verhält sich ein Programm nun mal streng deterministisch, 
d.h. es MUSS eine Hardware-Ursache geben, sonst würde das Problem nicht 
bei einem bestimmten Modul auftreten.

Es ist wohl irgendwas ziemlich knapp an der Grenze betrieben 
(höchstwahrscheinlich ist das ein Timing), die Software müsste damit 
zurechtkommen und tut es in bestimmten Fällen (BulkOut) nicht.

Nachdem ich mich mit der USB-Programmierung einfach viel zu wenig 
auskenne, um sinnvolles Debugging betreiben zu können, ist eine genauere 
Untersuchung der CRS-Clock-Geschichte wohl der Hebel, an dem ich 
ansetzen sollte.

Ich schau mir mal an, weche Möglichkeiten ich habe um rauszufinden, was 
die tatsächlichen Unterschiede zwischen den Modulen sind, und vor allem 
wie ich das 'ordentlich' quantifizieren kann.

Updates folgen, ihr dürft derweil gerne weiterdiskutieren :-).

mit Respekt, Alex

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> In UsbCharOut, UsbTxReady, UsbActive, UsbGetChar fehlt es vermutlich
> weiterhin an Sperren. Habe keine Lust das wie beschrieben detailliert
> aufzudröseln ob man die irgendwo einsparen kann; ist schließlich eine
> Mikrooptimierung, wenn man wirklich Rechenleistung einsparen wollte
> sollte man nicht jedes Zeicheln einzeln verarbeiten sondern ganze
> Pakete.

Keine Lust ist ein blödes Argument. Betrachten wir nur mal
1
bool UsbTxReady(void)
2
{
3
  DisableUsbIRQ ();
4
  bool res = configurationSet && !suspended && ((txw + 1) & (txLen - 1)) != txr;
5
  EnableUsbIRQ ();
6
  return res;
7
}
txLen ist eine Konstante, txw kann nur im main Programm verändert werden 
und txr kann im Interrupt nur so verändert werden, dass das Ergebnis des 
Vergleiches von false auf true springt, aber nicht von true auf false. 
Damit ist das komplett threadsave und benötigt keine Sperren.
Die Funktion selbst verändert ja noch nicht mal irgendeine Variable.
configurationSet und suspended können zu jeder Zeit im Interrupt 
verändert werden. Also auch direkt nach EnableUsbIRQ(). Damit ist die 
Sperre nutzlos.
Sinn würde das z.B. nur so ergeben:
1
  ....
2
  DisableUsbIRQ ();
3
  if (UsbTxReady())
4
   {
5
   UsbSendString(...);
6
   } 
7
  EnableUsbIRQ ();
8
  ....
Man muss also eine Sequenz von Aufrufen Sperren, damit das überhaupt nur 
einen Anflug von Sinn ergibt.
Auf der anderen Seite kann der User zu beliebigen Zeiten den VPC 
schließen oder das Kabel ziehen. Da kannst man die Flags 
configurationSet und suspended auswerten wie man will, das kann immer 
und zu jeder Zeit passieren. Auch das ist nicht weiter schlimm, wenn man 
in der UsbCharOut(char c) statt der Endlosschleife eine Timeout einbaut.
Ein anderer könnte auf die Idee kommen, einfach den Watchdog zu benutzen 
um solche Fälle abzudecken. Das kommt immer auf die Anwendung an, und 
keiner hat das Recht zu schimpfen: "sowas ist verpöhnt".

Jetzt mal zur UsbCharOut()
1
/* sendet ein Zeichen (d.h. schreibt es in den Tx-Buffer) */
2
bool UsbCharOut(char c)
3
{
4
  while (true) 
5
    {
6
    DisableUsbIRQ ();
7
8
    if (!configurationSet || suspended) 
9
      {
10
      EnableUsbIRQ ();
11
      return false;
12
      }
13
14
    // diesen Teil zu Sperren ist genau wie UsbTxReady komplett überflüssig   
15
    if (((txw + 1) & (txLen - 1)) != txr) 
16
      break;
17
18
    EnableUsbIRQ ();
19
20
    // das kann man so machen oder eine einen Timeout einbauen
21
    // Egal was passiert, im Fehlerfall läuft der Ringbuffer voll und das
22
    // ist eigentlich das einzige auf was ich als User reagieren muss.
23
    __asm__ volatile ("wfi"); /* trampeln auf der Stelle!! */
24
    }
25
    
26
  // das ist wieder komplett theradsave, 
27
  // da txw ausschließlich hier verändert wird.
28
  // die Abholroutine im Irq zieht txr nach, aber Daten gehen dabei 
29
  // nie verloren. Das verändern von txr kann nur zusätzlichen Platz
30
  // im Buffer schaffen, ihn aber nicht nehmen
31
  int i = (txw + 1) & (txLen - 1);
32
  UsbTxBuf[txw] = c;
33
  txw = i;
34
35
  // das will ich nicht kommentieren, da soll jeder selbst 
36
  // entscheiden wie er was will. Auf alle Fälle gilt hier das
37
  // gleiche wie oben, eine Interruptsperre ist nicht nötig
38
39
  /* Diese Bedingung einkommentieren, um nur dann automatisch abzusenden, wenn Sendepuffer voll. In diesem Fall kann über UsbTxFlush abgeschickt werden. */
40
  //    if (((txw + 1) & (txLen - 1)) == txr) {
41
    if (!transmitting) {
42
      EpBulkBeginTransmit ();
43
    }
44
  //    }
45
  EnableUsbIRQ ();
46
  return true;
47
}

Die anderen Funktionen sind alle ähnlich.

Niklas G. schrieb:
> wenn man wirklich Rechenleistung einsparen wollte
> sollte man nicht jedes Zeicheln einzeln verarbeiten sondern ganze
> Pakete

Es geht ja nicht darum Rechenzeit einzusparen, sondern darum lieber auf 
Verdacht Interruptsperren einzubauen nur weil man zu faul ist darüeber 
nachzudenken.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Es geht ja nicht darum Rechenzeit einzusparen, sondern darum lieber auf
> Verdacht Interruptsperren einzubauen nur weil man zu faul ist darüeber
> nachzudenken.

Naja, es ist legitim innerhalb eines begrenzten Kontext defensiv zu 
programmieren und einen Schutz "zur Sicherheit" einzubauen, statt viel 
Zeit darauf zu verwenden, zu überlegen, ob man ihn wirklich braucht. Vor 
allem wenn die Kosten minimal sind und man nicht für die Zeit bezahlt 
wird. Aber schön, dass erst die Beleidigungen kommen und dann die 
technische Erläuterung. Da ist man richtig motiviert darüber detailliert 
nachzudenken!

: Bearbeitet durch User
von temp (Gast)


Lesenswert?

Alex schrieb:
> Wenn es wirklich der Takt ist, müsste dann nicht die Übertragung in
> beide Richtungen Probleme bereiten? Immerhin läuft der Transfer von
> Daten zum PC auch *wochenlang !!* problemlos, und das braucht ja auch
> die ACK-Pakete in die andere Richtung.
> Das die Probleme völlig reproduzierbar immer nur beim BULK-OUT auftreten
> macht die CLK-These für mich unplausibel.

Die Signale müssen ja auf der einen Seite vom PC und auf der anderen 
Seite vom µC gesampelt werden. Das macht die Hardware, aber es ist nicht 
die gleiche. Von daher können schon richtungsabhängige Unterschiede 
auftreten. Die Länge der Pakete dürfte dabei auch eine Rolle spielen. 
Auch wenn es dir nicht plausibel erscheint, was hast du jetzt noch für 
Möglichkeiten? Eine andere Softwareimplementierung oder eine andere 
Hardware. Kannst du nicht mal an das schlechteste Modul einen Quarz dran 
fummeln und mal testen? Oder einen externen Taktgenerator, da brauchst 
du nur einen Pin.
Die Diskussionen hier werden dich mit deinem Problem nicht weiter 
bringen.

von W.S. (Gast)


Lesenswert?

temp schrieb:
> Der Hauptgrund war ja noch nicht mal das Wegoptimieren der Nops sondern,
> dass sie im Interrupthandler überhaupt nötig waren.

Erkenne doch bitte das Ziel der Übung: zuerst das Kommando vom Host mit 
der zugewiesenen Adresse mit ACK bestätigen und dann wenn der Host das 
ACK erhalten hat, auf die zugewiesene Adresse umschalten. Und das 
möglichst umgehend, weil zumindest mir nicht klar ist, ob man damit ewig 
warten darf. Und sofort die Adresse umzuschalten hatte ich nicht 
probiert, weil ich annahm, daß der Host das ACK noch von Adresse 0 
erwartet. Ich habe dazu keine Festlegung in den mir zugänglichen 
Unterlagen gefunden. Und nein, ich habe keine kostenpflichtigen 
Dokumente eingekauft, sondern mußte mich auf das beschränken, was man im 
Inet eben so findet.

> Trotzdem auch an dich die Frage: Wie siehts du die Notwendigkeit des 1ms
> Interrupts von dem ich ein paar Beiträge vorher gesprochen habe?

Dieser Interrupt kommt immer und muß behandelt werden, sonst denkt der 
Host, daß man gestorben ist - und dann klemmt er einen einfach ab.

Und da man diesen Interrupt eben immer behandeln muß und man ja dabei 
bereits im Interupt-Modus ist, ist es auch keine schlechte Idee, mal 
nachzuschauen, ob der EpBulkIn grad NICHT am Transferieren ist und vor 
sich hin faulenzt, während die SIE alle Anfragen des Host nach Daten mit 
NAK abweist und im Ringpuffer des Treibers Daten vor sich hin schmoren.

W.S.

von W.S. (Gast)


Lesenswert?

Frank M. schrieb:
> W.S. hat erklärt, warum es in seinem Code keine Probleme gibt. Niklas'
> Code sieht an den genannten Stellen anders aus. Wenn mehrere Variablen
> hintereinander atomar geändert werden müssen, ist eine Sperre
> unausweichlich.

Frank, das sihst du falsch. Sperren sind nur dort nötig, wo zwei 
unabhängige Instanzen DIESELBE Variable zu ändern versuchen.

Das Lesen derselben Variablen ist hingegen für alle Instanzen erlaubt.

Und wenn man sauber programmieren will, dann macht man das so, daß nur 
die Instanz eine Variable verändert, die in ihrem Besitz ist. Und wer 
welche Variable besitzt und das Recht auf Ändern hat, muß man als 
Programmierer sorgfältig planen UND DANN AUCH EINHALTEN.

W.S.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

W.S. schrieb:
> Und sofort die Adresse umzuschalten hatte ich nicht
> probiert, weil ich annahm, daß der Host das ACK noch von Adresse 0
> erwartet.

Richtig. Daher schaltet man die Adresse einfach im Interrupt um, wenn 
das ACK gesendet wurde. Ein fixes Delay mit NOP ist sehr fehleranfällig, 
weil die Zeit nicht vorhersehbar ist.

W.S. schrieb:
> Dieser Interrupt kommt immer und muß behandelt werden, sonst denkt der
> Host, daß man gestorben ist - und dann klemmt er einen einfach ab.

Das stimmt nicht. Den SOF-Interrupt kann man abschalten, die Hardware 
behandelt das Paket automatisch. Der USB-Peripherie ist es egal, ob die 
Software den Interrupt abfragt oder nicht. Schließlich setzt die 
Software ja auch keine Register im SOF-Handler. Auch ohne Interrupt 
bleibt das Gerät "online". Ich verwende den Interrupt lediglich um 
resume zu erkennen. Man könnte den SOF-Interrupt abschalten wenn er das 
erste Mal auftrat, und reaktivieren wenn man im suspend gelandet ist.

W.S. schrieb:
> Das Lesen derselben Variablen ist hingegen für alle Instanzen erlaubt.

"Erlaubt" ist beides. Das Lesen mehrerer Variablen kann aber 
inkonsistente Zustände zurückliefern, wenn zwischendurch die Variablen 
geändert werden. Es ist nur in diesem konkreten Fall eben so, dass die 
Interrupts die Variablen nicht zwischendurch in inkonsistente Zustände 
bringen (vermutlich). Man könnte sogar gemeinsam genutzte Variablen ohne 
Interrupt-Sperre beschreiben indem man STREX / LDREX benutzt, aber der 
Aufwand lohnt sich hier kaum.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

temp schrieb:
> txLen ist eine Konstante, txw kann nur im main Programm verändert werden
> und txr kann im Interrupt nur so verändert werden

temp schrieb:
> Die Diskussionen hier werden dich mit deinem Problem nicht weiter
> bringen.

Ja, das sehe ich genau so.

Ich sehe aber auch Probleme der allgemeineren Art:

1. Zur Hardware: ich habe schon eine Menge an USB-Kabeln gesehen, die 
zwar sehr schön als ordentlich abgeschirmt und auch sonst hochqualitativ 
angepriesen wurden, aber bei genauerem Hinsehen sich als miese 
Billigware erwiesen haben: keine Abschirmung, sondern nur ne blanke 
Litze beigelegt anstelle Schirm. Insbesondere sind das solche dünnen 
Typen vom Typ A nach Mini-USB und Mikro-USB. Diese Kabel machen Probleme 
ohne Ende. Manchmal geht's, manchmal nicht. Häufig bleibt bei sowas das 
Enumerieren mittendrin stecken.

2. Software, speziell gültige Dokumentationen: schwer oder nur gegen 
Geld zu kriegen. Wer da als privater Programmierer nicht im Konsortium 
ist, muß zusehen, wo und was er an Unterlagen kriegt. Und da tun sich 
Lücken auf, weil man eben hie und da nichts hat, um nachlesen zu können, 
was da korrekt ist und was nicht.

3. Rechtliches: Als Privater kann man keine pid und vid kriegen, denn 
das kostet was. Ergo kann man nur mit geklauten ID's arbeiten. Ist 
ziemlich unschön, aber nicht zu ändern.

Dem TO würde ich nach all der Diskussion hier empfehlen, sich über einen 
UART seines Chips einen zweiten Kanal zur Kontrolle mal einzurichten. 
Eben um zu kontrollieren, ob und was denn nun in seinem µC am Ende so 
herein kommt. Und das unter Ausprobieren verschiedener Kabel.

W.S.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> Man könnte den SOF-Interrupt abschalten wenn er das
> erste Mal auftrat, und reaktivieren wenn man im suspend gelandet ist.

Das ist eigentlich eine super Idee... Ich habe das mal testweise im 
Branch disable-sof-irq umgesetzt. Dadurch spart man sich eine Menge 
Interrupts und möglicherweise Energie. Das geht mit dem Ansatz, im 
SOF-Interrupt das Senden abzuhandeln, nicht. Möchte jemand den Branch 
mal ausprobieren?

Um das eigentliche Problem hier anzugehen, würde ich mal einen 
Breakpoint in ClearBuffer und in den Interrupt an die Zeile mit 
'trace("out\n");' setzen, Daten vom PC senden und in den Breakpoints die 
USB-Register ansehen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ein kleiner Hinweis zum Tracen.

In "meiner" usb.c befindet sich ziemlich weit oben ein 
Konfigurations-parameter mit dem man das Tracing aktiviert. Darunter 
habe ich als Kommentar den Output von einer erfolgreichen Enumerierung 
eingefügt.

Leider hat der F0 keinen TraceSWO Ausgang, also muss man die trace() 
Funktion so umschreiben, dass sie auf eine andere Schnittstelle 
schreibt. UART wurde ja schon empfohlen.

Ich hatte mir die Mühe damals nicht gemacht, weil der Code auf meinem 
STM32L0 direkt auf Anhieb lief. Aber beim STM32F303RE war das für mich 
hilfreich - und vor allem die Erklärungen der zahlreichen Helfer, 
insbesondere W.S. und Niklas.

von Thomas Z. (usbman)


Lesenswert?

Niklas G. schrieb:
>> Man könnte den SOF-Interrupt abschalten wenn er das
>> erste Mal auftrat, und reaktivieren wenn man im suspend gelandet ist.
>
> Das ist eigentlich eine super Idee...

der SOF kommt eigendlich immer am Ende eines ms Frame. Der Host wird das 
Device auch nie in den Suspend schicken, solange das nicht im Deskriptor 
explizit eingeschaltet ist. Die Spec schreibt allerdings vor, dass ein 
Device beim ausbleiben des SOF innerhalb von 5ms?? In den powerdown 
gehen muss. Das ist sehr oft nicht richtig implementiert.
Allerdings kommen während der Enumerierung sehr oft Suspend Events 
genauso wie reset Events vor.

Suspend ist kein Paket sondern ein spezieller Zustand auf D+ und D- der 
dann als Suspend interpretiert wird

Da der SOF auch die PLL zum nachsteuern des USB Clocks beim TO steuert, 
bin ich mir nicht so sicher ob es eine gute Idee ist da rumzuspielen.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Thomas Z. schrieb:
> Die Spec schreibt allerdings vor, dass ein
> Device beim ausbleiben des SOF innerhalb von 5ms?? In den powerdown
> gehen muss. Das ist sehr oft nicht richtig implementiert.

Das sollte durch den Suspend Interrupt abgehandelt werden. Habe es aber 
nicht ausführlich getestet.

Thomas Z. schrieb:
> Allerdings kommen während der Enumerierung sehr oft Suspend Events
> genauso wie reset Events vor.

Sollte nicht schlimm sein, weil während der Enumerierung ja auch noch 
keine Configuration gesetzt ist und der VCP daher durchgängig "tot" ist.

Thomas Z. schrieb:
> Da der SOF auch die PLL zum nachsteuern des USB Clocks beim TO steuert,
> bin ich mir nicht so sicher ob es eine gute Idee ist da rumzuspielen.

Es wird ja lediglich der Software-Interrupt abgeschaltet. Der USB-Kern 
sollte das SOF ganz normal verarbeiten. Die Hardware sollte überhaupt 
nichts davon mitbekommen ob man auf den Interrupt reagiert oder nicht.

von Bernd N. (_bn_)


Lesenswert?

>> Möchte jemand den Branch mal ausprobieren?
gerne doch.

von Thomas Z. (usbman)


Lesenswert?

Niklas G. schrieb:
> Das sollte durch den Suspend Interrupt abgehandelt werden. Habe es aber
> nicht ausführlich getestet.

Das ist was anderes. Eigentlich muss ein Device fehlende  SOFs 
detektieren und dann selbstständig in den Powerdown gehen. Das ist 
übrigens ganz unabhängig davon ob das Device schon konfiguriert ist. 
(selfsuspend).
An genau dieser Stelle verhalten sich auch kommerzielle Geräte oft nicht 
Spec Konform.
Sowas würde übrigens bei den Plug Fests zumindest früher überprüft.

von temp (Gast)


Lesenswert?

Ich habe hier ein nucleo32 stm32f042 gefunden, mit dem habe ich mal 
experimentiert. Sowohl mit HSI als auch mit ext. Clock. Es geht beides. 
Beim HSI ergab ein 1ms Systick eine gemessene Frequenz von 9956 Hz. Nur 
so zur Info. Ich habe nicht versucht die Clockrestauration zu machen.
Deshalb schließe ich die Clockvariante als Fehler mittlerweile aus.

Allerdings bin ich bei den Versuchen über etwas gestolpert, was mit dem 
Problem von Axel zu tun haben könnte.
Ich hatte den rx-Ringbuffer auf 64byte eingestellt, und prompt kam genau 
1 beliebiges Commando vom hterm an, danach war Ende im Gelände beim 
Empfang.

Die Ursache ist einfach:
1
void OnEpBulkOut(void) /* EP2 = Bulk-EP OUT */
2
{
3
  int i, n, hdroom, avail;
4
  UMEM_FAKEWIDTH D;
5
  char c;
6
  UMEM_FAKEWIDTH* P;
7
8
  /* Bulk EP anwählen und Anzahl der Bytes ermittlen */
9
  avail = EpTable[2].RxCount & 0x3FF;
10
11
  i = rxw - rxr;
12
  if (i < 0)
13
    i += rxLen;
14
  hdroom = rxLen - i;
15
  if (hdroom <= avail) {
16
    receiving = false;
17
    return;
18
    }
19
20
  P = (UMEM_FAKEWIDTH*) EP2RxBBuffer;
21
  n = 2;
22
  i = avail;
23
  D = *P++; /* 2 Byte laden */
24
  while (i > 0)
25
    {
26
    c = D & 0xFF; /* LSB zuerst   */
27
    UsbRxBuf[rxw] = c;
28
    rxw = (rxw + 1) & (rxLen - 1);
29
    D = D >> 8;
30
    --n;
31
    if (!n)
32
      {
33
      D = *P++;
34
      n = 2;
35
      }
36
    --i;
37
    }
38
39
  if (hdroom - avail >= EpBulkMaxLen)
40
    ClearBuffer(logEpBulkOut); /* wir haben's gelesen */
41
  else
42
    receiving = false;
43
}

Hier gibt es 2 Stellen, wo aus dem Interrupt gesprungen wird ohne das 
ClearBuffer(logEpBulkOut); zu rufen. Wenn das ausbleibt, steht die 
Kiste. Wiederholt wird der Interrupt nicht. Bei meinem 64byte Ringbuffer 
schlägt dieser Vergleich aber immer fehl. Irgendwo im UsbGetChar steht 
dieses  ClearBuffer(logEpBulkOut); nochmal um den Knoten zu lösen. Das 
halte ich an dieser Stelle aber für nicht klug. Die UsbGetChar() sollte 
nur Daten aus dem Ringbuffer lesen, und nicht noch solche Hampeleien 
machen.

Ich bin aber noch nicht am Ende mit Nachdenken. Ich glaube ich baue das 
für mich so um, dass die Daten lieber verworfen werden und ein Errorflag 
gesetzt wird. Dann kann in diesem Interruptteilstück immer! das 
ClearBuffer(logEpBulkOut); gerufen werden. Das passt dann auch wieder 
zum UART. Da gehen die Daten auch verloren, wenn sie keiner abholt und 
die Buffer überlaufen.

von temp (Gast)


Lesenswert?

Hallo Axel versuch mal diese beiden Funktionen in deinem Code 
auszutauschen:
1
volatile uint32_t rxOverRun;
2
void OnEpBulkOut(void) /* EP2 = Bulk-EP OUT */
3
{
4
  EpCnt++;
5
  int i, n, hdroom, avail;
6
  UMEM_FAKEWIDTH D;
7
  char c;
8
  UMEM_FAKEWIDTH* P;
9
10
  /* Bulk EP anwählen und Anzahl der Bytes ermittlen */
11
  avail = EpTable[2].RxCount & 0x3FF;
12
13
  P = (UMEM_FAKEWIDTH*) EP2RxBBuffer;
14
  n = 2;
15
  i = avail;
16
  D = *P++; /* 2 Byte laden */
17
  while (i > 0)
18
    {
19
    c = D & 0xFF; /* LSB zuerst   */
20
    if (((rxw + 1) & (rxLen - 1)) == rxr)
21
      {
22
      rxOverRun++; 
23
      }
24
    else
25
      { 
26
      UsbRxBuf[rxw] = c;
27
      rxw = (rxw + 1) & (rxLen - 1);
28
      }
29
    
30
    D = D >> 8;
31
    --n;
32
    if (!n)
33
      {
34
      D = *P++;
35
      n = 2;
36
      }
37
    --i;
38
    }
39
  ClearBuffer(logEpBulkOut); /* wir haben's gelesen */
40
}

und
1
char UsbGetChar(void)
2
{
3
  char c=0;
4
  if (rxr != rxw)
5
    {
6
    c = UsbRxBuf[rxr];
7
    rxr = (rxr + 1) & (rxLen - 1);
8
    }
9
  return c;
10
}

Sollten damit deine Probleme nicht mehr auftreten, dann weißt du 
wenigstens aus welcher Ecke sie kommen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Bei meinem 64byte Ringbuffer
> schlägt dieser Vergleich aber immer fehl.

Hehe, W.S.' Ringpuffer-Implementation mit 2 Zeigern kann nur N-1 
Elemente speichern, wenn N die Größe ist. Dann klappt das nie. Wenn die 
Paketgröße 64 ist, muss der Puffer also 65 groß sein, oder man fügt noch 
einen Füllstand-Merker hinzu.

temp schrieb:
> Das
> halte ich an dieser Stelle aber für nicht klug.

Ich schon.

temp schrieb:
> Die UsbGetChar() sollte
> nur Daten aus dem Ringbuffer lesen, und nicht noch solche Hampeleien
> machen.

Ich finde es sinnvoll, den OUT-EP genau dann zu aktivieren, wenn man 
bereit ist Daten zu empfangen. Und das ist dann der Fall, wenn man mit 
UsbGetChar() den Puffer entsprechend geleert hat.

W.S. Original-Implementation macht es so wie du vorschlägst.

temp schrieb:
> Das passt dann auch wieder
> zum UART. Da gehen die Daten auch verloren, wenn sie keiner abholt und
> die Buffer überlaufen.

Finde ich nicht gut. Beim UART ist das auch nur so, wenn man keine 
Flusskontrolle nutzt. Der VCP ist praktisch UART mit Flusskontrolle. 
Wenn man die Daten nicht abholt, sollte man vom PC auch keine schicken 
können.

von Stefan F. (Gast)


Lesenswert?

Niklas G. schrieb:
> Wenn die
> Paketgröße 64 ist, muss der Puffer also 65 groß sein, oder man fügt noch
> einen Füllstand-Merker hinzu.

Guter Punkt, das werde ich mal Quelltext entsprechend kommentieren.

von Stefan F. (Gast)


Lesenswert?

Mal was anderes: Ich könnte schwören, dass ich auf dem PC einfach

> cat /dev/ttyACM0

benutzen konnte, um Text-Meldungen vom µC --> PC anzuzeigen. Neuerdings 
geht das nicht mehr, weiß der Teufel warum (auch nicht als root). Aber 
mit jedem beliebigen Terminalprogramm kann ich den Port wie gewohnt 
öffnen und nutzen.

Hat da zufällig jemand einen Tipp für mich, was der Knackpunkt sein 
könnte?

von temp (Gast)


Lesenswert?

Niklas G. schrieb:
> Hehe, W.S.' Ringpuffer-Implementation mit 2 Zeigern kann nur N-1
> Elemente speichern, wenn N die Größe ist. Dann klappt das nie. Wenn die
> Paketgröße 64 ist, muss der Puffer also 65 groß sein, oder man fügt noch
> einen Füllstand-Merker hinzu.

Das ist mir selbst klar und es war ein Fehler von mir. Ich will auch 
nicht mit 64Byte Buffern arbeiten. Mir ist nur aufgefallen, dass sich 
das System dann genauso verhielt wie Alex es beschreiben hat.

Niklas G. schrieb:
> Ich finde es sinnvoll, den OUT-EP genau dann zu aktivieren, wenn man
> bereit ist Daten zu empfangen. Und das ist dann der Fall, wenn man mit
> UsbGetChar() den Puffer entsprechend geleert hat.
>
Das ist Ansichtssache

> W.S. Original-Implementation macht es so wie du vorschlägst.
Aber eben nicht ganz. Es gibt halt da die Stellen wo er einfach aus dem 
Interrupt rausspringt, und als Notanker ist die Hampelei im UsbGetChar 
verbaut. Und irgendjemand hat da drin auch noch den Aussprung 
programmiert wenn suspend gesetzt ist oder !configurationSet. Warum um 
Gottes Willen soll man in dem Zustand keine Daten mehr aus dem 
Ringbuffer holen?

Niklas G. schrieb:
> Finde ich nicht gut. Beim UART ist das auch nur so, wenn man keine
> Flusskontrolle nutzt. Der VCP ist praktisch UART mit Flusskontrolle.
> Wenn man die Daten nicht abholt, sollte man vom PC auch keine schicken
> können.

UART mit Flusskontrolle ist mir das letzte mal untergekommen als es noch 
kein Internet gab und Daten per Modem übertragen wurden.
Wenn eine 100% UART das Ziel ist hast du recht, aber heute sind 99,xx% 
der Anwendungen ohne Flußkontrolle. Und jede Wette auch Alex sein 
Projekt. Das ist ja eine Kette die sich von der Anwendung auf dem PC bis 
zum µC durchzieht. Wer von den Beteiligten benutzt denn regelmäßig 
Flußkontrolle?

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
>> Wenn die
>> Paketgröße 64 ist, muss der Puffer also 65 groß sein, oder man fügt noch
>> einen Füllstand-Merker hinzu.
>
> Guter Punkt, das werde ich mal Quelltext entsprechend kommentieren.

Mach es lieber nicht (oder richtig), denn es wird dann noch schlimmer. 
Wenn du in den Code schaust, wird häufig eine Maske gebaut aus buflen-1. 
Da kommt bei 256 eben 0xff raus. Versuch das mal mit 65...
Also immer schön bei den 2er Potenzen bleiben.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Wer von den Beteiligten benutzt denn regelmäßig Flußkontrolle?

Wir hatten die Diskussion schon weiter oben.

Diese Funktionen UsbGetChar/UsbPutChar darf sich jeder gerne so 
umschreiben, wie er sie braucht. Das ist ja durchaus überschaubar - auch 
für Leute wie mich, die von USB keine Ahnung haben.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Es gibt halt da die Stellen wo er einfach aus dem
> Interrupt rausspringt, und als Notanker ist die Hampelei im UsbGetChar
> verbaut.

Das ist kein Notanker, das ist der ganz normale Ablauf.

temp schrieb:
> Und irgendjemand hat da drin auch noch den Aussprung
> programmiert wenn suspend gesetzt ist oder !configurationSet.

Ich war das. Siehe git-History.

temp schrieb:
> Warum um
> Gottes Willen soll man in dem Zustand keine Daten mehr aus dem
> Ringbuffer holen?

Weil der PC das Gerät offenbar still legen will. Das Abholen der schon 
angekommenen Daten könnte man noch erlauben, ja.

temp schrieb:
> Wer von den Beteiligten benutzt denn regelmäßig
> Flußkontrolle?

Ich habe das vor 2 Jahren noch benutzt in einem Projekt, wo per UART 
Datenpakete von einem Sensor abgeschickt werden. Sehr praktisch zur 
Vermeidung von Overflows. Das Ganze wurde in dem alten Thread übrigens 
schon durchgekaut. Das sind übrigens alles Überlegungen, die man sich 
bei der direkten Verwendung von USB ohne VCP sparen kann. Aber wir 
wollten es ja "einfach" haben!

von Stefan F. (Gast)


Lesenswert?

Braucht sonst noch jemand einen Eimer um sich auszukotzen?

Komisch das der TO hier von allen am wenigstens Meckert, dabei ist er 
doch derjenige, der hier gerade wirklich ein akutes Problem hat.

von Stefan F. (Gast)


Lesenswert?

Ich habe nochmal getestet. Sowohl in meiner aktuellen Fassung als auch 
der von Niklas sehe ich keine Fehlfunktionen, wenn man mehr Daten sendet 
oder empfängt, als in den Puffer passen.

Meine Hauptschleife:
1
    while (1)
2
    {
3
        // LED On
4
        WRITE_REG(GPIOC->BSRR,GPIO_BSRR_BR13);
5
        delay_ms(100);
6
7
        UsbStrOut("Hello World!\n");
8
9
        // Send echo of received characters back
10
        while (UsbRxAvail())
11
        {
12
            char c=UsbGetChar();
13
            UsbCharOut(c);
14
        }
15
16
        // LED Off
17
        WRITE_REG(GPIOC->BSRR,GPIO_BSRR_BS13);
18
        delay_ms(1000);
19
    }

Ich kann mit dem Terminalprogramm wenige Zeichen bis einige hundert 
Zeichen am Stück senden (der USB Treiber teilt das natürlich auf), das 
Echo kommt vollständig zurück. Und es blockiert nichts.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Mach es lieber nicht (oder richtig), denn es wird dann noch schlimmer.
> Wenn du in den Code schaust, wird häufig eine Maske gebaut aus buflen-1.
> Da kommt bei 256 eben 0xff raus. Versuch das mal mit 65...
> Also immer schön bei den 2er Potenzen bleiben.

Verstehe, danke für den Hinweis.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich habe nochmal getestet. Sowohl in meiner aktuellen Fassung als auch
> der von Niklas sehe ich keine Fehlfunktionen, wenn man mehr Daten sendet
> oder empfängt, als in den Puffer passen.

Was du jetzt genau meinst weiss ich nicht, aber wenn du dich auf meinen 
Testvorschlag von oben beziehst hast du was falsch verstanden.
Ich unterstelle keinen eine Fehlfunktion, bei mir geht es ja auch schon 
lange.

Nur, als ich heute mit dem 64byte Buffer gespielt habe, was sowieso nie 
gehen konnte, ist mir ein ähnliches Verhalten wie bei Alex aufgefallen. 
Ich habe nur das erste Packet vom PC bekommen. Was Alex wie macht wissen 
wir alle nicht. Deshalb war mein Code-Vorschlag nur für ihn, mit dem 
Ziel ohne wenn und aber das ClearBuffer(logEpBulkOut); bei jedem Packet 
was reinkommt auszuführen. Wenn das funktioniert, braucht er nur noch 
diese beiden Funktionen bei sich zu analysieren. Wenn nicht hilft eine 
größere Glaskugel.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Ich unterstelle keinen eine Fehlfunktion,
> bei mir geht es ja auch schon lange.

Das wollte ich damit auch nicht sagen.

Ich wollte dem TO nur eine Bestätigung geben, dass die USB Software 
prinzipiell in Ordnung ist. Wenn er einen Softwarefehler hat, dann 
vermutlich in seinem eigenen Code den er drumherum gebaut hat.

von Thomas Z. (usbman)


Lesenswert?

Ich hatte ja versprochen einen Patch für DoGetStatus() einzustellen...
Der Patch ist fertig allerdings hab ich beim Testen festgestellt, das 
der Request nicht antwortet.

Ich habe festgestellt, dass GetFeature, SetFeature und GetStatus alle in 
einen Timeout reinlaufen. Da scheint noch ein prinzipielles Problem zu 
existieren.

Der VCP Comport selbst funktioniert problemlos. Es ist also eher ein 
formales Problem. Geprüft hab ich dieses mal mit den Sourcen von Stefan.
Mal schauen ob ich den Fehler finde.

von Alex (Gast)


Lesenswert?

Hallo Leute,

kurzer Zischenbericht zu meinen Versuchen:

Ich hab an das 'schlechte' Modul einen 24MHz TCXO drangebaut, mit 
PLL->48MHz.
Das Problem mit dem Senden von Kommandos bleibt aber bestehen.

Das hab ich definitiv nicht erwartet !!


@Stefan: Die Annahme, dass der Fehler in meinem Code liegt, teile ich 
:-)
Nächster Test: Neues Projekt, und mal nur den USB-Teil von euch + die 
Anpassungen an den Chip auf der 'schlechten' Hardware.

Alex

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Das hab ich definitiv nicht erwartet !!

Offenbar sind Taktprobleme damit ausgeschlossen.

Alex schrieb:
> Nächster Test: Neues Projekt, und mal nur den USB-Teil von euch + die
> Anpassungen an den Chip auf der 'schlechten' Hardware.

Klingt nach einem guten Plan

von Thomas Z. (usbman)


Lesenswert?

So die Ursache für die Timeouts habe ich gefunden..
Es ist das Stall(1); was natürlich falsch für Protokoll Stalls ist. 
Trotzdem muss da noch was anders sein.

von temp (Gast)


Lesenswert?

Was ich mir noch wünschen würde, ist eine Möglichkeit festzustellen, ob 
der PC den Port geöffnet oder geschlossen hat. Wenn man danach bei 
Google sucht, kommt man zu der Erkenntnis, dass das irgendwie nicht 
zuverlässig geht.
Hat hierzu jemand eine Idee?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Was ich mir noch wünschen würde, ist eine Möglichkeit festzustellen, ob
> der PC den Port geöffnet oder geschlossen hat. Wenn man danach bei
> Google sucht, kommt man zu der Erkenntnis, dass das irgendwie nicht
> zuverlässig geht.

Das haben wir doch alles schon durchgekaut:

Beitrag "Re: USB CDC von Stefan Frings und WS"

Das Gerät bekommt nichts davon mit, wenn ein Programm :COM1 o.ä. öffnet. 
So ist das halt beim VCP.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Niklas G. schrieb:
> Das haben wir doch alles schon durchgekaut:

Mag sein, ich habe auch nicht alle Forenbeiträge im Kopf.
Allerdings habt ihr folgendes doch nicht durchgekaut:

Man kann sehr gut das DTR Flag für diese Aufgabe benutzen. Ich habe das 
jetzt mal mit dem hterm probiert, mit canhacker und lt. Internet soll 
das steinalte Hyperterminal das auch beim Öffnen setzen und beim 
Schließen wieder resetten. Sicher viele andere Software auch und bei 
eigener kann man das selber einbauen. Beim hterm muss man einmalig DTR 
bei geöffnetem Port drücken. Danach setzt er das beim Öffnen und 
Schließen alleine.

Die Stelle im Code von WS würde dann so aussehen:
1
volatile bool bIsComPortOpen=false;
2
3
/* Zustand von DTR und RTS vom Host zum Gerät merken */
4
void VCOM_Read_DTR_RTS(void)
5
{
6
  if ((CMD.SetupPacket.wValue & 0x01)!=0)
7
    bIsComPortOpen=true;
8
  else
9
    bIsComPortOpen=false;
10
  Dtr_Rts = CMD.SetupPacket.wValue >> 8;
11
  ACK();
12
}

Ich werde das jedenfalls so benutzen, dass ich die Buffer leer mache
wenn der Port zu ist. Aber das kommt wie immer auch auf die Anwendung 
an. Ich nutze nur das hterm oft zum loggen, und da nervt es, wenn beim 
Öffnen und Schließen noch Daten aus den Buffern kommen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

temp schrieb:
> Man kann sehr gut das DTR Flag für diese Aufgabe benutzen.

Und ich dachte Flusskontrolle nutzt man nicht mehr... Das verlässt sich 
auch darauf dass das Programm das setzt. Ein eigenes Programm macht das 
eventuell nicht.

von temp (Gast)


Lesenswert?

Niklas, ich denke du hast ganz schön einen an der Waffel.
Unterlass doch einfach deine Beiträge, wenn sie so sind wie deine 
letzten beiden.

Niklas G. schrieb:
> Und ich dachte Flusskontrolle nutzt man nicht mehr... Das verlässt sich
> auch darauf dass das Programm das setzt. Ein eigenes Programm macht das
> eventuell nicht.

Was soll das? Unter Flusskontrolle verstehe ich was anders. Und ja, mag 
sein dass man das so nennen kann wenn man es wörtlich nimmt. Und ich 
will in meinem User-Code auch nichts mit Flusskontrolle zu tun haben. 
Punkt. Und was du machst und für richtig hältst ist mir sowas von 
Wumpe...

Aber was soll's, ich diskutiere mit dir nicht mehr. Die die es 
interessiert können und werden es benutzen wie sie wollen und die 
anderen lassen es bleiben.

Niklas G. schrieb:
> Ein eigenes Programm macht das
> eventuell nicht.

Ein eigenes Programm macht das was ich will. Mag sein dass das bei 
deinen anders ist.

von Alex (Gast)


Lesenswert?

Guten Morgen!
Update:

Das Hello World von S.F. Webseite läuft auf meiner 'schlechten' Hardware 
mit dem externen TCXO,
die runtergeschickten Zeichen kommen als Echo zurück.

Damit ist bewiesen, dass der Fehler an meinem Code liegt.

Weiter Updates folgen...

Alex

von temp (Gast)


Lesenswert?

Alex schrieb:
> Das Hello World von S.F. Webseite läuft auf meiner 'schlechten' Hardware
> mit dem externen TCXO,
> die runtergeschickten Zeichen kommen als Echo zurück.

Dann ist es so wie ich vermutet habe, die Daten werden irgendwann und 
irgendwie nicht mehr abgeholt und dann steht die Kiste. Ich hatte dir 
hier mal einen Test vorgeschlagen:
Beitrag "Re: STM32 USB Übertragungsproblem mit Code von S.F."
hast du das mal probiert?

von Alex (Gast)


Lesenswert?

Hallo temp,

ich hatte deinen Beitrag übersehen (bin bei eurer Diskussion leicht 
'ausgestiegen'), vielen Dank für die Erinnerung !!

Ich werds heute Abend ausprobieren und umgehend reporten!

DANKE!!

von Thomas Z. (usbman)


Lesenswert?

Hallo zusammen,
ich habs jetzt im wesentlichen zusammen:

1. der Configdescriptor ist ein byte zu lang (unkritisch)
2. OnGetStatus, OnGetSetFeature laufen wegen Sall(1) in einen Timeout
3. Stall() und UnStall() sind fehlerhaft

Überprüft habe ich das ganze mit Thesycons UsbIo Treiber, weil man damit 
jeden Chapter 9 Request einzeln absetzen kann. Da ich nur die V2.5 
besitze hab ich das ganze in einer VM unter W7 und XP getestetet, das 
aber nur am Rande.
1
void DoGetStatus(void)
2
{
3
   ...
4
    case 0x82: /* für einen Endpoint */
5
        trace("forEndpoint\n");
6
        switch (EP)
7
        {  
8
           /* nur für bulk + int eps notwendig
9
           case 0x80: //ctrl in
10
           case 0x00: //ctrl out  */
11
           case 0x02: //bulk out stall condition
12
                if (((USB_EP2R >> 12) & 0x03) ==1) Buf[0] = 1;
13
                break;
14
           case 0x81: //bulk in stall condition
15
                if (((USB_EP1R >>  4) & 0x03) ==1) Buf[0] = 1;
16
                break;
17
           case 0x83: //interrupt in stall condition
18
                if (((USB_EP3R >>  4) & 0x03) ==1) Buf[0] = 1;
19
                break;
20
           default:
21
                StallLogEP(logEpCtrl); 
22
                return;
23
         }
24
    ...
25
}

Stall bzw UnSTall ist kritischer, da ist STAT_RX bzw STAT_TX verdreht. 
Das hat mich etwas Zeit gekostet wegen der Magic Numbers.
Der Einfachheit halber hab ich einfach die Abfrage von != auf == 
geändert,
was bei STall() funktioniert bei Unstall aber nicht. Da muss ich die XOR 
Bedingungen noch anpassen. Generell bin ich mir beim XOR unsicher ob das 
die Togglebedingungen immer richtig abbildet, da muss ich noch etwas 
nachdenken.

Ich hab mir allerdings noch nicht überlegt ob das alles auch richtig 
wäre wenn man zB beide BulkEps auf einen bidirektionalen Endpoint legen 
würde.

von Stefan F. (Gast)


Lesenswert?

Thomas, kann ich das so 1:1 in die usb.c rein kopieren oder hängen damit 
noch andere notwendige Anpassungen zusammen?

von Thomas Z. (usbman)


Lesenswert?

Der gezeigte Code ist zwar korrekt und getestet. Das ist aber noch nicht 
alles. Ich würde warten, bis ich usb.c hochlade. Dann ist auch alles 
drin. Meine Änderungen beziehen sich ja nur auf USB Funktionen. Am VCP 
hab ich nichts gemacht.
Wie gesagt noch gibt's ein Problem beim UnStall().

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Ich würde warten, bis ich usb.c hochlade.

Ok, dann warte ich ab und hoffe dass es dann korrekt funktioniert. Weil: 
Fachlich kann ich euch da nicht folgen, dazu habe ich zu wenig (fast gar 
keine) Ahnung von USB.

von Alex (Gast)


Lesenswert?

Ich hab die beiden Funktionen, die temp mir oben (24.02.2021 15:41) 
vorgeschlagen hat mal reinkopiert, und es hat funktioniert !!!!

Nur um zu verifizieren, dass das die Ursache wirklich adressiert, hab 
ich wieder auf die beiden vorigen Funktionen zurückgestellt, und es hat 
auch funktioniert kopfkratz.

Ich glaub ich hab mittlerweile so heftig in dem Code rumgepfuscht, dass 
ich nicht mehr sauber nachvollziehen kann, wann ich was ausprobiert 
habe. Ein log hab ich nicht gemacht (schäm).

Ich schließ micht jetzt mal dem Stefan beim Warten an, und verwende die 
Version die Thomas dann hochlädt. Sonst wird der Saustall in meinem Code 
noch schlimmer..

von Johannes S. (Gast)


Lesenswert?

Da macht es Sinn sich mal mit git zu beschäftigen.

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> hab ich wieder auf die beiden vorigen Funktionen zurückgestellt,
> und es hat auch funktioniert kopfkratz.

Hast du vielleicht ganz knapp zu wenig RAM (Stack versus Heap Überlauf)?

Das müsste sofort eindeutig werden, wenn du den Sende-Puffer (txLen) mal 
deutlich größer oder kleiner machst. Zum Beispiel 16 Bytes versus 1024 
Bytes.

(txLen muss nicht >64 sein, aber eine Zweierpotenz (4,8,16,32,...)

von temp (Gast)


Lesenswert?

Alex schrieb:
> Ich hab die beiden Funktionen, die temp mir oben (24.02.2021 15:41)
> vorgeschlagen hat mal reinkopiert, und es hat funktioniert !!!!
>
> Nur um zu verifizieren, dass das die Ursache wirklich adressiert, hab
> ich wieder auf die beiden vorigen Funktionen zurückgestellt, und es hat
> auch funktioniert kopfkratz.

Das war jetzt auch mit dem exterenen Takt oder mit dem HSI48?

von temp (Gast)


Lesenswert?

Ich hatte bei meinem STM32F042 auch mal am Takt gespiel mit einem LED 
Tooglen in einem 1ms Systick-Handler:

HSE:           499.9 Hz

HSI:           497.6 Hz

HSI48:         505.0 Hz

HSI48 mit CRS: 499.9 Hz

nur um mal eine Hausnummer zu haben wieweit der Takt bei mir abweicht.
Zuerst hatte ich in geistiger Umnachtung versucht den HSI mit CRS gerade 
zu rücken. Natürlich ohne Erfolg. Dafür aber wieder was gelernt.

Wenn dich der Teil interessiert:
1
void SetSysClockHsi48()
2
{
3
  RCC->CR2 |= RCC_CR2_HSI48ON;
4
 
5
  // Wait till HSI48 is ready
6
  while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0)
7
    ;
8
  
9
  // Enable Prefetch Buffer and set Flash Latency 
10
  FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
11
 
12
  // HCLK = SYSCLK 
13
  RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
14
      
15
  // PCLK = HCLK 
16
  RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
17
18
  // Select PLL as system clock source 
19
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
20
  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSI48;    
21
22
  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_HSI48)
23
    ;  
24
25
  // CRS einschalten
26
  RCC->APB1ENR|=RCC_APB1ENR_CRSEN;
27
  CRS->CR|=CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
28
}

von temp (Gast)


Lesenswert?

der Kommentar:
1
// Select PLL as system clock source
ist natürlich Blödsinn...

von J. -. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Wie gesagt noch gibt's ein Problem beim UnStall().
Gut, daß Du das testen kannst.

Inzwischen habe ich den Code auch auf einer Bluepill mit 
Original-STM32F103C8T6 getestet (zuvor auf einem F103RCT6), und er läuft 
ebenfalls gut. Wobei mir die Stalls bzw. Bugs vielleicht bei meinen 
Anwendungen gar nicht auffallen.
Ich steuere über die Bluepill einen RFM69, der an andere RFM69 Daten und 
auch ganze AVR-Programme überträgt. da flutschen also schon auch 
'größere' Datenmengen von bis zu 16kB hin und her, abwechselnd mit 
Mini-Paketchen von 1-7 bytes als Statusbericht. Kein Problem bisher.
Aus Begeisterung habe ich sogar der Bluepill einen Erkennungsstring 
verpaßt. Das PC-Programm klappert alle Comports durch, ob sie einen 
bekannten string senden, um die Bluepill auch auf verschiedenen PCs 
anschließen zu können. Hat sofort funktioniert - mit den alten 
usb-Dateien war das ein Gekrampfe mit Timing, Aufhängern etc..

von Alex (Gast)


Lesenswert?

Ging sowohl mit HSI48 als auch mit dem HSE.

Ganz ausschließen kann ich die Takt-Geschichte glaub ich nicht, weil die 
CRS mittelt ja die Taktabweichung immer über 1ms, wenn die Schwankungen 
innerhalb dieser ms aber sehr groß sind, könnte das durchaus ein Problem 
für den USB sein.
Meine Chips sind im TSOP20-Package, die haben leider keinen MCO (main 
clock out) als Alternate Function.
Sonst hätte ich mit einem Frequenzzähler mal bei kürzerer gatetime den 
jitter verglichen...

von Alex (Gast)


Lesenswert?

> Hast du vielleicht ganz knapp zu wenig RAM (Stack versus Heap Überlauf)?
Ram hab ich jede Menge, der Flash ist mir ziemlich knapp...

von Thomas Z. (usbman)


Angehängte Dateien:

Lesenswert?

in folgenden Funktionen hab ich was verändert:

Stall();
UnStall;
DoGetSetFeature();
DoGetStatus();
und bei SetInterface.

Ein paar Kleinigkeiten bei den Deskriptoren sind unwesendlich ich hab da 
nur ein paar Dinge geändert um in Zukunft flexibler zu sein.

Bei SetInterface lösche ich die ToggleBits, wie von der Spec verlangt. 
Da ich nicht genau weis wann usbserial.sys SetInterface absetzt kann 
dies sich auch auf den VCP auswirken. Meine Tests waren zwar erfolgreich 
aber der Teufel steckt ja bekanntlich im Detail.

Alle anderen Änderungen sollten sich nicht auf den VCP auswirken, Sie 
betreffen lediglich die Kompatibilität mit der Spec. Die VCP 
ClassRequests habe ich noch nicht geprüft, Ich gehe aber davon aus, dass 
die ok sind.

Eine Änderung hätte ich noch für die Zukunft:
Im Moment melden sich ja alle Devices mit der gleichen Seriennumer.
Besser wäre es die Serien Nummer aus dem Chip zu lesen oder abschaltbar 
zu machen.

Viel Spass beim Ausprobieren.

von J. -. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Im Moment melden sich ja alle Devices mit der gleichen Seriennumer.
> Besser wäre es die Serien Nummer aus dem Chip zu lesen oder abschaltbar
> zu machen.
gute Idee

Ich habe gerade Dein usb.c mit der Bluepill verwendet (schreibe bewußt 
nicht getestet, weil ich das gar nicht kann), und es geht nach wie vor, 
also bleibt das neue usb.c drin ;-). Danke dafür.

2 Sachen noch:
1.)
Nop habe ich wieder durch
1
void Nop(volatile uint32_t count)
2
{
3
  while(count--);
4
}
ersetzt, damit es nicht wegoptimiert werden kann.

2.)
Woran ich beim letzten Mal geknobelt habe:
Oben in der usb.c steht
#define NAME_OF_USB_IRQ_HANDLER USB_LP_CAN_RX0_IRQHandler
und der Hinweis, daß der Name des Handlers mit startup_stm32.s matchen 
muß.
Coocox- bzw. SPL-User rennen vielleicht auch in die Falle; es gibt keine 
Fehlermeldung, aber der Handler USB_LP_CAN_RX0_IRQHandler wird nicht 
angesprungen.
Es sollte in diesem Fall USB_LP_CAN1_RX0_IRQHandler heißen.

von Thomas Z. (usbman)


Lesenswert?

Jürgen S. schrieb:
> Ich habe gerade Dein usb.c

na ja meine usb.c ist sehr übertrieben wenn schon ist das von W.S. mit 
Änderungen von einigen Forenmitgliedern.
Ich hab das bewusst im Original Stil belassen, und auch deshalb deutsche 
Kommentare verwendet.

Ich persönlich würde sowas genau wie W.S. machen auch wenn mein Code Sil 
natürlich ein etwas anderer wäre. Bare Metal Rules.
Ich lege allerdings sehr viel Wert auf Kompatibilität zur Spec. Viele 
meiner Devices laufen unabhängig vom OS seit XP, oder Linux ohne dass 
eine Zeile verändert wurde.
Da wäre z.B. zu sagen, dass VCP eigendlich IAD Deskriptoren vorschreibt. 
Das habe ich bewusst weggelassen, weil's bisher noch nicht notwendig 
ist, und noch funktioniert. Ich habe allerdings VCPs mit IAD am laufen.

Die zwei Dinge die du anmerkst sind genauso in der Version von Stefan 
drin. Mit den zig IDEs stehe ich etwas auf Kriegsfuss.

von Stefan F. (Gast)


Lesenswert?

Danke Thomas, ich habe deine Änderungen auf meine Homepage übernommen 
und noch ein bisschen aufgeräumt (Formatierung und Reihenfolge der 
Abschnitte).

Auch Danke an Dich Jürgen. Ich habe das volatile hinzugefügt aber das 
NOP stehen gelassen weil ich unsicher bin, ob das wirklich
bei jedem Compiler weg gelassen werden darf.

von Stefan F. (Gast)


Lesenswert?

Ich habe die API zum Anwendungsprogramm hin erweitert.

Es gibt dort jetzt eine neue Funktionen mit der man testen kann, ob ein 
bestimmtes Zeichen im Empfangspuffer liegt (zum Beispiel '\n').

Ich habe Funktionen zum Senden und Empfangen von Zeichenketten sowie 
Datenpaketen mit fester Länge hinzugefügt.

Bei den Funktionen zum Senden/Empfangen kann man jetzt einen Timeout 
angeben.

Wer daran Interesse hat, kann sich das von meiner Homepage downloaden:
http://stefanfrings.de/stm32/index.html

von Stefan F. (Gast)


Lesenswert?

Thomas Z, ich habe noch eine kleine Bitte an dich. Der Code enthält 
vermutlich noch einen alten Bug. Mit "alt" meine ich, das ich den Effekt 
schon vor unseren Änderungen bemerkt hatte.

Wenn ich den Port /dev/ACM0 mit Cutecom öffne sehe ich jede Sekunde die 
erwartete Meldung "Hello World!".

Wenn ich nun etwas zum Senden eintippe, dann sendet der µC diesen String 
als Echo zurück. Manchmal beginnt das Echo aber mit einem Fragment von 
"Hello World!", zum Beispiel:

Ich Sende:  bla
Ich empfange: Helbla

Wenn ich main.c auf dem Mikrocontroller so ändere, dass das Echo doppelt 
zurück gesendet wird, dann passiert dies:

Ich Sende:  bla
Ich empfange: Helbla
Ich empfange: Helbla

Ich Sende:  gaga
Ich empfange: Hellgaga
Ich empfange: Hellgaga

Da scheint ein Zusammenhang bezüglich der Anzahl der Zeichen zu 
bestehen.

Der Effekt tritt nur bei ersten gesendeten String auf. Danach nicht 
mehr. Und es passiert auch nicht immer.

Es wäre super, wenn du mal danach schauen könntest. Vielleicht hast du 
eine Idee, woran das liegen könnte.

von Stefan F. (Gast)


Lesenswert?

Thomas, ich habe noch eine Info dazu: Diese Problem aus meinem 
vorherigen Beitrag tritt unter Windows 10 nicht auf.

Unter Linux aber häufig. Es ist Debian Testing mit Kernel 5.10.13-1.

von Thomas Z. (usbman)


Lesenswert?

Ich schau mir das mal an, wird allerdings etwas dauern. Vielleicht hab 
ich dann auch schon die Sache mit der SN eingebaut.
Ich hab die Conig Params  zusammengefasst beim Keil bekommt man dann ein 
Einstellmenu. In anderen IDEs sind es weiterhin nur defines.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

In Ubuntu 20.04 (Live Stick) mit Kernel 5.8.0-43-generic tritt der 
Fehler auch auf.

Ich habe inzwischen eine Methode gefunden, den Fehler schneller 
auszulösen. Und zwar Klicke ich links oben wiederholt auf den Open/Close 
Button. Manchmal erscheinen dann falsche Zeichen. Der Fehler tritt sogar 
im read-only Modus auf.

Was mir dabei sehr auffällt ist: Die falschen Zeichen sind immer 
Buchstaben aus "Hello World!" oder LF oder CR. Niemals andere 
Buchstaben.

von Thomas Z. (usbman)


Angehängte Dateien:

Lesenswert?

Stefan, kannst du mal tracen was unter linux bei open/close für Requests 
kommen? Ich erwarte da ein paar ClassRequests, die hab ich bisher noch 
garnicht getestet.


Anbei ein Bild meines ConfigMenus und hier der source dafür:
Die core Einstellungen laufen schon die VCP Einträge machen noch nichts
1
/* USB als virtuellen COM Port betreiben */
2
#include "usb.h"
3
4
// <<< Use Configuration Wizard in Context Menu >>>
5
// <h> Configuration for STM bare metal VCP
6
// <h> CORE params
7
8
// <o> UMEMSHIFT      <0=> off
9
//                    <1=> on
10
// <i> Off for devicec like STM32L0x2, STM32L0x3, STM32F0x2, STM32F303xD and xE
11
// <i> On  for devicec like STM32F103, STM32F302, STM32F303xB and xC                
12
#define UMEM_SHIFT     1
13
14
// <o> USB_IRQ_NUMBER <0-31>
15
// <i> Take the number from the reference manual for ypor controller
16
#define USB_IRQ_NUMBER 20
17
18
// <o>  ENABLE_TRACING <0=> false
19
//                     <0=> true
20
// <i>  Enable trace messages via SWO
21
#define ENABLE_TRACING 0
22
23
// </h>
24
// <h> VCP params
25
26
// <o> USB_VID         <0-0xFFFF>
27
// <i> USB Vendor ID
28
#define USB_VID        0x0416
29
30
// <o> USB_PID         <0-0xFFFF>
31
// <i> USB Prodct ID
32
#define USB_PID        0x5011
33
34
// <o> USB_SERIAL      <0=> none>
35
//                     <1=> fixed>
36
//                     <2=> from chip
37
// <i> Select what kind of USB Serial Number is used
38
#define USB_SERIAL     0 
39
40
// <o> IAD_SUPPORT     <0=> false
41
//                     <1=> true
42
// <i> Enable extra IAD conform descriptors
43
// <i> Spec requires IAD for devices using which use 2 or more interfaces for one function
44
// <i> although neither WIN nor Linux requires that up to now
45
#define IAD_SUPPORT    0  
46
47
// <o> VCP_IN_EP       <0x81=> EP1 In
48
//                     <0x82=> EP2 In
49
//                     <0x83=> EP3 In
50
//                     <0x84=> EP4 In
51
//                     <0x85=> EP5 In
52
//                     <0x86=> EP6 In
53
//                     <0x87=> EP7 In
54
#define VCP_IN_EP      0x81
55
56
// <o> VCP_OUT_EP      <0x01=> EP1 Out
57
//                     <0x02=> EP2 Out
58
//                     <0x03=> EP3 Out
59
//                     <0x04=> EP4 Out
60
//                     <0x05=> EP5 Out
61
//                     <0x06=> EP6 Out
62
//                     <0x07=> EP7 Out
63
#define VCP_OUT_EP     0x02 
64
65
// <o> VCP_STAT_EP     <0x81=> EP1 In
66
//                     <0x82=> EP2 In
67
//                     <0x83=> EP3 In
68
//                     <0x84=> EP4 In
69
//                     <0x85=> EP5 In
70
//                     <0x86=> EP6 In
71
//                     <0x87=> EP7 In
72
#define VCP_OUT_EP     0x83
73
74
// <<< end of configuration section >>>
75
....

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Beim Einstecken bekomme ich:
1
RESET
2
InitEndpoints
3
setAddr adr=0
4
CTR out
5
logEpCtrl
6
SETUP
7
rdCtrlBlock maxlen=8, count=8
8
clrBuf logEpNum=0
9
isStandardRequest
10
GET_DESCRIPTOR
11
doGetDescr type 0001
12
descDevice
13
wrCtrlBlock count=18
14
validateBufvalidateBuf logEpNum=1

Beim Öffnen des COM Portes:
1
CTR in
2
logEpBulkIn
3
validateBuf logEpNum=1
4
CTR out
5
logEpCtrl
6
SETUP
7
rdCtrlBlock maxlen=8, count=8
8
clrBuf logEpNum=0
9
IsClassRequest
10
SET_CONTROL_LINE_STATE
11
wrCtrlBlock count=0
12
validateBuf logEpNum=0
13
CTR in
14
logEpBulkIn
15
validateBuf logEpNum=1
16
CTR out
17
logEpCtrl
18
SETUP
19
rdCtrlBlock maxlen=8, count=8
20
clrBuf logEpNum=0
21
IsClassRequest
22
SET_LINE_CODE
23
wrCtrlBlock count=0
24
validateBuf logEpNum=0
25
CTR out
26
logEpCtrl
27
EpCtrlOut
28
IsClassRequest
29
SET_LINE_CODE
30
rdCtrlBlock maxlen=7, count=7
31
clrBuf logEpNum=0
32
wrCtrlBlock count=0
33
validateBuf logEpNum=0
34
wrCtrlBlock count=0
35
validateBuf logEpNum=0
36
CTR in
37
logEpCtrl
38
CTR in
39
logEpBulkIn
40
validateBuf logEpNum=1
41
CTR out
42
logEpBulkOut
43
clrBuf logEpNum=2
44
CTR in
45
logEpBulkIn
46
validateBuf logEpNum=1
47
CTR in
48
logEpBulkIn
49
validateBuf logEpNum=1
50
CTR in
51
logEpBulkIn
52
validateBuf logEpNum=1
53
CTR in
54
logEpBulkIn
55
validateBuf logEpNum=1validateBuf logEpNum=1
56
CTR in
57
logEpBulkIn
58
validateBuf logEpNum=1
59
CTR in
60
logEpBulkIn
61
validateBuf logEpNum=1
62
CTR in
63
logEpBulkIn
64
validateBuf logEpNum=1
65
CTR in
66
logEpBulkIn
67
validateBuf logEpNum=1
68
CTR in
69
logEpBulkIn
70
validateBuf logEpNum=1
71
CTR in
72
logEpBulkIn
73
validateBuf logEpNum=1
74
CTR in
75
logEpBulkIn

Beim Schließen des COM Portes:
1
validateBuf logEpNum=1
2
CTR in
3
logEpBulkIn
4
validateBuf logEpNum=1
5
CTR in
6
logEpBulkIn
7
validateBuf logEpNum=1
8
CTR in
9
logEpBulkIn
10
validateBuf logEpNum=1
11
CTR in
12
logEpBulkIn
13
validateBuf logEpNum=1
14
CTR in
15
logEpBulkIn
16
validateBuf logEpNum=1
17
CTR in
18
logEpBulkIn
19
CTR out
20
logEpCtrl
21
SETUP
22
rdCtrlBlock maxlen=8, count=8
23
clrBuf logEpNum=0
24
IsClassRequest
25
SET_LINE_CODE
26
wrCtrlBlock count=0
27
validateBuf logEpNum=0
28
CTR out
29
logEpCtrl
30
EpCtrlOut
31
IsClassRequest
32
SET_LINE_CODE
33
rdCtrlBlock maxlen=7, count=8
34
clrBuf logEpNum=0
35
wrCtrlBlock count=0
36
validateBuf logEpNum=0
37
wrCtrlBlock count=0
38
validateBuf logEpNum=0
39
CTR out
40
logEpCtrl
41
SETUP
42
rdCtrlBlock maxlen=8, count=8
43
clrBuf logEpNum=0
44
IsClassRequest
45
SET_CONTROL_LINE_STATE
46
wrCtrlBlock count=0
47
validateBuf logEpNum=0
48
CTR in
49
logEpCtrl
50
validateBuf logEpNum=1

Ich habe keine Ahnung, was das alles bedeutet. Hoffentlich hilft es dir.

von Stefan F. (Gast)


Lesenswert?

Ich finde das sehr auffällig:
1
validateBuf logEpvalidateBuf logEpNum=1

Allerdings kann ich da keinen 1:1 Zusammenhang zu den unerwarteten 
Zeichen an COM Port finden. Beides tritt unabhängig voneinander auf.

In den allermeisten Fällen sehen die Trace Meldungen so aus, während der 
Fehler auftritt:
1
validateBuf logEpNum=1    --> Hello World!
2
CTR in
3
logEpBulkIn
4
validateBuf logEpNum=1    --> Hello World!
5
CTR in
6
logEpBulkIn
7
validateBuf logEpNum=1    --> Hello World!
8
CTR in
9
logEpBulkIn
10
CTR out                   <-- qqq
11
logEpBulkOut
12
clrBuf logEpNum=2
13
validateBuf logEpNum=1    --> Hqqq   (das H ist hier falsch)
14
CTR in
15
logEpBulkIn
16
validateBuf logEpNum=1    --> Hello World!
17
CTR in
18
logEpBulkIn
19
validateBuf logEpNum=1    --> Hello World!
20
CTR in
21
logEpBulkIn

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Ich bin ein Stück weiter. Die folgende main() Funktion zeigt mir, dass 
der Fehler in dem Moment des Öffnens vom COM-Port auftritt.

Dass ich den Fehler vorher erst nach Eingabe einer Zeichenkette (im 
CuteCom) gesehen habe lag daran, dass das Programm vorher alle 
hereinkommenden Zeichen bis zum ersten LF sammelte.
1
int main(void)
2
{
3
    // Initialize system timer
4
    SysTick_Config(SystemCoreClock/1000);
5
6
    init_io();
7
    UsbSetup();
8
9
    while (1)
10
    {
11
        // LED On
12
        WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BS5);
13
        WRITE_REG(GPIOC->BSRR, GPIO_BSRR_BR13);
14
        delay_ms(100);
15
16
        UsbSendStr("Hello World!\n",10);
17
        // Alternative: puts("Hello World!");
18
19
        // Echo received characters
20
        while (UsbRxAvail())
21
        {
22
          UsbSendStr("rx:",10);
23
          char c;
24
          UsbGetChar_noWait(&c);
25
          UsbSendChar(c, 10);
26
                UsbSendChar('\n', 10);
27
        }
28
29
        /*
30
        // If a line has been received, then send an echo back
31
        if (UsbRxBufferContains('\n'))
32
        {
33
            char buf[256];
34
            UsbGetStr(buf,sizeof(buf),'\n',0);
35
            UsbSendStr(buf,10);
36
        }
37
        */
38
39
        // LED Off
40
        WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BR5);
41
        WRITE_REG(GPIOC->BSRR, GPIO_BSRR_BS13);
42
        delay_ms(900);
43
    }
44
45
}

Die Ausgabe zeigt ganz deutlich dass der µC seine "Hello World!" 
Meldungen einwandfrei sendet. Aber kurz nach dem Öffnen des COM Portes 
empfängt er fälschlicherweise ein unerwartetes Fragment, scheinbar aus 
dem Sende-Puffer.

von W.S. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Woran ich beim letzten Mal geknobelt habe:
> Oben in der usb.c steht
> #define NAME_OF_USB_IRQ_HANDLER USB_LP_CAN_RX0_IRQHandler
> und der Hinweis, daß der Name des Handlers mit startup_stm32.s matchen
> muß.
> Coocox- bzw. SPL-User rennen vielleicht auch in die Falle; es gibt keine
> Fehlermeldung, aber der Handler USB_LP_CAN_RX0_IRQHandler wird nicht
> angesprungen.
> Es sollte in diesem Fall USB_LP_CAN1_RX0_IRQHandler heißen.

Das hat Stefan eingeführt und ich bin mit so etwas nicht glücklich. 
Ich war ganz früher auch mal auf diesem Trip, aber mittlerweile stehe 
ich auf dem Standpunkt, daß ein usb.c eben nur genau für den Chip sein 
soll, für den er geschrieben ist.
Und wenn der gleiche Quellcode zu 99.9% auch für einen anderen Chip 
brauchbar sein sollte, dann ändert man die restlichen 0.1% und speichert 
ihn unter anderem Namen oder woanders ab, so daß eben immer gilt:
  1 Plattform = 1 Handler.
Soviel Platz haben wir mittlerweile auf unseren Festplatten. Wenn man 
das so tut, dann braucht man auch keine Flags in der Quelle, keine 
unnötigen externen Referenzen, keine #ifdef und so weiter.
Vielleicht sollte man sich mal auf irgend eine Förmlichkeit einigen, 
z.B.:
usb_stf103.c
usb_lpc4088.c
usb_nuc120.c
und so ähnlich.

W.S.

von W.S. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Ich lege allerdings sehr viel Wert auf Kompatibilität zur Spec.

Und hast du selbige da und darfst du sie auch mal posten?
Originalunterlagen würde ich mir gern mal ansehen.

W.S.

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Es gibt dort jetzt eine neue Funktionen mit der man testen kann, ob ein
> bestimmtes Zeichen im Empfangspuffer liegt (zum Beispiel '\n').
>
> Ich habe Funktionen zum Senden und Empfangen von Zeichenketten sowie
> Datenpaketen mit fester Länge hinzugefügt.

Also Stefan, da knurrt aber der Blindenhund ganz gewaltig!

Also: der USB-Treiber ist der Lowlevel-Treiber, was du hingegen machst, 
ist etwas, das 1..2 Ebenen höher angesiedelt ist. Also soll das auch in 
eine andere Quelle, die sich nur um das von dir Angesprochene kümmert 
und die je nach Bedarf auch andere LL-Treiber benutzt, z.B. einen für 
einen UART.

Ich häng dir mal so etwas ähnliches zur Ansicht dran, damit du siehst, 
wie z.B. ich da etwas Ordnung in die Datenströme kriege. Die Datei ist 
eine Vorlage, die an die konkrete Plattform angepaßt wird. Manche haben 
keinen UART0, andere keine UART6..7..sonstwas. Obendrein gibt es bei den 
meisten µC-Anwendungen bei mir auch kein Kommandofenster und kein 
Filesystem und deshalb auch keine Textfiles, dennoch ist sowas wie 
CharToFileStream(..) oder CharToCommandWindow(..) formal vorgesehen. Die 
Anwendungseben spricht bei mir NIEMALS den usb.c oder serial.c oder so 
an, sondern macht das grundsätzlich nur über gio.c.

Und weil es bei mir häufig vorkommt, daß einige Programmstücke nicht 
wissen (sollen), was der aktuelle I/O-Kanal ist, gibt es in Analogie zum 
PC sowas wie stdout und stdin als generalisierten Kanal.

Und jetzt kommst du und wirfst das Zusammensetzen von Kommandozeilen und 
Datenpaketen in den LL-Treiber, wo sowas definitiv nicht hin gehört.

Und mal abgesehen davon, erzeugst du damit firmwareinterne Probleme: Was 
ist, wenn eine gewünschte Pufferlänge größer ist als der FIFO des 
LL-Treibers? Ich denke da grad an eine meiner Anwendungen zum 
Programmieren von µC, wo ich einen Programmierpuffer habe, der 2..8K 
oder so groß ist.

Nein, der Ringpuffer im LL-Treiber dient NUR zur Entkopplung und nicht 
als Puffer für eine Kommandozeile oder eines sonstigen 
anwendungsspezifischen Blockpuffers. Sowas muß separat gemacht werden 
und es gehört auch logisch auf eine höhere Ebene.

W.S.

von Alex (Gast)


Lesenswert?

Zu dem Thema mit der Seriennummer kann ich vielleicht etwas beitragen.
Ich nutze dazu die Unique ID vom STM. Die StringSerial ist bei mir keine 
Konstante, sondern eine Variable, die in der UsbSetup() gesetzt wird.
1
// Device ID vom chip zum Erzeugen einer USB-Seriennummer
2
// STM32F042: Device ID:   @ 0x1FFF F7AC +0 +4 +8 (3x32bit)
3
#define DEVICE_ID_ADDRESS         (0x1FFFF7AC)  
4
#define DEVICE_ID_SIZE          (12)//in bytes

Folgenden Block hab ich in die UsbSetup() eingefügt:
1
    // read Unique ID and generate serial number for the USB
2
    char c;
3
    int j;
4
    uint8_t* idB;
5
    uint8_t x;
6
  StringSerial[0] = DEVICE_ID_SIZE*2 + 2; //
7
  StringSerial[1] = DESC_STRING;
8
9
  for (j = DEVICE_ID_SIZE*2*2 + 2, idB = (uint8_t*)(DEVICE_ID_ADDRESS + DEVICE_ID_SIZE-1); j>2; idB--)
10
  {
11
    x = *idB;
12
    c = (char)(x & 0x0F);
13
    if (c < 10)
14
      c += 0x30;
15
    else
16
      c += 0x37;
17
    StringSerial[--j] = 0;
18
    StringSerial[--j] = c;
19
    x >>= 4;
20
    c = (char)(x & 0x0F);
21
    if (c < 10)
22
      c += 0x30;
23
    else
24
      c += 0x37;
25
    StringSerial[--j] = 0;
26
    StringSerial[--j] = c;
27
  }
28
  // serial number finished

Ich bin mir aber nicht sicher, ob die Seriennummer dann nicht zu lang 
ist.
Im Gerätemanager werden nur 12 von den 24 hex digits angezeigt.

Ist sicher noch verbesserungswürdig, aber funktioniert bei mir.

von Alex (Gast)


Lesenswert?

@ Stefan und W.S.

Ich denke W.S. hat mir seiner Kritik einen wichtigen Punkt getroffen.

Ich hatte bei mir im Code auch eine Zusatzfunktion eingefügt, mit der im 
Empfangsbuffer auf ein CR oder LF geprüft wurde.
Erst dann wurden die Daten weiterverarbeitet.

Ich glaube, dass das mit ein Grund war, warum der Code bei mir solche 
Schwierigkeiten gemacht hat.

von Stefan F. (Gast)


Lesenswert?

Ob man die Funktionen des Application Layers in der gleichen Datei hat, 
oder nicht, ist Geschmackssache. Ich möchte darüber nicht streiten. 
Jeder kann sich seine Variante des Codes so gestalten, wie er es haben 
möchte.

Ich möchte viel lieber den Fehler lösen. Aus irgend eine Grund empfängt 
der µC nur unter Linux beim Öffnen des COM Port falsche Bulk Out 
Interrupts in denen sich Fragmente zuvor gesendeter Daten befinden.

von Stefan F. (Gast)



Lesenswert?

Ich habe sicherheitshalber nochmal den Gegentest gemacht. Der Fehler 
tritt wirklich auch mit dem Original-Code von W.S. aus dem Jahr 2015 
auf. Ich habe ihn angehängt.

Wenn ich den COM Port öffne, empfängt der µC häufig (aber nicht immer) 
unerwünschte Zeichen. Im Screenshot sind das die Zeilen mit dem Präfix 
"rx:".

Im Hammer Terminal sieht es genau so aus. Wie gesagt passiert das aber 
nur unter Linux.

von J. -. (Gast)


Lesenswert?

W.S. schrieb:
> Das hat Stefan eingeführt und ich bin mit so etwas nicht glücklich.
> Ich war ganz früher auch mal auf diesem Trip, aber mittlerweile stehe
> ich auf dem Standpunkt, daß ein usb.c eben nur genau für den Chip sein
> soll, für den er geschrieben ist.
Ohoh, da bin ich ganz anders veranlagt. Ich habe im Gegensatz sogar 
meine 407/429/103-Bibliotheken mit #ifdefs ausgestattet, um ja nicht für 
jeden Chip wieder eine separate Datei zu haben. Hab tatsächlich nur noch 
eine spi.h/c, usb.h/c, diskio.h/c etc. für diese 3 Prozessoren, und für 
manche Projekte auch ein CPU-übergreifendes H-File für STM32 und AVR.
Ich komme einfach nicht mehr hinterher, in einem Projekt eine Datei zu 
ändern und dann daran zu denken, diese Änderung auch für die anderen 
Prozessoren/Projekte einzuflechten. Irgendwann hat man dann wieder 
drölfzig Versionen, von denen die eine die x-Verbesserung hat, aber 
dafür nicht die y-Verbesserung, und vice versa.
Das war also meinerseits keine Kritik, den IRQ-Handler oben wählbar 
auszuführen, sondern eher Kritik an Coocox bzw. eher SPL oder gar CMSIS, 
daß der IRQ-Handler nicht semantisch geprüft wird.


@Alex, vielleicht verwende ich Dein Seriennummerprogramm mit dem 
nichtkonstanten SerialString. Ich hatte selbst auch dran gesetzt (die 12 
Byte der CPU_UNIQUE_ADDRESS passen einfach zu gut in den Descriptorstr, 
als daß man die Gelegenheit versäumen sollte :). Ich hatte dann nur den 
*P pointer für diesen String mit einem nichtkonstanten ersetzt - aber 
irgendwas lief nicht richtig. Egal.
Für die 103er User und die anderen STMs hier die entsprechenden 
Startadressen der CPU_UNIQUE_ADDRESS bzw. bei Dir DEVICE_ID_ADDRESS
1
// Unique device ID register (96 bits), Base address:
2
//#define DEVICE_ID_ADDRESS  0x1FFFF7E8    // STM32F1
3
#define DEVICE_ID_ADDRESS  0x1FFF7A10    // STM32F4,STM32F2
4
//#define DEVICE_ID_ADDRESS   0x1FFFF7AC    // STM32F0,STM32F3
5
//#define DEVICE_ID_ADDRESS  0x1FF0F420    // STM32F7
6
//#define DEVICE_ID_ADDRESS  0x1FF80050    // STM32L0
7
//#define DEVICE_ID_ADDRESS  0x1FF80050    // STM32L0, L1 Cat.1,Cat.2
8
//#define CPU_UNIQUE_ADDRESS  0x1FF800D0    // STM32L1 Cat.3,Cat.4,Cat.5,Cat.6

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
>> Ich lege allerdings sehr viel Wert auf Kompatibilität zur Spec.
>
> Und hast du selbige da und darfst du sie auch mal posten?
> Originalunterlagen würde ich mir gern mal ansehen.

Na ja die Specs hab ich von der usb.org. Ich nehme mir allerdings die 
Freiheit raus üblicherweise die v1.1 Spec ranzuziehen, wenn ich sowieso 
nur ein FS Device habe.

Die zweite Informationsquelle sind dann noch die Testbeschreibungen die 
mit UsbCv kommen.

Zum testen nehme ich usbio.sys in einer älteren Demo Version. Die 
aktuelle Version (mit W10 Support) ist ja nicht mehr frei verfügbar und 
zu stark eingeschränkt.

Es gibt natürlich auch ein paar Dokumente die nicht öffentlich sind, 
aber wirklich relevantes steht da auch nicht drin. Das sind mehr so 
Hands On Dokumente.

Ich kann aber bestätigen,  das die Dokumente von der usb.org teilweise 
unter aller Sau sind. Typisch halt für Gremien. So haben Sie 
beispielsweise bei der Midi2.0 Spec. einfach vergessen, dass da IAD rein 
muss.

von Stefan F. (Gast)


Lesenswert?

Ich bin überrascht dass W.S. für seinen obigen Einwurf

W.S. schrieb:
> Also Stefan, da knurrt aber der Blindenhund ganz gewaltig!

ein -1 bekommen hat. Ich finde seine Ansicht durchaus legitim, den USB 
Treiber und den Applikations-Layer nicht zu vermischen. Auf der Arbeit 
in meinen Java Projekten trenne ich die Layer schließlich auch streng.

Dennoch mache ich es hier absichtlich anders, weil ich dieses 
Testprojekt einfach halten will. In einer ernsthaften Anwendung wird 
man sich das sowieso passend umschreiben.

Ich habe ihm jetzt ein +1 gegeben, um das auszugleichen :-)

Wie dem auch sei, entweder ist in dem Code mindestens seit 2015 ein Bug 
drin, oder in Linux.

von Thomas Z. (usbman)


Lesenswert?

@Alex
Das ist so ziemlich genau das was ich in usb.c einbauen werde. 
Allerdings möchte sich es konfigurierbar machen. So in der Art off | 
fixed | chipid.
UsbStrings können bis zu 63 Zeichen lang werden. Lediglich die MSC Spec 
schreibt dass Sie genau 12 Zeichen lang sein müssen, wenn das Device 
bootbar sein muss.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Irgendwie riecht das stark nach einem Linux Bug. Das Programm usbmon 
erzeugt mir folgende Ausgabe:
1
ffff9ea3abec8000 3590089985 S Bo:1:025:2 -115 1 = 65  "e"
2
ffff9ea3abec8480 3590089988 S Bo:1:025:2 -115 1 = 6c  "l"
3
ffff9ea3abec8600 3590089990 S Bo:1:025:2 -115 1 = 6c  "l"
4
ffff9ea3abec8780 3590089991 S Bo:1:025:2 -115 1 = 6f  "o"
5
ffff9ea3abec8a80 3590089993 S Bo:1:025:2 -115 1 = 20  " "
6
ffff9ea3abec86c0 3590089995 S Bo:1:025:2 -115 1 = 57  "W"
7
ffff9ea340ba0480 3590089996 S Bo:1:025:2 -115 1 = 6f  "o"
8
ffff9ea340ba0c00 3590089998 S Bo:1:025:2 -115 1 = 72  "r"
9
ffff9ea340ba0180 3590090000 S Bo:1:025:2 -115 1 = 6c  "l"
10
ffff9ea340ba03c0 3590090002 S Bo:1:025:2 -115 1 = 64  "d"
11
ffff9ea340ba0300 3590090003 S Bo:1:025:2 -115 1 = 21  "!"
12
ffff9ea340ba0900 3590090006 S Bo:1:025:2 -115 2 = 0d0a

Bo heisst nach meinem Verständnis, dass dies Daten sind, die der PC an 
den µC gesendet hat. Dann kann der µC wohl gar nichts dafür.

Ich bin aber unsicher, ob ich das so korrekt interpretiere, denn ich 
habe dieses Tool noch nie benutzt und von USB eigentlich keine Ahnung.

Kann jemand meine Schlussfolgerung bestätigen oder mich korrigieren?

Ich habe einen etwas längeren Abschnitt angehängt. In dieser Zeit habe 
ich den COM Port dreimal geöffnet:

1) Beim ersten mal trat kein Fehler auf

2) beim zweiten mal habe ich nur ein falsches Zeichen 48 "H" gesehen

3) beim Dritten mal fast die gesamte "Hello World!" Meldung gefolgt von 
einem 0d (CR) dessen Herkunft mir völlig suspekt ist. In meinen 
Quelltexten habe ich nämlich konsequent nur 0a (LF) als Zeilenumbruch 
verwendet.

von Thomas Z. (usbman)


Lesenswert?

Jürgen S. schrieb:
> (die 12 Byte der CPU_UNIQUE_ADDRESS passen einfach zu gut in den
> Descriptorstr, als daß man die Gelegenheit versäumen sollte :)

Du täuschst dich.. der String ist 12*4 + 2 Bytes lang.
24 Digits in Unicode + 2

von Stefan F. (Gast)


Lesenswert?

Ich werde irre, ich habe die Erklärung gefunden: 
https://stackoverflow.com/questions/14866899/linux-cdc-acm-device-unexpected-characters-sent-to-device

Also es ist wohl so, dass der Linux Kernel diese CDC Geräte als serielle 
Konsole behandelt. Auf diesen Konsolen sendet er alle Zeichen als Echo 
zurück, und zwar in dieser charakteristischen Sequenz von Einzel-Bytes.

So ein Scheiß!

Ich habe nicht herausgefunden, wie man dem Kernel sagen kann dass er von 
meinem µC die Finger lassen soll. Aber immerhin kann man dieses echo su 
deaktivieren:
1
sudo stty -F /dev/ttyACM0 -echo

Danach funktioniert auch wieder mein von früher gewohnter cat Befehl zum 
Anzeigen der Ausgaben:
1
cat /dev/ttyACM0

Ich danke für eure Aufmerksamkeit :-)

Thomas, meine Bitte an dich (zu helfen), hat sich damit erledigt.

von Thomas Z. (usbman)


Lesenswert?

Stefan ⛄ F. schrieb:
> So ein Scheiß. Jetzt müsste man das nur irgendwie deaktivieren können
> ...

Willkommen in der Welt der OS unabhängigen USB Devices. Da gibt's sicher 
einen workaround. Ich kann mir nicht vorstellen dass kommerzielle CDC 
Devices auch das Problem haben. Das sollte man mit den Silabs Dingern 
doch gegentesten können.
Die Kunst beim USB Firmware Design ist auch, dass es überall gleich 
funktioniert. Wenn ein Mac im Spiel ist wird das noch viel lustiger.

Ich hab schon Usbfunktionen gebaut, die aufgrund der Requests beim 
Enumerieren erkennen konnten ob das Device am Mac oder unter Win 
arbeitet. Der Grund dafür war das beide OS eine unterschiedliche 
Teilmenge der Spec gut unterstützten. Ich hatte also für jedes OS einen 
eigenen Satz Deskriptoren und Firmware Abschnitte.

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Das sollte man mit den Silabs Dingern doch gegen testen können.

Ich habe ein ESP8266 Modul mit Silabs CP2102, aber die melden sich nicht 
als /dev/ttyACM* Gerät, sondern als /dev/ttyUSB*

Thomas Z. schrieb:
> Die Kunst beim USB Firmware Design ist auch, dass es überall gleich
> funktioniert.

Du bist lustig, genau deswegen wollte ich CDC benutzen.

von Thomas Z. (usbman)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich habe ein ESP8266 Modul mit Silabs CP2102, aber die melden sich nicht
> als /dev/ttyACM* Gerät, sondern als /dev/ttyUSB*

Nun das könnte ja schon der Workaround sein.
Poste mal die Deskriptoren...
Win ist es vermutlich egal. Wie ich MS kenne, machen die aus allem einen 
VCP solange da nichts grob falsch ist.

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Nun das könnte ja schon der Workaround sein.

Sag bloß ich kann theoretisch einfach die Deskriptoren ändern und dann 
wird aus /dev/ttyACM0 ein /dev/ttyUSB0. Sonst ist keine Änderung an dem 
komplexen Quelltext nötig?

von Thomas Z. (usbman)


Lesenswert?


von W.S. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Ohoh, da bin ich ganz anders veranlagt. Ich habe im Gegensatz sogar
> meine 407/429/103-Bibliotheken mit #ifdefs ausgestattet, um ja nicht für
> jeden Chip wieder eine separate Datei zu haben...

Das finde ich schlimm. Schließlich hast du zwar nur eine Datei, dafür 
aber für jede elende Plattform dort drin irgendwelche #ifdef's, die du 
dann jedesmal neu einstellen mußt, entweder durch Editieren der Quelle 
oder durch eine Abhängigkeit von einem Projektfile, einer weiteren .h 
oder einem Makefile.
Wohlgemerkt: die Datei usb.h sollte für alle Plattformen gleich sein, 
damit eben die höheren Schichten problemlos portierbar sind, aber die 
usb.c sollte wirklich auf "ihre" Plattform passen und möglichst 
keinerlei Anpassungen nötig haben. In dieser Hinsicht begrüße ich, daß 
Thomas die Definition der HW-Register in die usb.c transferiert hat, 
damit ist dann auch die Abhängigkeit von einer 'prozessorname'.h 
beseitigt.


> Irgendwann hat man dann wieder
> drölfzig Versionen, von denen die eine die x-Verbesserung hat, aber
> dafür nicht die y-Verbesserung, und vice versa.

Das muß doch nur einmal (und hoffentlich richtig) für eine Plattform 
gemacht sein und fertig ist die Laube, solange es diesen Chip zu kaufen 
gibt.

> Das war also meinerseits keine Kritik, den IRQ-Handler oben wählbar
> auszuführen, sondern eher Kritik an Coocox bzw. eher SPL oder gar CMSIS,
> daß der IRQ-Handler nicht semantisch geprüft wird.

Du meinst wohl nicht den Handler, sondern dessen Namen. Der wiederum ist 
eigentlich überhaupt nicht von einer IDE prüfbar, weil er ja nur genau 
mit dem Namen im Startupcode übereinstimmen muß - und der sollte zwar 
zum RefManual passen, muß das aber nicht. Prinzipiell könnte man den 
USB-Interrupt auch 'Ottokar' nennen, wenn man sich in allen beteiligten 
Quellen daran hält. Aber wie soll eine IDE das alles prüfen? Da sind wir 
wieder bei den Versionen für mehrere Chips, wo es dann eben verschiedene 
Namen gibt. Auch deshalb bin ich gar sehr dafür, so einen Treiber NUR 
für eine einzige Plattform zu machen. Das eliminiert dann auch solche 
Namensprobleme.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Das muß doch nur einmal (und hoffentlich richtig) für eine Plattform
> gemacht sein und fertig ist die Laube, solange es diesen Chip zu kaufen
> gibt.

Alleine schon an den Beiträgen in diesem Forum siehst du, wie oft die 
usb.c in den vergangenen 5 Jahren aufgrund akuter Fehlfunktionen 
verändert wurde. dazu kommen Verbesserungen die von konkreten Projekten 
getrieben werden, die man sich aber auch für künftige Projekte (auch auf 
anderen µC) konservieren möchte.

Mit "einmal richtig machen" ist es hier (und in vielen anderen 
Projekten) nicht getan.

von W.S. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Win ist es vermutlich egal. Wie ich MS kenne, machen die aus allem einen
> VCP solange da nichts grob falsch ist.

Das ist ja auch völlig korrekt aus meiner Sicht. Immerhin ist sowas ja 
erstmal nichts anderes als ein bidirektionaler serieller Kanal. Also 
sollte der Treiber im OS diesen zwar bereitstellen, damit Applikationen 
darauf zugreifen können, aber nicht mehr.

Da ist es ja doch wohl eher die Aufgabe einer Shell oder einer anderen 
Anwendung, gegebenenfalls anzunehmen, daß dieser Kanal zu einer 
Fern-Konsole führt und dann ggf. die Zeichen als Echo zurückzusenden. So 
einen Kurzschluß im OS-Kernel zu haben, verstehe ich wirklich nicht.

W.S.

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
> In dieser Hinsicht begrüße ich, daß Thomas die Definition der
> HW-Register in die usb.c transferiert hat, damit ist dann auch die
> Abhängigkeit von einer 'prozessorname'.h beseitigt.

Du irrst dich, die Definitionen waren schon drin als ich das angeschaut 
habe. Ich hab da nichts geändert, nur mal mit dem Datenblatt 
gegengecheckt.

Was ich gemacht habe ist EPs mit 0x07 zu maskieren, da es nur 8 EPs 
gibt. Ich bin mir aber nicht sicher ob ich alle Stellen erwischt habe.

von W.S. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Du irrst dich

Macht nix, es ist eine Abhängigkeit weniger und das ist gut.

Andererseits bin ich ziemlich unzufrieden mit sowas wie UsbTxFlush und 
der Aufblähung von UsbCharOut. Mein eigentliches Ziel war und ist es, 
die beiden Ringpuffer als einzige Schnittstelle zwischen der allgemeinen 
Firmware und dem zum USB gehörigen Treiberzeugs zu haben.

Und jetzt wird von dort, also quasi von außen aus massiv dem USB in die 
Gedärme gegriffen. Muß das sein? Bei meinen anderen (älteren) 
Implementationen (LPC, NUC) und auch meiner zugrundeliegenden 
Treiberversion war das nicht nötig, bzw. war mir nichts negatives 
aufgefallen. Da wird alles direkt im Interrupt erledigt, teilweise eben 
durch den Timertick am USB. Für die übrige Firmware sollte es doch 
ausreichend sein, festzustellen, ob es Bytes abzuholen gibt oder ob man 
Bytes senden kann oder nicht. Warten muß man ja auch bei einem realen 
COM-Port, bis die Zeichen im Puffer endlich nach draußen geschaufelt 
sind.

Ich hatte das bei anderen Plattformen so gelöst, daß ich im Timertick 
einfach den Int auf NAK-BulkIn eingeschaltet hatte. Damit gibt es dann 
alsbaldig einen Int, sobald der Host die SIE vergeblich nach Daten 
abfragt und dieser Int konnte dann feststellen, ob etwas im Ringpuffer 
steht. Und wenn ja, wurde ein Paket fertiggemacht und aktiviert und 
voila, der Datenfluß war wieder angelaufen - alles ohne Eingriffe von 
außen.

Im EpBulkIn-Handler hatte ich da jeweils den Int auf NAK-BulkIn wieder 
ausgeschaltet, damit der µC nicht alle paar µS einen Interupt abkriegt. 
Bloß bei dem Core in dem STM32 habe ich eine derartige Möglichkeit zur 
Kommunikation mit der SIE nicht gefunden. Vielleicht hast du ja eine 
Idee, wie man das hier sauber wieder hinkriegt, dann wäre das ganze 
Gehampel mit Int verbieten und von außen dem Treiber in die Gedärme zu 
greifen überflüssig.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Andererseits bin ich ziemlich unzufrieden mit sowas wie UsbTxFlush und
> der Aufblähung von UsbCharOut. Mein eigentliches Ziel war und ist es,
> die beiden Ringpuffer als einzige Schnittstelle zwischen der allgemeinen
> Firmware und dem zum USB gehörigen Treiberzeugs zu haben.

Du meinst wohl die (inzwischen umbenannte) Funktion:
1
// Send a character to the host (via send buffer).
2
// Returns false if the buffer is full.
3
bool UsbSendChar_noWait(char c)
4
{
5
    // check space
6
    int i = (txw + 1) & (USB_TXLEN - 1);
7
    if (i == txr)
8
    {
9
        return false;
10
    }
11
12
    // write into the buffer
13
    UsbTxBuf[txw] = c;
14
    txw = i;
15
16
    // Comment in the following condition to delay sending until the buffer is full
17
    // Then you may call UsbTxFlush() to trigger sending
18
19
    // if (((txw + 1) & (txLen - 1)) == txr)
20
    {
21
        // trigger sending
22
        if (!transmitting)
23
        {
24
            DisableUsbIRQ();
25
            EpBulkBeginTransmit();
26
            EnableUsbIRQ();
27
        }
28
    }
29
    return true;
30
}

Was ist denn da aufgebläht? Der Aufruf von EpBulkBeginTransmit() wurde 
vor einem Jahr (Beitrag "USB CDC von Stefan Frings und WS") 
hinzugefügt, weil die ganze Übertragung unter gewissen Bedingungen 
stecken bleibt.

Ich denke, dass deine Idee "die beiden Ringpuffer als einzige 
Schnittstelle" schlicht nicht funktioniert hatte.

Entweder braucht es oben den Aufruf von EpBulkBeginTransmit(), oder eben 
als separate Funktion:
1
// Trigger sending the remaining characters from the 
2
// send buffer (asynchronously, not blocking)
3
void UsbTxFlush (void)
4
{
5
    if (!transmitting)
6
    {
7
        DisableUsbIRQ();
8
        EpBulkBeginTransmit();
9
        EnableUsbIRQ();
10
    }
11
}

Wie sonst willst du dafür sorgen, dass das Senden zuverlässig getriggert 
wird?

> Ich hatte das bei anderen Plattformen so gelöst, daß ich im Timertick
> einfach den Int auf NAK-BulkIn eingeschaltet hatte.

Im oben verlinkten Thread hat Niklas begründet, warum er es anders 
gelöst hat. Ist das jetzt so schlimm? Auch andere Stream basierte 
Schnittstellen haben mehr als nur die Puffer zwischen Anwendung und 
Treiber. Daran ist nichts überraschendes.

Das eigentliche Problem ist doch vermutlich eher, dass diese Änderung 
von Niklas stammt und ihr beiden euch zerstritten habt. Immerhin 
funktioniert seine Anpassung, ist das nicht wichtiger?

von Stefan F. (Gast)


Lesenswert?

an W.S:
Ich möchte nochmal klarstellen, dass ich und viele andere hier für 
deinen Code sehr dankbar sind. Dank deiner Arbeit muss ich nicht diese 
scheiß HAL verwenden.

Nur sei doch bitte nicht angepisst, dass Leute deinen Code weiter 
entwickeln, so wie es ihnen beliebt. So ist das halt bei Open-Source. 
Dadurch geht dein Werk weder kaputt noch wird es herab gewürdigt. Ganz 
im Gegenteil, das ist ein Ausdruck der Wertschätzung. Meinst du ich 
hätte freiwillig die vergangenen drei Tage durchgehend daran gearbeitet, 
wenn er nicht entsprechend wertvoll wäre? Ganz sicher nicht.

Auch Niklas hat sich vor einem Jahr tagelang damit befasst, obwohl er es 
gar nicht nötig gehabt hätte (er hat ja seine eigene Implementierung). 
Auch Niklas hat dir damit großen Respekt gezollt.

Nicht zu vergessen Thomas, der sich offenbar auch mit deinem Werk 
beschäftigt. Er würde das nicht tun, wenn dein Code schlecht wäre.

Wir sind halt nur nicht in allen Punkten der gleichen Meinung. Aber wir 
sind dir dankbar. Lass uns bitte Freiheit darauf aufzubauen und es für 
uns selbst nach unserem Geschmack zu ändern. Deine Veröffentlichung 
(Beitrag "Re: STM32F4 USB CDC") betrifft das 
nicht.

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
> Vielleicht hast du ja eine
> Idee, wie man das hier sauber wieder hinkriegt

Mir ist bekannt, dass es cores gibt die einen Interrupt auf NAK bieten, 
z.B. FX2 Das ist vielleicht interessant zu Debugzwecken sonst fällt mir 
dazu nichts ein.
NAK steht ja nunmal dafür Ich hab nichts, musst du später noch mal 
probieren. Das weiß die FW aber auch so. Simulieren könntest du sowas 
indem ein Flag generiert wird was epnum,dir und ctr auswertet im 
InterruptStatusReg auswertet.

Angenommen machst sowas auf dem InEp:
ArmEp(EpNo, nBytes); dann weißt du wenn im FlagReg CTR für diesen EP 
gesetzt ist dass der Code nun NAKs schickt bis ein neues ArmEp kommt.

von J. -. (Gast)


Lesenswert?

W.S. schrieb:
> Das finde ich schlimm. Schließlich hast du zwar nur eine Datei, dafür
> aber für jede elende Plattform dort drin irgendwelche #ifdef's, die du
> dann jedesmal neu einstellen mußt, entweder durch Editieren der Quelle
> oder durch eine Abhängigkeit von einem Projektfile, einer weiteren .h
> oder einem Makefile.
Es wird schon einen guten Grund haben, wenn Du das so handhabst, wie Du 
es machst. Denn gute Treiber zeichnen sich dadurch aus, daß man sie nur 
noch wenig anfassen muß, weil sie eben ausgereift sind. Da ist schon was 
dran.
Zudem haben die #ifdef-Konstruktionen bei größeren Projekten neben der 
schlechteren Lesbarkeit den Nachteil, daß die Objektfiles nur für die 
ausgewählten Definitionen gelten, man also bei anderer Konstellation 
alles neu compilieren muß. Bei kleinen Hobbybastler-Sachen fällt das 
aber nicht ins Gewicht.
> Wohlgemerkt: die Datei usb.h sollte für alle Plattformen gleich sein,
> damit eben die höheren Schichten problemlos portierbar sind, aber die
> usb.c sollte wirklich auf "ihre" Plattform passen und möglichst
> keinerlei Anpassungen nötig haben. In dieser Hinsicht begrüße ich, daß
> Thomas die Definition der HW-Register in die usb.c transferiert hat,
> damit ist dann auch die Abhängigkeit von einer 'prozessorname'.h
> beseitigt.
Ich denke da nochmal drüber nach, wenn ich die Deine bzw. inzwischen 
eure usb.h und usb.c für den STM32F4 einge-#ifdef-t habe :). Meine Tests 
auf dem F4 stehen noch aus.
> Das muß doch nur einmal (und hoffentlich richtig) für eine Plattform
> gemacht sein und fertig ist die Laube, solange es diesen Chip zu kaufen
> gibt.
Das wäre der Idealfall. Man hat das knowhow, entsprechende 
Testmöglichkeiten, konstruiert eine gute Software und legt sie als 
'erledigt' ab. Bei den Nichtprofis wie mir gab es in den ersten Jahren 
immer wieder etwas zu ändern, teils durch Wissenszuwachs, teils, weil 
sich andere Ansätze als erfolgversprechender herausstellten, teils, weil 
beim Ändern einer Datei eine andere auch geändert werden muß.
> Du meinst wohl nicht den Handler, sondern dessen Namen. Der wiederum ist
> eigentlich überhaupt nicht von einer IDE prüfbar, weil er ja nur genau
> mit dem Namen im Startupcode übereinstimmen muß - und der sollte zwar
> zum RefManual passen, muß das aber nicht.
Das mit den IRQ-Handlernamen ist nicht einfach, wenn es ganz sicher sein 
soll, ja. Die billigste, aber für oberflächliche Fehlervermeidung 
ausreichende Variante wäre, nicht angesprungene Prozeduren als #warning 
auszugeben. So würden falsch benamte IRQ-Handler auffliegen.
Als weitere Sicherheit und Minimalkonvention könnte man IRQ-Handlernamen 
noch abverlangen, daß sie "isrvect_" oder sowas fest im Namen haben 
müssen. So daß man gleich weiß, daß es ein IRQ-Handler sein sollte, der 
da ungenutzt rumbaumelt.
Advanced wäre es, wenn der Compiler/Linker anhand der CPU-Register 
erkennt, daß ein Interrupt gesetzt ist, und untersucht, ob der 
Einsprungpunkt bzw. die Adresse, auf die der Interruptvektor zeigt, als 
Prozedur definiert ist. Aber was ist wahrscheinlich zu utopisch/komplex.

Edit:
Stefan ⛄ F. schrieb:
> Aber wir sind dir dankbar.
Definitiv. Nur zwei Dateien, plattformunabhängig, kompakt, und stabiler 
als andere Versionen, die ich probiert habe. Das ist schon sehr gut.

von Stefan F. (Gast)


Lesenswert?

Ich möchte darauf hinweisen, dass die usb.c auf meiner Homepage keine 
#ifdef enthält.

Da gibt es nur 4 Plattform spezifische Zeilen. Die habe ich ganz bewusst 
ganz nach oben platziert, damit man bei der spezifischen Anpassung 
nichts falsch macht:
1
// For devices with 2x16 bits/word access schema 
2
// (e.g. STM32L0x2, STM32L0x3, STM32F0x2, STM32F303xD and xE)
3
#define UMEM_SHIFT 0
4
#define UMEM_FAKEWIDTH uint16_t
5
6
// For devices with 1x16 bits/word access schema 
7
// (e.g. STM32F103, STM32F302, STM32F303xB and xC)
8
// #define UMEM_SHIFT 1
9
// #define UMEM_FAKEWIDTH uint32_t
10
11
// The name of the IRQ handler must match startup_stm32.s 
12
#define NAME_OF_USB_IRQ_HANDLER USB_IRQHandler
13
14
// Take the number from the reference manual of your µC. 
15
#define USB_IRQ_NUMBER 31

Tatsächlich habe ich diese Datei 4 mal auf meiner Festplatte in 
Plattform-Spezifischen Verzeichnissen. Für mich hat es sich als sehr 
praktisch heraus gestellt, dass alles unterhalb dieser #defines in allen 
4 Dateien identisch ist. So kann ich Korrekturen einfach herüber 
kopieren.

von W.S. (Gast)


Lesenswert?

Thomas Z. schrieb:
> NAK steht ja nunmal dafür Ich hab nichts, musst du später noch mal
> probieren. Das weiß die FW aber auch so.

Ähem... das ist so ein Problem: Wenn in Richtung µC-->PC mal eine Weile 
keine Daten vorhanden sind und nach dem letzten ACK der SIE an den Host, 
also wenn die letzten vorhandenen Daten gesendet worden sind, nix mehr 
zu senden da ist, dann kann man auch kein weiteres Paket fertig machen 
und muß den Interrupt unverrichteterdinge beenden.

Und genau DA passiert es nämlich, daß ab da die SIE dem Host nur noch 
NAK sagt, es aber keinen Interrupt mehr gibt. Wer also soll dann später, 
wenn wieder Daten im Ringpuffer aufgelaufen sind, sich darum kümmern? 
Ohne Interrupt auch keine Routine im Treiber. Das ist das Problem.

Ich hatte das so geregelt, daß sich eben der Timertick so alle 
Millisekunde mal drum kümmern soll, Niklas hingegen hat das nicht 
verstehen/akzeptieren wollen und stattdessen sich sowas wir diese Flush 
aus dem Grundprogramm heraus ausgedacht.

Natürlich ist sonnenklar, daß es irgendwen geben muß, der sich drum 
kümmert. Das eleganteste ist da natürlich, immer mal den 
NAK-BI-Interrupt einzuschalten, dann kümmert sich nämlich die SIE quasi 
darum. Dann regelt das der Treiber von selbst und das Grundprogramm muß 
sich nicht drum kümmern. Und so soll es eigentlich sein: Der Treiber 
soll die höheren Schichten nicht mit seinen internen Befindlichkeiten 
belästigen.

Alternativ kann man natürlich irgendwo im Treiber ein Flag haben, so wie 
das jetzt von euch gehandhabt wird. Aber bei so einem Flag ist wieder 
die Frage, wer es denn anschauen soll. Der UsbCharOut ist dafür kein 
guter Kandidat, denn er kriegt ja nur einzelne Zeichen ab und würde 
entweder bei jedem Zeichen den Transfer anstoßen müssen, also immerzu 
nur Pakete der Länge 1 machen oder er würde sammeln müssen, aber bis 
wohin? Der Treiber weiß ja niemals, ob das aktuelle Zeichen jetzt nun 
definitiv das Letzte ist für eine Weile.

Ich hatte mir das vor Jahren schon einmal alles überlegt und kam zu dem 
Ergebnis, daß es wohl das erträglichste ist, wenn der CharOut einfach 
nur den Ringpuffer vollstopft und ansonsten wartet - und spätestens nach 
einer Millisekunde der Timertick im Treiber sich um das Starten der 
Übertragung kümmert.

Eine Millisekunde an Verzögerung ist für einen virtellen COM-Port m.E. 
durchaus akzeptabel, immerhin geht dann ja ein Block von 255 Bytes auf 
die Reise und wenn die Firmware noch mehr Bytes hat und den Ringpuffer 
zwischendurch schnell genug wieder nachfüllt, dann geht es ab da ja 
ratzfatz, bis mal wieder eine ausreichend große Lücke kommt und die SIE 
anfängt NAK zu sagen und später aus diesem Zustand wieder herausgeholt 
werden muß.

Und noch ein Wort an Stefan: Natürlich kann das ein jeder machen wie er 
will. Ich habe dazu allerdings eine Meinung und mit der will ich nicht 
hinterm Berg halten, schließlich hatte ich mir dazu Gedanken gemacht. 
Ich möchte allerdings auch nicht ohne sachliche Argumente einfach nur so 
angeblafft werden, wie Niklas das getan hat. Verstehe das mal.

W.S.

von Alex (Gast)


Lesenswert?

Jetzt dreh ich langsam durch...

Wenn ich Stefans Hello World (usb.c. vom 27.2. um 19:05) mit Echo bei 
mir aus dem Debugger laufen lasse, dann klappt es.
Als Release compiliert und aus dem Flash kommt kein Echo.

Als Debug compiliert läuft es auch mit Echo, wenn ich es aus dem Flash 
boote.
Anpassung lediglich an meinen Chip, mit TCXO.
USB läuft, Hello World kommt immer.


Unterschied in den Einstellungen: (jeweils zuerst die debug-cfg)

GCC Assembler:

-mcpu=cortex-m0 -g3 -c -x assembler-with-cpp --specs=nano.specs 
-mfloat-abi=soft -mthumb

-mcpu=cortex-m0 -c -x assembler-with-cpp --specs=nano.specs 
-mfloat-abi=soft -mthumb

GCC Compiler:

-mcpu=cortex-m0 -std=gnu11 -g3 -DUSE_HAL_DRIVER -DSTM32F042x6 -DDEBUG -c 
-I../Core/Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc 
-I../Drivers/STM32F0xx_HAL_Driver/Inc/Legacy 
-I../Drivers/CMSIS/Device/ST/STM32F0xx/Include 
-I../Drivers/CMSIS/Include -O0 -ffunction-sections -fdata-sections -Wall 
-fstack-usage --specs=nano.specs -mfloat-abi=soft -mthumb

-mcpu=cortex-m0 -std=gnu11 -DUSE_HAL_DRIVER -DSTM32F042x6 -c 
-I../Core/Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc 
-I../Drivers/STM32F0xx_HAL_Driver/Inc/Legacy 
-I../Drivers/CMSIS/Device/ST/STM32F0xx/Include 
-I../Drivers/CMSIS/Include -Os -ffunction-sections -fdata-sections -Wall 
-fstack-usage --specs=nano.specs -mfloat-abi=soft -mthumb

GCC Linker:

-mcpu=cortex-m0 
-T"C:\Users\Alex\STM32CubeIDE\workspace_1.4.0\SFusbTest2\STM32F042F6PX_F 
LASH.ld"  --specs=nosys.specs -Wl,-Map="${ProjName}.map" 
-Wl,--gc-sections -static --specs=nano.specs -mfloat-abi=soft -mthumb 
-Wl,--start-group -lc -lm -Wl,--end-group

-mcpu=cortex-m0 
-T"C:\Users\Alex\STM32CubeIDE\workspace_1.4.0\SFusbTest2\STM32F042F6PX_F 
LASH.ld"  --specs=nosys.specs -Wl,-Map="${ProjName}.map" 
-Wl,--gc-sections -static --specs=nano.specs -mfloat-abi=soft -mthumb 
-Wl,--start-group -lc -lm -Wl,--end-group

Wenn ich in der Debug-CFG die Optimierungen (-Os) einschalte und die 
debuglevel (-g3) ausschalte hat das keinen Effekt.

Ich steh völlig auf der Leitung.
Was zum Kuckuck hab ich da noch übersehen?

von Stefan F. (Gast)


Lesenswert?

Könnte es sein dass du im Release Modus das falsche Binary in den Flash 
überträgst?
Gucke dir mal die Debug Configurations (beim grünen Käfer) an.

von Alex (Gast)


Lesenswert?

Wenn ich das .bin vom release in den Flash schreibe und von dort starte, 
dann kommt das Echo nicht.
Wenn ich mit dem Debugger das .elf vom selben compile-Vorgang laufen 
lasse, dann hab ich das Echo.

Im Debugger gehen also beide Versionen, aus dem Flash nur die als Debug 
compilierte-Version (das .elf).

Kapieren tu ich das noch nicht.

von Stefan F. (Gast)


Lesenswert?

Schau mal im Dateimanager auf das Datum der Dateien. Haben beide Dateien 
das aktuelle  Datum/Zeit?

von Alex (Gast)


Lesenswert?

Ja, die passen definitiv zusammen.

von Alex (Gast)


Lesenswert?

Hab grad mit dem CubeProgrammer das ELF in den Flash geschrieben, kein 
Echo.
Das SELBE ELF im Debugger gibt ein Echo.

von Stefan F. (Gast)


Lesenswert?

Dem Cube Programmer traue ich schon lange nicht mehr. Bei mit zickt er 
immer wieder herum (nicht nur wegen der Java Version). Versuche mal zum 
Vergleich das alte ST-Link Utility.

> Das SELBE ELF im Debugger gibt ein Echo.

Ich erinnere mich an ein Problem das ich mit der System Workbench hatte. 
Da lief eins meiner Programme mit falscher Taktfrequenz bei diese beim 
Flashen und die Taktfrequenz auf 64 MHz via HSI änderte und mein eigener 
Code danach nicht mehr imstande war, die von mit gewünschte 
Takteinstellung vorzunehmen. Da war die Lösung, dass ich zunächst die 
PLL abschalten musste, bevor ich sie um-konfiguriere.

Das ist jetzt nicht direkt dein Problem, aber könnte in eine ähnliche 
Richtung gehen. Da dein Programm im Debugger läuft, wäre jetzt mal 
interessant, ob es danach auch noch läuft, wenn du den µC Stromlos 
machst und neu startest.

von Alex (Gast)


Lesenswert?

Irgendwelche Takt-Zeug hab ich ausgeschlossen, da aber das Hello World 
brav kommt.

> Da dein Programm im Debugger läuft, wäre jetzt mal interessant, ob es
> danach auch noch läuft, wenn du den µC Stromlos machst und neu startest.

Schreibt der Debugger das Programm in den Flash?
Da hab ich noch garnicht drüber nachgedacht. Musste er ja eigentlich, 
vor allem wenn ich das SELBE elf auch flashen kann, muss es so sein.

Hab das grad versucht, und es schein so, als ob es garnichts damit zu 
tun hat, ob Debugger oder nicht. Mal gehts, mal nicht, aber eher nicht.
Bin grad immer am selben elf-file, und sehe grad kein Muster...
Die Tests gestern Abend hab ich 3mal wiederholt und es war konsistent.
Jetzt grad ist nichts konsistent.
Ich probiers später mal mit einer 'guten' Hardware, vielleicht hat der 
Chip ja wirklich einen an der Waffel (immerhin tapse ich da jetzt schon 
wochenlang dran rum, und die Luft ist zu der Jahreszeit eher etwas 
trocken...)
Bringt ja nix, Geister zu jagen.

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Irgendwelche Takt-Zeug hab ich ausgeschlossen, da aber das Hello World
> brav kommt.

Ach ja, stimmt.

> Schreibt der Debugger das Programm in den Flash?

Normalerweise schon. Jedenfalls bei den Mikrocontrollern, die ich 
verwende (F1, F3, L0).

> Mal gehts, mal nicht, aber eher nicht, sehe grad kein Muster...

Das ist bitter. Suche weiter!

Könnte es an der Verkabelung liegen?

von temp (Gast)


Lesenswert?

Alex schrieb:
> Wenn ich das .bin vom release in den Flash schreibe und von dort starte,
> dann kommt das Echo nicht.

Das kann doch nicht alles sein was du zur Fehlersuche beitragen kannst? 
Klappt die USB-Enumeration überhaupt noch oder geht das auch schon nicht 
mehr.

Wenn du komplett im Dunkeln tappst, kannst du ja mal nur bestimmte 
Dateien mit -O(x) übersetzen und den Rest mit -O0.
Und wenn das nicht hilft, kannst du immer noch bestimmte Teile gezielt 
mit #pragmas optimierenm oder auch nicht.

von Stefan F. (Gast)


Lesenswert?

Das rudimentäre Beispielprogramm müsste völlig unabhängig von diesen 
Compiler/Linker Einstellungen sein.

von temp (Gast)


Lesenswert?

W.S. schrieb:
> Ich hatte mir das vor Jahren schon einmal alles überlegt und kam zu dem
> Ergebnis, daß es wohl das erträglichste ist, wenn der CharOut einfach
> nur den Ringpuffer vollstopft und ansonsten wartet - und spätestens nach
> einer Millisekunde der Timertick im Treiber sich um das Starten der
> Übertragung kümmert.
>
> Eine Millisekunde an Verzögerung ist für einen virtellen COM-Port m.E.
> durchaus akzeptabel, immerhin geht dann ja ein Block von 255 Bytes auf
> die Reise und wenn die Firmware noch mehr Bytes hat und den Ringpuffer
> zwischendurch schnell genug wieder nachfüllt, dann geht es ab da ja
> ratzfatz, bis mal wieder eine ausreichend große Lücke kommt und die SIE
> anfängt NAK zu sagen und später aus diesem Zustand wieder herausgeholt
> werden muß.
>

Deine Überlegungen verstehe ich durchaus.

> Und noch ein Wort an Stefan: Natürlich kann das ein jeder machen wie er
> will. Ich habe dazu allerdings eine Meinung und mit der will ich nicht
> hinterm Berg halten, schließlich hatte ich mir dazu Gedanken gemacht.
> Ich möchte allerdings auch nicht ohne sachliche Argumente einfach nur so
> angeblafft werden, wie Niklas das getan hat. Verstehe das mal.

Und diese ganz besonders.

Aber zum Thema, mir gefällt auch absolut nicht, daß das OnEpBulkIn(); 
aus dem Usercode gerufen wird. Auf der anderen Seite möchte ich aber die 
1ms Interrupts nicht haben. Ich hab mir jetzt so geholfen.
1
// 1. SOF und ESOF Interrupt disabled. 
2
void InitEndpoints(void)
3
{
4
  ....
5
  USB_CNTR =
6
        CTRM |             /* Int bei ACKed Paketen in oder out */
7
        RESETM |           /* Int bei Reset */
8
        SUSPM | WKUPM 
9
       // | ESOFM | SOFM;       /* Int bei 1 ms Frame */
10
       ;  
11
}     
12
13
// 2. TxFlush
14
// bei TxFlush wird nur der SOF-Interrupt enabled
15
void UsbTxFlush(void) 
16
{
17
  // SOF Interrupt enablen
18
  // for handling EpBulkBeginTransmit();
19
  DisableUsbIRQ();
20
  if (!transmitting) 
21
    USB_CNTR |= SOFM; 
22
  EnableUsbIRQ();
23
}
24
// oder
25
void UsbTxFlush(void) 
26
{
27
  // SOF Interrupt enablen
28
  // for handling EpBulkBeginTransmit();
29
  USB_CNTR |= SOFM; 
30
}
31
32
// 3. Im Interrupt:
33
// der SOF-Interrupt wird sofort wieder disabled, aber das Flag 
34
// bleibt stehen. Damit sollte der Interrupt sofort anspringen
35
// wenn jemand UsbTxFlush() aufruft ohne max. 1ms warten zu müssen
36
// Ein SOF Interrupt wird dann nur noch optional gerufen wenn jemand
37
// UsbTxFlush() ruft. 
38
// Selbst wenn man die Überprüfung auf "transmitting" in UsbTxFlush() 
39
// weglässt, kommt der Code nicht durcheinander. 
40
// Es gibt dann nur ein paar wenige SOF Interrupts mehr.
41
// In dem Fall sollte es nicht mal nötig sein das DisableUsbIrq() 
42
// einzubauen.
43
void NAME_OF_USB_IRQ_HANDLER(void)
44
{
45
  .... 
46
  if (I & SOF) /* Start of Frame, alle 1 ms */
47
    {
48
    if ((USB_CNTR & SOFM) != 0)
49
      {
50
      USB_CNTR &= ~SOFM; // Int disablen, Flag nicht löschen
51
      if (!transmitting)
52
        OnEpBulkIn();    // immer mal nachschauen...
53
      }
54
    } 
55
  .....
56
}

Das UsbTxFlush() baue ich dann nach Belieben in UsbCharOut oder 
UsbStrOut ein, darauf will ich nicht näher eingehen.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

An der Verkabelung kanns nicht liegen, da das Ding wie ein USB Stick 
direkt an den Host gesteckt wird.

Hab jetzt mal mit wireshark mitgeloggt, was passiert und die Daten etwas 
zusammengestutzt (Maus-Bewegungen rausgeschnitten).

2mal folgende Prozedur:
- einstecken
- Hterm öffnen
- Hello World empfangen
- mehrfach etwas runterschicken
- Hterm schließen
- ausstecken

Beim ersten Mal kam ein Echo, beim zweiten Mal nicht.

von Thomas Z. (usbman)


Lesenswert?

Ich hab jetzt den Serial String implementiert analog wie die trace 
Geschichte. InitSerial() mache ich in UsbSetup().
Zusätzlich habe ich IAD fest eingebaut und testweise überprüft ob die 
Enumeration auch mit anderen EP0 sizes (8,16,32) klarkommt. Das  ist ein 
Test den ich eigentlich immer mache. Funktioniert perfekt. Das wäre z.B 
bei einem LowSpeed Device wichtig, da dort nur EP0 Size=8 erlaubt ist.

Noch ein Hinweis:
Da ich plane meine usb11.h und usbcdc12.h in Zukunft für die Spec. 
Konstanten zu verwenden wird usb.c sich immer weiter von der Version von 
Stefan entfernen. Deshalb ist es vermutlich besser wenn ich meiner 
Version einen neuen Name gebe.

Hier nun der Serial No code.
1
void DoGetDescriptor(void)
2
....
3
#if USB_SERIAL_NO
4
        case 3:
5
            aLen = SerialStr[0];
6
            P =SerialStr;
7
            break;
8
#endif
9
....
1
#if USB_SERIAL_NO 
2
  #define U_ID_SIZE  12  // in bytes
3
  #define U_ID       (*(volatile uint8_t *)( 0x1FFFF7E8UL))
4
  
5
  uint8_t SerialStr[U_ID_SIZE * 2 * sizeof(uint16_t) +2];
6
    
7
  uint8_t toAscii (uint8_t digit)
8
  {
9
     digit &= 0x0F;
10
     return ((digit < 10) ? digit + '0'
11
                          : digit +('A'- 10));
12
  }
13
  
14
  void InitSerial(void)
15
  {
16
     uint8_t *s = &SerialStr[0];
17
     uint8_t b;
18
     int i;
19
     
20
     for (i=0; i < sizeof(SerialStr); i++) SerialStr[i]=0; //memset
21
22
     *s++  = U_ID_SIZE *2 * sizeof(uint16_t) +2;
23
     *s++  = 0x03;  
24
     i = U_ID_SIZE-1; //0..11 
25
     while(i > -1)    //rückwärts lesen
26
     {
27
        b   = U_ID + i;
28
        *s  = toAscii(b);      s += 2;
29
        *s  = toAscii(b >> 4); s += 2;
30
        i--;
31
     }
32
  }
33
#else
34
    #define InitSerial() // nothing
35
#endif

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Deshalb ist es vermutlich besser wenn ich meiner
> Version einen neuen Name gebe.

Wirst du das irgendwo veröffentlichen?  Wenn ja, dann schreibe mal, wo 
man es finden kann.

von Dirk (Gast)


Lesenswert?

Hallo,

gibt es diesen Code auch für den STM32F072?
Ich finde da nichts passendes, am besten SPL oder LL, HAL würde ich aber 
auch nehmen.

Ich brauchen einen VCP für genau diesen Prozessor, weil die Hardware 
vorgegeben ist.

Das ganze brauche ich nur zur Inbetriebnahme der Hardware.
Dazu soll das hier bekannte MCURSES darauf laufen und mir Informationen 
anzeigen bzw auf Tastendruck Aktionen ausführen.
Halt das was man so braucht um eine Hardware langsam zu testen.

VG Dirk

von Stefan F. (Gast)


Lesenswert?

Dirk schrieb:
> gibt es diesen Code auch für den STM32F072?

Ja, ist der selbe Code nur anders konfiguriert. Schau dir die #defines 
am Anfang an.

von Dirk (Gast)


Lesenswert?

Reden wir hier über deine STM32F103_usb_test.zip?
Oder ist das der falsche Code?

In diesem Code finde ich keine passenden Defines.

Es freut mich das es Code gibt, dann sollte ich ja wenn ich ihn habe, 
recht schnell Ergebnisse haben. Wenn mir dann was auffällt helfe ich 
gerne beim Fehler suchen, ist ja dann auch in meinem Interesse.

VG Dirk

von temp (Gast)


Lesenswert?

@Alex

Stell doch mal deinen komplette Code hier rein, sonst müssen wir alle 
Kaffeesatz lesen.

von Stefan F. (Gast)


Lesenswert?

Dirk schrieb:
> Reden wir hier über deine STM32F103_usb_test.zip?
Diese: http://stefanfrings.de/stm32/STM32F103_usb_test.zip

Oder meinetwegen auch die Variante von Niklas 
(https://github.com/Erlkoenig90/WSusb) oder die von Thomas.

> In diesem Code finde ich keine passenden Defines.

Ich habe sie oben schon zitiert in 
Beitrag "Re: STM32 USB Übertragungsproblem mit Code von S.F."

von Dirk (Gast)


Lesenswert?

Gut jetzt habe ich das besser verstanden.
Auch wenn ich jetzt noch nicht die richtigen Parameter kenne, sollten 
die ja nicht so schwer herauszufinden sein.

Habe Beide mir geladen und werde versuchen die zum laufen zu bringen.

Vg Dirk

von Stefan F. (Gast)


Lesenswert?

Dirk schrieb:
> Auch wenn ich jetzt noch nicht die richtigen Parameter kenne, sollten
> die ja nicht so schwer herauszufinden sein.

Nummer und Name des IRQ Handler kann ich dir auch nicht nennen. Ich habe 
keinen F0. Du wirst sie finden.

von Dirk (Gast)


Lesenswert?

Das ist nicht schwer zu finden, kann nur gerade nicht nachsehen.

Hast keinen M0, da verpasst Du was.
Die sind inzwischen bei mir auf gut 7 Platinen drauf und verdrängen 
einen AVR nach dem anderen.
Nach dem Inbetriebnahme System kommt der erste M3 (103) zum Einsatz, dem 
verpasse ich dann auch einen VCP mit MCURSES zum Testen, wenn alles gut 
läuft.
Die 2 Projekte werde ich in den nächsten 4 Wochen ausgiebig testen und 
wie gesagt wenn ich was finde helfe ich gerne.

VG Dirk

von Stefan F. (Gast)


Lesenswert?

Dirk schrieb:
> Hast keinen M0, da verpasst Du was.

Doch habe, einen STM32 L073. Der macht einen deutlich aufgeräumteren 
Eindruck als der F103.

> Nach dem Inbetriebnahme System kommt der erste M3 (103) zum Einsatz

Nimm lieber gleich den F303, das ist der direkte Nachfolger zum F103. 
Der ist auch deutlich aufgeräumter und kostet nicht mehr. Außerdem hat 
er eine FPU, und du riskierst nicht, eine schlechte Fälschung zu 
bekommen.

von Thomas Z. (usbman)


Angehängte Dateien:

Lesenswert?

Hier nun meine neue Version des VCP mit Header Files für usb1.1 und 
vcp1.2. Das ganze ist noch nicht 100% ausgereift, funktioniert aber als 
Replacement für usb.c. Im Quelltext hab mal ein paar Stellen mit todo 
markiert, die ich noch für buggy halte.
Noch entspricht das Endpoint Management dem Original, d.h. die 
bidirektionalen  sind noch nicht implementiert.

Die entgültige Version werde ich dann vermutlich in Projekte & Code 
einstellen.

von W.S. (Gast)


Lesenswert?

Mal noch ein paar Anmerkungen meinerseits:

uint16_t UsbSetup(void)

Ein int würde ausreichen, da in diesem Treiber niemals etwas anderes als 
0 zurückgegeben wird. Wahrscheinlich täte es ein bool auch. Das ganze 
ist ne historisch gewachsene Altlast und wenn du ohnehin erhebliche 
Änderungen machst, dann wäre mMn ein bool oder gar ein void eher 
angebracht.

volatile bool receiving = false;
volatile bool transmitting = false;

Sowas setzt die Vorbelegung des RAM im Startup voraus. Ich würde die 
beiden Flags schlichtweg in UsbSetup auf null setzen, dann kann der 
Startup tun oder lassen, was er will. Ist mal wieder eine Fehlerquelle 
weniger.

void UsbStrOut(char* S)
Schmeiß es lieber ersatzlos raus. Ich hatte mich schon vor Jahren 
darüber geärgert, daß ich es überhaupt mal dort hineingesetzt hatte. 
Hab's dann nur der Kompatibilität zuliebe drin gelassen.

/* holt ein Zeichen vom USB ab */
/* Achtung: wenn nix abzuholen ist, wird 0 zurückgeliefert */
char UsbGetChar(void)
{ char c;
  c = 0;
  if (!configurationSet || suspended)
  {  return -1;
 ...

Naja, return 0 wäre mMn eher passend. Ist ja ein 8 Bit Char.

Und in UsbGetChar()
... if (!receiving)...

Wenn das denn schon im Usercode-Bereich behandelt werden soll, dann 
kommt mir dabei der kühne Gedanke, auf den Ringpuffer in Richtung 
PC-->µC ganz und gar zu verzichten. Immerhin haben wir ja Bulk_Out_A und 
Bulk_Out_B zum eventuellen Umschalten, wenn man sich diese Mühe machen 
will. Vorbereitet ist das alles schon seit langem, ich hatte es bloß 
damals nicht benutzt, weil ich eben nicht wollte, daß der Usercode in 
den Innereien des USB-Interrupts herumfuhrwerkt, sondern daß der 
Usercode sich eben damit begnügt, im zuständigen Ringpuffer 
nachzuschauen, ob's was gibt oder nicht.

W.S.

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
> Mal noch ein paar Anmerkungen meinerseits:

Danke, einiges was du aufzählst ist mir selbst schon aufgefallen. 
Momentan arbeite ich nur am USB Teil.
Am Usercode bzw Buffer Code ist alles noch original zu der Version von 
Stefan.

Im Moment stelle ich gerade die beiden Bulk EPs so um, dass Sie beide 
auf EP1 liegen.

Im Endausbau soll das dann so sein, das es bis zu 4 VCPs gibt VCP 1 wie 
gehabt, die restlichen auf ser. Schnittstellen umgeleitet.

von W.S. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Im Endausbau soll das dann so sein, das es bis zu 4 VCPs gibt VCP 1 wie
> gehabt, die restlichen auf ser. Schnittstellen umgeleitet.

Bist du sicher, daß man das tatsächlich braucht?
Nicht alles, was man können kann, muß man auch tatsächlich tun.

Sinn und Zweck der ganzen Übung war ja ursprünglich, daß man an seinem 
µC eine Serielle per USB hat, um darüber mit dem PC kommunizieren zu 
können. Da reicht eine Serielle völlig aus.

Und ich hatte auch drauf achten wollen, daß der Treiber nicht unnötig 
umfänglich wird, damit auch diejenigen, die IAR oder Keil bis jeweils 
32K benutzen, noch genug Flash haben für ihr eigentliches Zeugs.

Vorschlag: Mach ruhig deine Vollst-Version, aber mach auch gleich drauf 
eine wieder abgespeckte Version nur für das Nötigste.

W.S.

von Thomas Z. (usbman)


Lesenswert?

W.S. schrieb:
> Vorschlag: Mach ruhig deine Vollst-Version, aber mach auch gleich drauf
> eine wieder abgespeckte Version nur für das Nötigste.

Na ja meine Idee ist es konfigurierbar zu machen im einfachsten Fall ist 
es dann funktionsgleich zum Original.

Das ist auch gleichzeitig meine Spielwiese um mit der ST Peripherie warm 
zu werden.

von Thomas Z. (usbman)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt die bidirektionalen BulkEps eingebaut und auch sonst 
einiges umgestellt. Noch ist der Code funktionsgleich zum Original, 
wobei ich die Kopier Funktionen von und zum usbmem etwas verändert habe.
Es wäre gut wenn das jemand auf einem Controller gegenchecken kann der 
UMEMSHIFT=0 benötigt. Ich habe nur auf den BluePills getestet.

Der code ist momentan sogar etwas kleiner als das Original. Noch nicht 
imlementiert, aber vorbereitet ist der mehrfach VCP.

Usb2CV läuft ohne Fehler durch, im Moment funktioniert 
SetConfiguration(0) noch nicht, das wird aber nur als Hinweis gemeldet.

Ich würde mich über Rückmeldungen freuen.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Thomas Z. schrieb:
> Es wäre gut wenn das jemand auf einem Controller
> gegenchecken kann der UMEMSHIFT=0 benötigt.
> Ich würde mich über Rückmeldungen freuen.

Funktioniert auf den ersten Blick.

von Thomas Z. (usbman)


Lesenswert?

Danke für den Test. Dann hab ich das ja soweit richtig verstanden. Ich 
hatte sowieso nur die Kopierfunktionen für EP0 geändert. Wenn ich einen 
Fehler gemacht hätte, würde Enum auf dem f303 nicht mehr funktionieren.

von Alex (Gast)


Lesenswert?

Hallo Thomas,

ich hab gestern Abend endlich wieder Zeit gefunden, um an den Modulen 
weiterzumachen. Hab deine obige Version in meinen F042 reingespielt und 
hat bei mit unter Win10 funktioniert.
Auf Win7 ging es nicht, Win behauptet dass es keinen passenden Treiber 
hat.
Der einzige Unterschied, den ich fand ist, dass mit der neuen Version 
von dir die Hardware-ID im Gerätemanager
'USB\VID_0416&PID_5011&REV_0100&MI_00'
ist.
Mit der alten Version (usb.c. von S.F.) war das MI_00 nicht dabei.

nachdem ich auf Win7 die NuvotonCDC.inf wie folgt angepasst habe, läuft 
es.
1
[Devices.NT]
2
%DESCRIPTION%  = NuvotonCDC_DEV, USB\VID_0416&PID_5011
3
%DESCRIPTION%  = NuvotonCDC_DEV, USB\VID_0416&PID_5011&MI_00
4
5
[Devices.NTamd64]
6
%DESCRIPTION%  = NuvotonCDC_DEV, USB\VID_0416&PID_5011
7
%DESCRIPTION%  = NuvotonCDC_DEV, USB\VID_0416&PID_5011&MI_00
Nur falls sonst noch jemand W7 laufen hat... :-)


Ein anderes Thema hab ich leider immer noch:
Hab die Version von dir auf einem jener Module getestet, die beim 
Runterschicken von Befehlen immer Probleme hatten (auf einem alten, 
nicht dem mit dem ich diesen Thread gestartet hab).
Die Übertragungsprobleme hab ich damit immer noch.
Manchmal verträgt es 1-2 Befehle, aber irgendwann ist Schluss mit 
Runterschicken.


Alex

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> falls sonst noch jemand W7 laufen hat

Uff, das ist bei mir "aus den Augen, aus dem Sinn".

von W.S. (Gast)


Lesenswert?

Alex schrieb:
> Manchmal verträgt es 1-2 Befehle, aber irgendwann ist Schluss mit
> Runterschicken.

Tja, wenn ich mir all die Bemühungen anschaue, die es hier in diesem und 
in anderen Threads so gegeben hat, dann stellt sich mir das 
(generalisiert gesagt) etwa so dar:

1. Einführung von #ifdef's oder zusätzlichen Headern, um mit 1 Treiber 
mehrere STM32Fxxx abdecken zu können. Meine Ansicht: 1 Treiber für exakt 
1 Plattform gefällt offenbar manchen nicht.

2. Meine Quasi-Automatik, den Datenfluß per Timertick des USB wieder in 
Gang zu kriegen, gefällt offenbar auch nicht, deswegen die Bemühungen, 
dieses stattdessen von der 'userland'-Seite aus zu tun.

3. Änderungen bei Features und Status und Verhalten wenn nicht 
angeschlossen, zu denen ich damals keine ausreichende Dolumentation 
hatte, was aber bei mit trotzdem bislang funktioniert hatte. ( Warum 
eigentlich? Sind das Dinge, die bei einer popligen Seriellen per USB gar 
nicht wirklich relevant sind? )

4. Einführung von chipspezifischen Seriennummern.

5. Aufregung über die simple Verzögerungsschleife, obwohl das eigentlich 
recht nebensächlich (und nur GCC-spezifisch) ist.

Naja, und der Rest ist eigentlich gleich geblieben. Nun hab ich ja schon 
vor Zeiten und auch mit anderen µC so meine eigenen Tests gemacht, Daten 
von wenig bis massiv in beiden Richtungen über den USB geschickt und war 
damit eigentlich zufrieden. Eigentlich deshalb, weil ich vom Device aus 
nicht wirklich habe feststellen können, ob auf dem PC nun irgend eine 
Anwendung den seriellen Kanal geöffnet hat oder nicht - da ist eben 
immer das OS mit seinem Treiberstack und der Fileverwaltung dazwischen.

Und nun geht es bei dir nach all diesen gehabten Änderungen noch immer 
nicht - und noch immer weißt du nicht, woran es denn tatsächlich liegt.

Und ebenso noch immer kann jeder andere hier nur spekulieren über das, 
was ihm dazu so einfällt:
- Hardwarefehler
- Firmwarefehler durch Verwendung von irgendwas (Cube und Konsorten), 
das umbemerkt an irgend einer Stelle dazwischenfunkt.
- Fehler in deinem Algorithmus, die Befehle auszuwerten oder auf 
unverständliche Befehle zu reagieren
- Probleme mit dem OS auf dem PC
- Irgend etwas Unbedachtes in deiner Anwendung auf dem PC
- Irgend eine Art Synchronisationsproblem zwischen PC und µC
und so weiter.
Das alles hilft hier offenbar auch bloß nicht.
Also nochmal mein Vorschlag: alles, was der µC über den USB empfängt, 
auf einem anderen Kanal (z.B. UART) auszugeben und dort dann mal zu 
schauen, was da so kommt.

W.S.

von Thomas Z. (usbman)


Lesenswert?

@Alex
dass du eine geänderte inf umter W7 braucht liegt ganz einfach daran 
dass das Device nun ein Compound Device ist (wg IAD) der Treiber wird 
nun nicht mehr auf das Device installiert sondern auf das Interface 
(MI_00). Änderungen in der Funktionalität gibts noch keine. Es ist also 
sehr unwahrscheinlich dass dies bei deinen Übertragungsproblemen hilft.

@W.S.
mir ist klar dass dir die includes bez der spec nicht gefallen. Die 
machen aber letztendlich auch nichts anderes als defines im Quelltext. 
Es ist bei mir halt so dass diese Header files zentral in einem Ordner 
\usb liegen. Ich habe diese Dinger über die Jahre gepflegt und 
erweitert, weshalb ich die immer benutze. Es gibt aber ansonsten 
keinerlei Unterschied.

Die Feature Geschichte hab ich korrigiert weil deine Version einfach 
nicht funktionierte (TimeOut beim Request). Ursache war der Stall(1) an 
diversen Stellen. GET_LINE_CODING funktioniert übrigens auch nicht, da 
du in OnEpCtrlIn() das an der falschen Stelle auswertest.
Die Feature Geschichte geht übrigens auch beim 3fach VCP von Niklas 
nicht er antwortet aber korrekt mit einem STALL Handshake. Das sind aber 
formale USB Geschichten. Der VCP funktioniert trotzdem.

Die einzige Sache die ich bis jetzt wirklich neu gemacht habe sind die 
beiden CopyFunktionen von und USB Mem für EP0. Deshalb auch die 
Testanfrage für andere MCUs.

Eine Sache noch:
Meiner Meinung nach ist die Initialisierung der EpTable[0].TxCount mit 0 
falsch. (Ergibt nur einen 2 Byte Buffer)

von Alex (Gast)


Lesenswert?

> Also nochmal mein Vorschlag: alles, was der µC über den USB empfängt,
> auf einem anderen Kanal (z.B. UART) auszugeben und dort dann mal zu
> schauen, was da so kommt.

Das hatte ich ja schon mit dem Hello-World / Echo - Beispiel von S.F, 
dort war der Fehler reproduzierbar.


> - Hardwarefehler
Mit Sicherheit hat es was mit bestimmten Chip-Exemplaren zu tun. Der 
Fehler tritt bei manchen µCs auf, egal auf welche PCB sie gelötet sind.

> - Fehler in deinem Algorithmus, die Befehle auszuwerten oder auf
> unverständliche Befehle zu reagieren
Ist durch den Echo-test ausgeschlossen

> - Probleme mit dem OS auf dem PC
Wurde bereits ausgeschlossen. Tritt auf verschiedenen PCs und OS auf 
(W7, W10, Linux)

> - Irgend etwas Unbedachtes in deiner Anwendung auf dem PC
Wurde ausgeschlossen. Tritt auch in Terminalprogrammen auf.

> - Irgend eine Art Synchronisationsproblem zwischen PC und µC
> und so weiter.
?

> - Firmwarefehler durch Verwendung von irgendwas (Cube und Konsorten),
> das umbemerkt an irgend einer Stelle dazwischenfunkt.
Gut möglich, aber wenn ich den Codegenerator nicht anwerfe, sollte doch 
nur der Code aus meinen Files verarbeitet werden, oder?


Folgende beiden Fragen stell ich mir aktuell:
Nachdem ich ja mit wireshark schon rausgefunden habe, dass es immer dann 
auftritt, wenn auf ein Bulk_out -Paket keine Antwort von STM kommt:

a) Werden diese Antwortpaket vom STM in Hardware erzeugt, oder macht das 
die usb.c?

b)
Thomas schrieb am 22.2.:
> Dann gibt es einen Bug beim Get/SetFeature bzw GetStatus liefert nicht
> das erwartete Ergebnis. (STALL oder 0).
Hier wurde ja kein relevanter Bug gefunden, oder?

Alex

von Stefan F. (Gast)


Lesenswert?

Alex, hast du mal den originalen Code von 2015 ausprobiert? Ich denke 
das wäre ein einfacher Schritt und damit würdest W.S. auch wieder 
einfangen, so dass er möglicherweise mehr Lust hat, dir zu helfen, 
anstatt die Anderungen zu kritisieren.

Siehe Beitrag "Re: STM32 USB Übertragungsproblem mit Code von S.F.", da 
habe ich seine originale Variante als Cube IDE Projekt angehängt.

von W.S. (Gast)


Lesenswert?

Alex schrieb:
> Folgende beiden Fragen stell ich mir aktuell

Also, wenn ich mich recht erinnere, dann wird bei meinem Original beim 
EpBulkOut solange der Puffer nicht geleert, bis dessen Inhalt in den 
Ringpuffer hineinpaßt. Was soll der Treiber auch anderes machen? Egal 
was man sich ausdenkt, es kommt immer die Situation, wo der Host einen 
mit Daten vollpflastert, die dann eben warten müssen, bis sie von der 
Anwendungsschicht der Firmware abgeholt werden (und wann das sein wird, 
kann der Treiber nicht wissen).

Das ist sozusagen das Gegenstück zu der Situation beim Bulk-In, wo man 
selber zusehen muß, daß man bei anstehenden Daten im Ringpuffer den 
EpBulkIn befüllen und damit den ganzen Transfer in Gang setzen muß.
Nun weiß ich nicht, ob es zum Leeren des EpBulkIn-Puffers an irgend 
einer Stelle eine Art Timeout gibt, so wie das beim Hängenlassen des 
Timerticks passiert.

Mal ne Frage an dich: Ändert sich das Verhalten deiner Firmware, wenn du 
testeshalber den Ringpuffer für die Richtung PC-->µC mal riesengroß 
machst? Mir kommt da nämlich der Verdacht, daß es irgend einen 
zeitlichen Stau geben mag, der dazu führt, daß für eine zu große 
Zeitspanne die vom PC gesendeten Daten nicht abgeholt werden und dann 
irgend ein Timeout zuschlägt, oder daß bei dem Herumschalten am 
Interruptcontroller irgend etwas verloren geht. Ja, das sind auch nur 
weitere Vermutungen, aber was soll man machen?

W.S.

von W.S. (Gast)


Lesenswert?

Nachtrag: ich seh grad, daß ich oben eigentlich EpBulkOut gemeint habe, 
also die Situation, wo der Puffer vom PC gefüllt wurde und man keinen 
Platz hat, die Daten dort raus und woanders rein schaufeln zu können.

W.S.

von J. -. (Gast)


Lesenswert?

Auf einem STM32F405 läuft es bei mir nicht. Prinzipiell habe ich die 
Clocks genauso initialisiert wie bei den Codevarianten vom MCD-Team, und 
da läuft CDC/VCP auf dem F4.
Muß noch etwas drüber grübeln, und kann meine geliebten #ifdefs leider 
noch nicht reinpfriemeln :(
heulend und schluchzend

von Stefan F. (Gast)


Lesenswert?

Jürgen S. schrieb:
> Auf einem STM32F405 läuft es bei mir nicht.

Der STM32F4 hat ein andere USB Peripherie, darauf wird der hier 
diskutierte Code niemals laufen können.

Siehe die Vergleichstabelle in 
https://www.st.com/resource/en/application_note/dm00296349-usb-hardware-and-pcb-guidelines-using-stm32-mcus-stmicroelectronics.pdf 
Seite 3.

Der Code ist nur für die Variante "A" geeignet.

von J. -. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Der STM32F4 hat ein andere USB Peripherie, darauf wird der hier
> diskutierte Code niemals laufen können.
Ja, aber ... dann muß ich ja zwei verschiedene USB-Treiber für zwei 
verschiedene Chips nehmen. Das wäre schrecklich :)
Muß mal den Code noch genauer anschauen, wo Registerzugriffe 
stattfinden, wie und welche. Der Code vom MCD-Team war bei mir schon 
ge#ifdefd und lief sowohl für den F103 und den F407 (wenn ich mich recht 
entsinne).

Edit: Danke für die Beschreibung. Schmöker ich mal durch.

von Alex (Gast)


Lesenswert?

@ W.S.
>Mal ne Frage an dich: Ändert sich das Verhalten deiner Firmware, wenn du
>testeshalber den Ringpuffer für die Richtung PC-->µC mal riesengroß
>machst?

Klingt grundsätzlich plausibel, aber es tritt der Fehler ja manchmal 
schon auf, wenn ich nur 'stop<crlf>' sende. Also nur 6 Zeichen (in einem 
einzigen BulkOut). Die Buffer sind alle deutlich größer.

Trotzdem werd ich morgen VM kurz testen, ob die Buffergrößen einen 
Einfluss haben...

Alex

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

@ Stefan:
den Originalen Code von W.S. 2015 hab ich nicht probiert, da ich ja 
UMEM_SHIFT 0 habe und die Unterscheidung da ja noch nicht drin ist.
Und das selbst umzustricken ist sicher keine gute Idee...

Test zu den Buffergrößen:

Die Buffergröße hat keinen merklichen Einfluss.
Der Echo Test bleibt mal nach 10 chars stecken, mal nach 30.
Rx Buffer von 128 auf 512 erhöht -> keine Änderung.

Anbei mein main.c. von dem Test

von Alex (Gast)


Lesenswert?

Allerdings scheint es so zu sein, dass das Verhalten durch das Senden 
von einem langen String auf einmal sehr zuverlässig reproduzeirbar ist.
Und zwar unabhängig von der Buffergröße.
Schicke ich
'123456789012345678901234567890<crlf>' steht der bulkOut sofort.
'1234567890<crlf>' verträgt er mit kurzen Pausen länger.

von Alex (Gast)


Lesenswert?

Um auszuschließen, dass es durch eine der Änderungen von euch ohnehin 
behoben wurde, hab ich eben den Echo Test noch mit dem neuen Code von 
Thomas probiert. Zeigt grundsätzlich selbes Verhalten.

Ich hab das selbe .bin-file jetzt auf 2 der 'schlechten' µCs 
aufgespielt.
Der eine steigt bei 10 Zeichen reproduzierbar aus, der andere schafft 
jedesmal 40.

von Thomas Z. (usbman)


Lesenswert?

@Alex:
es könnte durchaus sein dass was mit dem UMEM Shift nicht so 
funktioniert wie es sollte. Ich hab ja alle meine Tests mit den Bluepill 
Boards gemacht. Um ehrlich zu sein habe ich den Fall mit UMEMSHIFT =0 
noch nicht näher betrachtet. Ich muss mir das mal genauer anschauen und 
mit einem Datenblatt vergleichen.

Die ganzen bisherigen Änderungen meinerseits beziehen sich im 
Wesentlichen auf die Enum und Kompatibilität zur Spec. Der einzige 
offene Punkt auf meiner Liste ist nur noch GetLineCoding was sich aber 
nicht auf die Buffer auswirkt.

von Alex (Gast)


Lesenswert?

So wies scheint ist das Risiko, dass der BulkOut steckenbleibt größer, 
je mehr Zeichen übertragen werden.
Wo im Code muss ich mich hinsetzen (breakpoint), um den Fall abzufangen, 
wo das passiert?

von Thomas Z. (usbman)


Lesenswert?

Ich denke dass irgendwas mit der EP_Table nicht stimmt. Halte die 
Funktion einfach mal in der Main an nachdem die ENum abgeschlossen ist 
und gib die Ep_Table aus. Wenn ich richtig liege stimmt dort was nicht 
mit den Einträgen.
Es ist übrigens egal ob du meine Version oder die Version von Stefan 
benutzt.
Du solltest das nur die Version angeben, da meine EP_Table etwas anders 
aussieht. (wg dem bidirktionalen EP).
Mich würde der Inhalt der TableStruct interessieren. (mindestens 64 
Bytes)

Zusatzlich solltest du sicherstellen dass die APB Freq. > 10MHz ist.

Siehe Errata:

Possible packet memory overrun/underrun at low APB 
frequencyDescriptionSome data sheet and/or reference manual revisions 
may omit the information that 10 MHz minimum APB clockfrequency is 
required to avoid USB data overrun/underrun issues.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Thomas Z. schrieb:
> Zusatzlich solltest du sicherstellen dass die APB Freq. > 10MHz ist.
>
> Siehe Errata:

wenn ich mir das so recht überlege passt das sehr gut zu deinem 
"Manchmal" Problem.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

Anbei ein screenshot von der EpTable,
die Basisadresse ist ja 0x40006000,
EpTableOffset 0x190

Die Clock sollte 48Mhz sein, der µC läuft auf HSI48 (SYSCLK), und HPRE 
und PPRE sind jeweils 0.

von Alex (Gast)


Lesenswert?

oops, ist 3mal das gleiche

von Alex (Gast)


Lesenswert?

Ich probier mal, die ABP clk zu halbieren, die ist laut Datenblatt auf 
48MHz maximal spezifiziert.

von Alex (Gast)


Lesenswert?

Hab den HPRE auf 2 gesetzt, SYSCLK damit auf 24MHz -> keine Änderung.

Der Screenshot der EpTable war aber im Debug-Modus gemacht, mit dem 
.bin-file konnte ich den Effekt wieder nicht reproduzieren.

von temp (Gast)


Lesenswert?

Also Alex, ich habe deine main.c und den Stand von Thomas:
Beitrag "Re: STM32 USB Übertragungsproblem mit Code von S.F."
mal zusammengebaut und auf meinem Nucleo32 mit STM32F042K6 probiert. 
Außer dass meine Finger schon blutig sind vom Tippen im hterm kann ich 
keine Auffälligkeiten feststellen.
Allerdings sehe ich folgendes:
Ich toggle im 1ms Systick einen PIN und messe bei meinem Board 505,7Hz. 
Mit anderen Worten die CSR arbeitet nicht. Wir haben dich von Anfang an 
auf den Taktpott gesetzt, ohne Reaktion. Wenn ich die Stelle mit meinen 
Code ersetze, bin ich bei 499,8Hz->CRS geht. Ich erwarte jetzt von dir, 
dass du mal deine Messwerte des Takts nennst, sonst quatschen wir bis 
Weihnachten über Endpunkte und Fehler im Code die keine sind.
1
void SystemInit(void)
2
{
3
  // Enable the Internal High Speed oscillator (HSI48)
4
       SET_BIT(RCC->CR2, RCC_CR2_HSI48ON);
5
       while (!READ_BIT(RCC->CR2, RCC_CR2_HSI48RDY));
6
7
   // switch SYSCLK to HSI48
8
       MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_HSI48);
9
       while (!READ_BIT(RCC->CFGR, RCC_CFGR_SWS_HSI48));
10
11
     //  Configure the USB clock source
12
       MODIFY_REG(RCC->CFGR3, RCC_CFGR3_USBSW, RCC_CFGR3_USBSW_HSI48);
13
14
   SystemCoreClock = 48000000;
15
16
  // Initialize system timer
17
    SysTick_Config(SystemCoreClock/1000);
18
19
  //[ALEX]
20
    SET_BIT(RCC->APB2ENR, RCC_APB2ENR_SYSCFGEN);
21
  while (!READ_BIT(RCC->APB2ENR, RCC_APB2ENR_SYSCFGEN));
22
23
  //[ALEX]
24
  SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);
25
  while (!READ_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN));
26
27
  //[ALEX] remap pins for USB
28
  SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA11_PA12_RMP);
29
30
  // Setup Clock Recovery System CRS to sync with USB SOF
31
       // enable CRS
32
       SET_BIT(RCC->APB1ENR, RCC_APB1ENR_CRSEN);
33
       while (!READ_BIT(RCC->APB1ENR, RCC_APB1ENR_CRSEN));
34
//#define CRS_ORG
35
#ifdef CRS_ORG
36
       // reset CRS
37
       RCC->APB1RSTR |= (RCC_APB1RSTR_CRSRST);
38
       RCC->APB1RSTR &= ~(RCC_APB1RSTR_CRSRST);
39
40
       CRS->CFGR = CRS_CFGR_SYNCDIV_0 |       // prescaler: no divider
41
          CRS_CFGR_SYNCSRC_1 |      // source: USB SOF
42
         CRS_CFGR_SYNCPOL   |      // polarity: falling
43
         (47999U << CRS_CFGR_RELOAD_Pos) | // reload value
44
         (34 << CRS_CFGR_FELIM_Pos);   // error limit value
45
          // reload value =  f_{target} / f_{sync} - 1
46
          // reload value =  48e6/1e3 - 1 = 47999
47
          // error limit value: from cubeMx code generator
48
49
       // Adjust HSI48 oscillator smooth trimming
50
       MODIFY_REG(CRS->CR, CRS_CR_TRIM, (32 << CRS_CR_TRIM_Pos));
51
          // trim value: from cubeMx code genererator
52
53
       // START AUTOMATIC SYNCHRONIZATION
54
       SET_BIT(CRS->CR, CRS_CR_AUTOTRIMEN | CRS_CR_CEN);        // enable automatic trimming & frequency error counter
55
#else
56
  // CRS einschalten
57
  RCC->APB1ENR|=RCC_APB1ENR_CRSEN;
58
  CRS->CR|=CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
59
#endif
60
}

von temp (Gast)


Lesenswert?

Nachtrag: Ich habe bei mir die Werte in CSR->CFGR so gelassen wie sie 
beim Reset sind. Die passen. Dein Fehler ist das CRS_CFGR_SYNCDIV_0. Das 
bedeutet das 0. Bit und somit Division durch 2. Damit kann das nicht 
gehen.
1
#define  CRS_CFGR_SYNCDIV                    ((uint32_t)0x07000000U) /* SYNC divider                       */
2
#define  CRS_CFGR_SYNCDIV_0                  ((uint32_t)0x01000000U) /* Bit 0                              */
3
#define  CRS_CFGR_SYNCDIV_1                  ((uint32_t)0x02000000U) /* Bit 1                              */
4
#define  CRS_CFGR_SYNCDIV_2                  ((uint32_t)0x04000000U) /* Bit 2                              */
Oder du hast andere Header.

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> es könnte durchaus sein dass was mit dem UMEM Shift nicht so
> funktioniert wie es sollte. Ich hab ja alle meine Tests mit den Bluepill
> Boards gemacht.

Ich habe allerdings mit dem STM32F303 und STM32L073 getestet. Die würden 
gar nicht funktionieren, wenn dieser Teil fehlerhaft wäre.

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Wo im Code muss ich mich hinsetzen (breakpoint), um den Fall abzufangen,
> wo das passiert?

Breakpoints sind ungünstig. Sobald das Programm stoppt, fällt die USB 
Verbindung aus.

Wenn du debuggen willst, dann mit Hilfe der eingebauten Text-Ausgaben 
auf SWO. Eventuell wirst du weitere Meldungen hinzufügen, um das problem 
einzukreisen.

von Alex (Gast)


Lesenswert?

Du hast recht, sas mit dem CRS schaut definitiv nach einem Fehler aus.
Ich hab zwar andere Header, aber es ist auch bei mir eine Division /2.
Diese Einstellungen hab ich aus dem Codegenerator vom Cube, bevor ich 
auf W.S.-Usb umgestellt hab, nicht auszuschließen, dass da beim 
'entfernen' der HAL Mist passiert ist.

Den Takt direkt hab ich (wie ich schon weiter oben mal geschrieben hab) 
nie exakt geprüft, weil ich kein MCO (main clock out) auf dem Package 
habe.
Allerdings tritt der Kommunikationsfehler auch mit externem TCXO auf, 
daher hatte ich die Taktsache ausgeschlossen (abgesehen von ev. zu 
großem Jitter, den ich wegen fehlendem MCO nicht prüfen kann).

Was ich nicht kapier ist, wieso das dann bei 20 Modulen funktioniert.
Und es funktioniert wochenlang mit 10 Modulen parallel ohne Fehler.
Der CRS müsste ja komplett daneben sein.

Ich fang gleich an zu testen.

von temp (Gast)


Lesenswert?

Alex schrieb:
> Den Takt direkt hab ich (wie ich schon weiter oben mal geschrieben hab)
> nie exakt geprüft, weil ich kein MCO (main clock out) auf dem Package
> habe.

Dann mach's doch wie ich, im Systick-Handler (1ms) einfach einen 
beliebigen Pin toggeln und mit dem Multimeter messen. Ich hab hier ein 
Meterman 37XR.

Alex schrieb:
> Was ich nicht kapier ist, wieso das dann bei 20 Modulen funktioniert.
> Und es funktioniert wochenlang mit 10 Modulen parallel ohne Fehler.
> Der CRS müsste ja komplett daneben sein.

Kann sein, dass die falschen CRS Einstellungen den Takt noch mehr 
verbiegen als wenn es ausgeschaltet ist. Und dass bei 20 Modulen die 
RC-Oszillatoren nicht gleich sind ist auch klar. Eventuell sind ein paar 
davon auf Kante. Die gemessenen 505,x Hz bei meinem Modul sind ja schon 
mehr als 1%. Keine Ahnung ab wann das kritisch wird. Allerdings, wenn 
man das CRS einschaltet, dann sollte es schon richtig funktionieren.
Im Netz findet man:

The USB 2.0 Specification defines the tolerances for data rates on the 
USB bus, including all drift sources.  For low-speed communications, the 
data rate is specified to be 1.5 Mbps +/- 1.5%.  For full-speed 
communications, the data rate is specified to be 12 Mbps +/- 0.25%.

If an external clock source is used as the USB clock, it must meet the 
above specifications for reliable USB communications.  The internal 
oscillator on the device family can be used for either low or full-speed 
USB.  If the internal oscillator is used for full-speed USB 
communications, 'clock recovery' must be enabled to ensure the data rate 
tolerance specification of +/- 0.25%.

Tu uns doch bitte mal den Gefallen und miss. Es würde uns alle 
interessieren ob, und wenn ja in wie weit die Module streuen.

von Alex (Gast)


Lesenswert?

Hab bei einem 'schlechten' Modul mit Echo-Test den Divider korrigiert, 
und es läuft definitiv besser. Konnte noch keinen Fehlerfall 
verursachen, auch nicht durch exterem lange Zeichenketten.
-> Diese Fehlerursache ist damit verifiziert.

Ich hab ja einen PWM-Pin an den Modulen, da hab ich die Frequenzen mal 
von mehreren Modulen (mit scope) verglichen. Jitter war deutlich zu 
erkennen, aber keine Frequenzunterschiede zwischen den Modulen.
Ich hab daraus geschlossen, dass der CRS gundsätzlich funktioniert.

Wenn aber der CRS so total falsch konfiguriert war, dürfte das ja 
garnicht sein.
Morgen Vormittag wird gemessen (das ist ein Versprechen :-)

von Alex (Gast)


Lesenswert?

Nur um Verwirrung wegen unklarer Formulierung auszuschließen:  die 
Messung mit dem Scope hatte ich vor einiger Zeit gemacht, hatte weiter 
oben darüber berichtet.

von Alex (Gast)


Lesenswert?

Messung an den PWM-Ausgängen:
Sollfrequenz = 48MHz/78 = 615,38kHz

bei 2 Modulen (davon ein 'schlechtes') am Scope die Frequenzen gemessen:
616,07 und 616,14 kHz (schwankt jeweils um +- 0,1 kHz).

die selben Module mit korrigierter CRS-Einstellung:
beide ca. 615,5kHz mit +- 0,4 kHz (schwankt deutlich mehr !?).


Ich bin bei meiner letzen Messung (post vom 24.2.) von der Annahme 
ausgegangen, dass wenn der CRS nicht funktioniert, die 
Frequenzabweichungen zwischen den Modulen deutlich zu sehen sein 
sollten. Dementsprechend hatte ich die Frequenzen der Module miteinander 
verglichen, den Absolutwerten aber keine übermäßige Bedeutung 
beigemessen. Das war offenbar ein entscheidender Fehler.
Dennoch bin ich extrem erstaunt, wie 'gut' die nicht nachgetunten 
RC-Oszillatoren sind.

von temp (Gast)


Lesenswert?

Alex schrieb:
> Messung an den PWM-Ausgängen:
> Sollfrequenz = 48MHz/78 = 615,38kHz
>
> bei 2 Modulen (davon ein 'schlechtes') am Scope die Frequenzen gemessen:
> 616,07 und 616,14 kHz (schwankt jeweils um +- 0,1 kHz).
>
> die selben Module mit korrigierter CRS-Einstellung:
> beide ca. 615,5kHz mit +- 0,4 kHz (schwankt deutlich mehr !?).

Das erscheint mir trotzdem noch komisch. Bei meinem Teil lag die 
Abweichung bei einem Prozent und es ging noch. Ob ein Oszilloskope da 
zum Messen taugt wage ich fast zu bezweifeln. Aber egal, wenn es 
geholfen hat ist's gut.

von Stefan F. (Gast)


Lesenswert?

Die Frage ist, was wir jetzt daraus lernen. Taugt das CRS nicht?

von Alex (Gast)


Lesenswert?

Das erscheint nicht nur dir komisch.

Mich ärgert vor allem, dass ich mich offensichtlich ziemlich massiv 
selbst ausgetrickst habe, bei der Fehlersuche.
Klassisches Layer-8-Problem ...

Und was es mit dem externen 24MHz TCXO auf sich hat, den ich ja 
testhalber auf eines der Module 'draufgepopelt' habe, ist mir aktuell 
auch noch nicht klar. Da muss ich ja auch irgendeinen Bock geschossen 
haben...

Jetzt hol ich mir einen Kaffee und Schokolade....

von Johannes S. (Gast)


Lesenswert?

Beim H743 gibt es auch das CRS, dummerweise funktioniert das in einigen 
Revisionen nicht, ist im Errata festgehalten. Aber so einen Boliden wird 
man sowieso mit Quarz(oszi) betreiben.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Die Frage ist, was wir jetzt daraus lernen. Taugt das CRS nicht?

Doch, aber halt nicht, wenn es so wie bei Alex falsch konfiguriert 
wurde.

Deinem Jittern bei deinen Messungen traue ich immer noch nicht über den 
Weg.
Hier mal 2 Oszibilder vom Toggeln im (jetzt 100µS) SystickHandler.
Das wackelt und jittert auch nichts.

von Stefan F. (Gast)


Lesenswert?

Könnte eventuell eine mangelhafte (noch nicht ganz kaputte) USB 
Verbindung zum Versagen des CRS führen?

Schlechte USB Verbindung müsste man vermutlich an unregelmäßigen SOF 
Paketen erkennen können, wenn man da mal einen I/O Pin toggelt.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Könnte eventuell eine mangelhafte (noch nicht ganz kaputte) USB
> Verbindung zum versagen des CRS führen?

Nochmal zum Mitschreiben, der CRS Teil ist im Code von Alex falsch 
konfiguriert gewesen, und, kaum macht man's richtig -> schon geht's.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Nochmal zum Mitschreiben, der CRS Teil ist im Code von Alex falsch
> konfiguriert gewesen, und, kaum macht man's richtig -> schon geht's.

Aber du hast gerade erst zitiert:

> bei 2 Modulen (davon ein 'schlechtes') am Scope die Frequenzen gemessen:
> 616,07 und 616,14 kHz (schwankt jeweils um +- 0,1 kHz).

> die selben Module mit korrigierter CRS-Einstellung:
> beide ca. 615,5kHz mit +- 0,4 kHz (schwankt deutlich mehr !?).

Das war nach seiner letzten Korrektur - habe ich zumindest so 
verstanden.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das war nach seiner letzten Korrektur - habe ich zumindest so
> verstanden.

Was er da misst ist das eine, mit CRS auf alle Fälle die richtige 
Frequenz von 615.5kHz bei 615.38kHz Soll, was beweist dass sie 
funktioniert.
Und damit geht es ja. Er muss für sich nur klären, ob seine Messungen 
was taugen.
Oder seine Chips entsorgen. Eventuell werden die von den Chinesen auch 
schon gefälscht oder der Ausschuss verkauft.

von Alex (Gast)


Lesenswert?

Ich teste gerade die Änderungen auf mehreren Modulen,
dabei ist mit eine Kleinigkeit in der initSerial aufgefallen:
1
#define U_ID       (*(volatile uint8_t *)( 0x1FFFF7E8UL)) //for F103 only
2
3
...
4
...
5
6
     while(i > -1)    //r�ckw�rts lesen
7
     {
8
        b   = U_ID + i;
9
        *s  = toAscii(b);      s += 2;
10
        *s  = toAscii(b >> 4); s += 2;
11
        i--;
12
     }

die U_ID müsste erst nach der Summe in der Schleife dereferenziert 
werden.

Sonst haben alle die gleiche, komische Seriennummer ...


Hab grad einen ziemlichen Sauhaufen auf meinem Rechner mit 
Geister-Treibern den ich versuche aufzuräumen. Manche der Module melden 
sich jetzt zwar als COMxx an, ich kann sie aber nicht öffnen. Auch das 
Deinstallieren der Treiber hilft da nicht. So kann ich die Änderungen 
nicht mal wirklich durchtesten. Hat da jemand eine Idee, wie man das 
unter W7 aufräumt?

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
> Hat da jemand eine Idee, wie man das
> unter W7 aufräumt?

Versuche mal das Batch Script, nachdem du alle verzichtbaren COM-Ports 
aus der Systemsteuerung entfernt hast (auch die verborgenen!):
1
@echo off
2
3
for /L %%A in (1,1,300) do (
4
  echo Deleting OEM%%A.INF
5
  pnputil /d OEM%%A.INF
6
)

Es entfernt alle Treiber, die gerade nicht benutzt werden, und erzwingt 
somit bei Bedarf eine Neuinstallation dieser.

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> die U_ID müsste erst nach der Summe in der Schleife dereferenziert
> werden.

Ups du hast Recht, das ist Käse....

Wegen der Tests:
Es ist vermutlich sinnvoll die SerienNummer ganz auszuschalten, solange 
du am testen bist. Das verhindert dass immer neue Vom Ports angelegt 
werden.

Zum Aufräumen gibt es mehrere Möglichkeiten:
im Gerätemanager ausgeblendet Geräte anzeigen und dann löschen. Das geht 
auch unter W7.
Oder im system32\ Driver die entsprechenden PNF Dateien löschen. Oder in 
der Registry unter HKLM\system\CurrentControlset\Enum\Usb\ die 
entsprechenden Einträge löschen. Dieser Registry Zweig sollte auch unter 
W7 vorhanden sein.

von J. -. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Der Code ist nur für die Variante "A" geeignet.
Yep, verstanden. Ich habe mir auch noch das Referenzhandbuch zum F4 und 
USB_OTG_FS angeschaut, das sind alleine 140 Seiten. Das ist zuviel 
jammer
Immerhin kommt ihr dem eigentlichen Problem von Alex immer mehr auf die 
Schliche, da lernt man auch was dabei. Von CRS hab ich noch nie was 
gehört :)

von Stefan F. (Gast)


Lesenswert?

Jürgen S. schrieb:
> das sind alleine 140 Seiten. Das ist zuviel

Yepp.

Ich hatte auch kurz erwägt, mit einen F4 zu kaufen nur um den Code dafür 
anzupassen. Aber als ich dann die Doku dazu sah, fiel mir wieder ein, 
dass selbst ein L0 schon sehr viel mehr kann, als ich jemals brauchte. 
Damit hat sich das für mich wieder erledigt.

von Alex (Gast)


Lesenswert?

Die Ausgeblendeten COMs hatte ich entfernt, aber erst das Entfernen der 
'USB-Verbundgeräte' hats gelöst. :-)

Noch eine Beobachtung:
Mir ist auch aufgefallen, dass die neue Version von Thomas (die mit dem 
MI_00 im descriptor) weniger 'gutmütig' bei Wackelkontakten ist.
Beispiel:
COM ist im Terminal offen, und die Verbindung wird mechanisch kurz 
unterbrochen (z.B. Wackelkontakt).
In der vorigen Version von S.F. hab ich den COM geschlossen und wieder 
geöffnet, und es ging weiter.
In der neuen muss der Port geschlossen werden, dann das Modul aus- und 
wieder Eingesteckt werden, erst dann kann ich den Port wieder öffnen.
(So war es aber auch mit der Version vor diesem Thread).
Hat das was mit der Vorbereitung zur multi-VCP zu tun?

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> Hat das was mit der Vorbereitung zur multi-VCP zu tun?

Der IAD ist vermutlich nicht die Ursache. Allerdings habe ich die 
Initialisierung der Bulk EPs von InitEndpoints() nach USB_ConfigDevice() 
verschoben. Die Bulk Endpoints dürfen ja erst arbeiten wenn das Device 
conigured ist. Zusätzlich habe ich bei USB_SET_INTERFACE die ToggleBits 
zurückgesetzt. Das könnte das Problem erklären. Entferne Mal die If A 
Abfragen an der Stelle.

von Stefan F. (Gast)


Lesenswert?

Ich glaube auch, dass Thomas Änderungen diesbezüglich relevant sind. Nur 
welche genau, das vermag ich nicht zu erkennen. Auch mir ist 
aufgefallen, dass das Re-connecten nach einer kurzen Unterbrechung nun 
viel zuverlässiger funktioniert.

von Thomas Z. (usbman)


Lesenswert?

Was mir dazu noch einfällt
Vielleicht werden in ClassStart nicht alle Variablen zurückgesetzt, das 
ist noch original. Beim Öffnen des Comports sollte ein USB_SET_INTERFACE 
Request kommen. Dort müsste eigendlich auch eine Abfrage der Interface 
Nummer rein. Darauf hab ich bisher verzichtet.

von Alex (Gast)


Lesenswert?

Wieder mal ein Testreport zu meinen Übertragungsproblemen.
Hab aktuell 10 Module mit der korrigierten Software, die werden das 
Wochenende über durchlaufen.

Das Korrigieren des CRS hat die Stabilität bei langen Strings erhöht, 
vollständig gelöst ist die Sache damit aber nicht.
Ich hab derzeit 3 Patienten isoliert, die auch mit der korrekten 
CRS-Einstellung Probleme machen. Auch bei sehr kurzen Strings (mein 
'stop<crlf>'-Befehl).

Bei allen ist aber die CLK gut.
Hab mit einem Counter mal die Taktraten an meinem PWM-Ausgang gemessen, 
die passen alle. Da muss noch was im Busch sein...

Nachtrag zu den Frequenzmessungen: Durch den CRS zappelt der Takt (Wert 
am Counter) deutlich mehr rum als wenn der CRS abgeschaltet ist.
Je kürzer die Gatezeit umso deutlicher wird das. Wahrscheinlich wär es 
weg, sobald die Gatezeit mit dem SOF synchronisiert würde, das muss ja 
vom nachtunen im SOF-Takt stammen.
Vielleicht könnte man das Nachstellen noch sanfter machen, aber ich 
glaub mich zu erinnern dass die Schrittweite relativ grob ist und man 
das daher nicht wirklich 'smooth' hinbekommt.

von temp (Gast)


Lesenswert?

Also, wenn du den Takt im Qszi jittern siehst, ist wohl noch was mit 
deiner Hardware im Argen. Besorg dir mal ein Nucleo32 mit dem F042 damit 
du wenigstens mal zum Vergleich etwas hast was richtig geht. Oder zeig 
uns mal ein Bild von Schaltung und Layout. Wenn du hier von PWM 
sprichst, uns aber einen andern Code vor die Füße wirfst, brauchst du 
dich nicht wundern wenn dich bald keiner mehr ernst nimmt. Fehler sucht 
man meiner Meinung nach anders. Wenn hier im Thread nicht noch an einem 
guten Code für USB gearbeitet würde wäre ich längst raus.

von Thomas Z. (usbman)


Lesenswert?

Ich habe dieses Wochenende den Code erweitert und einen 2. VCP in die 
Deskriptoren eingehängt. Dazu habe auch einige defines aktiviert und die 
Kopierroutinen für die Bulk EPs so erweitert, dass die Routinen auch mit 
anderen EPs funktionieren.

Das hat soweit funktioniert, ich kann einen zweiten VCP sehen. Leider 
habe ich mir beim Testen das einzige BluePill Board mit WCH Controller 
abgeschossen.

Ich kann also im Moment nur noch mit STM testen.
Der Bug mit der SN ist gefixt.

Vermutlich hab ich nächstes WE was vorzeigbares, dann auch mit Umleitung 
zu den ser. Schnittstellen.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

@temp
Ich versteh deinen Frust, vor allem das mit der Taktgeschichte ist 
wirklich sehr blöd gelaufen.
Von allen Seiten kamen die Hinweise mit dem Takt und wie wichtig ein 
Quarz ist bei USB.
Ich hab ehrlich nicht gedacht, dass es (noch dazu mit einem falsch 
laufenden) RC-Oszillator überhaupt möglich ist, überhaupt eine 
lauffähige Übertragung hinzubekommen, und diesen Fehler als Ursache 
ausgeschlossen.
Und ich denke, dass ich damit zumindest nicht ganz allein bin hier.

Zudem hab ich ein Modul mit einem TCXO getestet, und die 
Übertagungsprobleme hatte ich damit auch.
Da das Verhalten der 'schlechten' Module nicht immer 100%ig gleich 
reproduzierbar ist, ist ein zuverlässiger Vergleichstest immer 
schwierig.


Die Entscheidung, welche Informationen hier reinsollen und welche nicht, 
ist nicht immer ganz einfach, und führt ja nicht von ungefähr immer 
wieder zu Diskussionen. Dass es da unterschiedliche Auffasungen gibt ist 
völlig logisch.
Ich gehe eigentlich davon aus, dass die CLK-Sache jetzt passt.
(Nur um klarzustellen: meine Jitter-Aussage betraf nicht eine Messung an 
benachbarten CLK-Pulsen sondern eine optische Wahrnehmung bei Messung 
mit verzögerter Zeitbasis bzw. die Schwankung der Frequenzmessung.)

Die Board-Level Hardware würde ich eigentlich ausschließen, aber das war 
beim CRS ja ich so.... Daher Schaltungsteil und Layout anbei.

Folgendes wurde schon alles probiert:
- Abblock-Cs vergrößern
- Die 33pF an den USB Leitungen austauschen (auf 22p) (um falschen Wert 
auszuschließen)
- Die 33pF an den USB Leitungen wegnehmen
- Den Spannungsregler tauschen
- die 10R-Widerstände in den USB-Leitungen prüfen
- auf Lötfehler kontrollieren
- 3V3 prüfen
- mit und ohne Kabel betreiben
- externen TCXO auflöten
- den STM auf ein anderes Board löten (mit und ohne anderer Peripherie)
- den STM auf ein anderes Board löten (von einem 'guten' Modul)

Letzter Stand:
ein 'schlechtes' Modul, CLK wurde überprüft,
echo-Test funktioniert mit 10 Zeichen zuverlässig immer,
mit 11 Zeichen bleibts beim ersten Versuch stehen.
Die Hello Worlds kommen munter weiter.

Auch hier ist es so, dass ein längerer String dazu führt, dass die 
Übertragung zusammenbricht. War bei der CRS-Sache auch so.
Aber der CRS ist ja jetzt korrigiert und vermessen ist dieses Modul 
auch.

von Thomas Z. (usbman)


Lesenswert?

Ich reagiere bei offenen Pins immer allergisch. Zumindest den Osz In 
würde ich versuchsweise auf GND legen, oder die Pins per Programm 
anfassen.

von temp (Gast)


Lesenswert?

1. Wenn aum Ausgang des NCP700 wirklich nur 100nF sind, wundert mich 
hier überhaupt nichts mehr. "Stable with Ceramic Output Capacitors as 
low as 1µF" sagt das Datenblatt. Und dann sollte der auch >=1µF haben 
wenn 3,3V anliegen. Also ich hätte da irgendwas zwischen 2,2 und 10µF 
verwendet. Gerade bei den Spannungswandlern und Kerkos habe ich selbst 
schon genügend Lehrgeld bezahlt.

2. Die Reset Leitung offen als Antenne zu führen ist eventuell auch 
nicht optimal. Das wird zwar hier nicht das Problem sein, aber wer weiss 
das so genau.

von temp (Gast)


Lesenswert?

3. So wie ich das sehe ist im Layout am Ausgang des Sapnnunsreglers 
überhaupt kein C. Du hast zwar in gefühlt 1km Abstand und ein paar Vias 
2 C's an den 3.3V des Controllers, aber der Sapnnungsregler selbt hängt 
so gesehen in der Luft. Das solltest du unbedingt vermeiden, egal ob das 
die Ursache für deine Probleme ist oder nicht.

von Stefan F. (Gast)


Lesenswert?

Wieso kommt der Plan eigentlich erst jetzt und nicht vor 265 Beiträgen?

Und dann ist er auch noch total unspektakulär, nichts was dieses 
Staatsgeheimnis erklären würde.

von Alex (Gast)


Lesenswert?

Thx für comments,
@0 :-)
Solange der Osc-Block abgeschaltet ist, dürfts da nix geben.
@1 die Bestückung ist bei 2x1µ, aber ja, sie sind zu weit weg, vor allem 
da neben dem noise-c noch Platz gewesen wäre. Zumindest einen von denen 
werd ich direkt zum Regler setzen.
(In die Falle mit der Minimum-C. an LDOs bin ich schon öfter getappt.)
@2 der RST hat einen Pullup mit max 55k, dürfte m.E. nach bei dem kurzen 
Stück unkritisch sein.
@3 -> @1, die 3V3 sind sauber, auch bei den 'schlechten' Modulen.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Alex schrieb:
> @1 die Bestückung ist bei 2x1µ, aber ja, sie sind zu weit weg, vor allem
> da neben dem noise-c noch Platz gewesen wäre. Zumindest einen von denen
> werd ich direkt zum Regler setzen.

2x1µF ist aber auch falsch. Beim Abblocken kann man nicht davon ausgehen 
dass mehr immer nur besser ist. Ein 0,1µF C verhält sich bei hohen 
Frequenzen nun mal anders als ein 1µ oder mehr. Wenn, dann sollte der 
100nF drin bleiben und ein größerer (10µ) parallel. Und der hautnahe zum 
Spannungsregler zusätzlich, aber nicht verschieben.

Wenn du dir mal das Blockschaltbild vom STM32F042 ansiehst, wirst du 
auch sehen, dass die RC-Generatoren von Vdda gespeist werden. Da würde 
ich auch mal L und C überprüfen ob das konform mit der Spezifikation 
ist. Die schreibt insgesamt größere Kapazitäten vor.

von Alex (Gast)


Lesenswert?

> Ein 0,1µF C verhält sich bei hohen
> Frequenzen nun mal anders als ein 1µ oder mehr. Wenn, dann sollte der
> 100nF drin bleiben und ein größerer (10µ) parallel.

Nein, das ist in der Regel keine gute Idee. Die 
Hochfrequenz-Eigenschaften der Cs werden durch die Serieninduktivität 
bestimmt, die in erster Linie von der Bauteilgeometrie (also vom 
Package) abhängt.
Durch Parallelschalten von Cs unterschiedlicher Werte können sich 
Resonanzen ergeben, die in einem schmalen Frequenzbereich die 
Abblock-Wirkung deutlich reduzieren.
Wenn man unterschiedliche Werte parallel schaltet, dann sollte einer 
davon einen höheren ESR haben, um die Sache zu dämpfen.

von Alex (Gast)


Lesenswert?

Hab grad versucht an der VDDA das Rauschen zu messen, bin aber mit den 
Scope nicht weit gekommen. Rauschlevel ist etwa so groß als wenn ich den 
Tastkopf mit dem Gnd-Clip verbinde. Also nicht aussagekräftig und nicht 
größer als 1mVeff.
Konnte auch keine 48-MHz Signalkomponente im Spektrum finden.

Im Datenblatt ist ein 1µ // 10n vorgeschlagen, nachdem aber der HSI48 
nur ca. 330µA braucht und ein recht guter Ferrit davorsitzt, müssten die 
100nF leicht ausreichen.
Die überraschend gute Stabilität des RC-Osc bestätigt das ja auch.

von Alex (Gast)


Lesenswert?

Nur um die Gefühlsmäßige Abschätzung mit den 100n @ VDDA zu untermauern:

Wenn der STM im Mittel 330µA zieht, dann sind das in einer Periode des 
HSI48 knapp 7pC (330µA/48MHz).
Selbst wenn der die 7pC jetzt als Impuls aus dem 100nF rauszieht, wären 
das nur  7pC/100nF = 70µV.
Klar mess ich das nicht mit dem Scope :-)

von W.S. (Gast)


Lesenswert?

Alex schrieb:
> Im Datenblatt ist ein 1µ // 10n vorgeschlagen,

bedenke mal, daß vieles in älteren Dokumentationen noch von der Annahme 
ausgeht, daß Kondensatoren im µF Bereich Elkos sind. Die waren bis vor 
einiger Zeit ja auch die billigsten für größere Kapazitäten. Aber das 
ist vorbei. Der allgegenwärtige keramische 10µ/10V im 0805 ist seit 
Jahren der Universal-Abblocker, wenngleich er neuerdings von 0603 oder 
noch kleiner abgelöst wird. Ich hatte mich zu diesem Thema nämlich mal 
mit unserer Bestückerfirma unterhalten, als ich die letzten Tantal-Elkos 
aus den Produkten entfernt hatte. Kannst dich ja mal bei 
Wittig-Electronic in Brand-Erbisdorf nach den am besten gehenden C's 
erkundigen.

W.S.

von temp (Gast)


Lesenswert?

Alex schrieb:
> Nein, das ist in der Regel keine gute Idee.
komisch nur dass das STM so vorschreibt.

Alex schrieb:
> Die überraschend gute Stabilität des RC-Osc bestätigt das ja auch
Da stehe ich auf der Leitung. Hast du nicht weiter oben geschrieben dass 
deine Messwerte wackeln? Und auch mit CRS darf da nichts wackeln.
Hast du das ganze auch mal an einem anderen USB Port oder hinter einem 
Hub probiert?

Alex schrieb:
> Rauschlevel ist etwa so groß als wenn ich den
> Tastkopf mit dem Gnd-Clip verbinde. Also nicht aussagekräftig und nicht
> größer als 1mVeff.
Es geht auch nicht um das Rauchlevel. Schließlich haben wir hier keine 
statischen Verhältnisse. Der interessante Punkt ist dabei wie das System 
auf dynamische Laständerungen reagiert. Und das kriegt man wohl schlecht 
mit dem Draufgucken auf das Oszi mit. Da wäre es ehr angesagt das 
Speicheroszi vom Controller an den zeitlich relevanten Stellen zu 
triggern und da im zeitlichen Umfeld was festzustellen oder 
auszuschließen.
Fakt ist doch eins, deine Probleme liegen in der Hardware. Immerhin bist 
du der einzige mit solchen Problemen und dann auch noch mit 
unterschiedlichen Ergebnissen bei unterschiedlichen Platinen.

von Alex (Gast)


Lesenswert?

>> Nein, das ist in der Regel keine gute Idee.
>komisch nur dass das STM so vorschreibt.
findet man in vielen Datenblättern, ist aber Mist.
Lässt sich auch in Spice leicht zeigen, dass es Mist ist.

>> Die überraschend gute Stabilität des RC-Osc bestätigt das ja auch
>Da stehe ich auf der Leitung. Hast du nicht weiter oben geschrieben dass
>deine Messwerte wackeln? Und auch mit CRS darf da nichts wackeln.
>Hast du das ganze auch mal an einem anderen USB Port oder hinter einem
>Hub probiert?

Mit CRS muss es wackeln, schließlich schraubt der CRS jede ms mal an 
der Einstellung vom Oszillator rum. Daher wackelt es auch weniger, je 
länger die Gate-Zeit des Counters ist, weil sich die Änderungen dann 
rausmitteln.
Und wie schon öfters geschrieben, gibts das Problem unter W7, W10, Linux 
und auf verschiedenen PCs, mit und ohne Kabel usw.
Noch nicht geschriebem: mit verschiednen aktiven und passiven Hubs 
konnte ich keine Änderung im Verhalten feststellen.


> Es geht auch nicht um das Rauchlevel. Schließlich haben wir hier keine
> statischen Verhältnisse. Der interessante Punkt ist dabei wie das System
> auf dynamische Laständerungen reagiert.
Nachdem am AVDD nur der HSI48 läuft, dürfte es da kaum Lastwechsel 
geben, die mit dem Empfang über USB zu tun haben.
Wenn eine Störung von der 3V3 / 5V - Seite kommt, sollten die Ferrite 
das sehr gut abfangen. Die Messung war, um auszuschließen dass die 100nF 
zu klein sind. Daher hab ich auch speziell nach der 48MHz-Komponente im 
Rauschen gesucht.

> Fakt ist doch eins, deine Probleme liegen in der Hardware. Immerhin bist
> du der einzige mit solchen Problemen und dann auch noch mit
> unterschiedlichen Ergebnissen bei unterschiedlichen Platinen.
Richtig, aber die Probleme hängen mit bestimmten STM-Exemplaren zusammen 
und dem darauf laufenden Code zusammen. Ich hab bei allen Test bisher 
keinen Ansatzpunkt dafür gefunden, dass es an der Beschaltung liegt.
Stichwort: 'schlechten' Chip auf eine andere Platine löten usw...

Mein aktueller Ansatz:
nachdem ich ja mal beobachtet hab, dass es einen Unterschied macht, ob 
ein Programm als Debug oder als Release kompiliert ist, werd ich 
versuchen jeweil 'gutes' und ein 'schlechtes' Minimalbeispiel mit 
reproduzierbarem Ergebnis zu bekommen.

von temp (Gast)


Lesenswert?

Dein Text ist voll von "müsste" und "dürfte" und da du es sowieso besser 
weißt wie es geht nehme ich hier nichts mehr ernst.

Alex schrieb:
> Messung an den PWM-Ausgängen:
> Sollfrequenz = 48MHz/78 = 615,38kHz
>
> bei 2 Modulen (davon ein 'schlechtes') am Scope die Frequenzen gemessen:
> 616,07 und 616,14 kHz (schwankt jeweils um +- 0,1 kHz).
>
> die selben Module mit korrigierter CRS-Einstellung:
> beide ca. 615,5kHz mit +- 0,4 kHz (schwankt deutlich mehr !?).

Alex schrieb:
> Mit CRS muss es wackeln, schließlich schraubt der CRS jede ms mal an
> der Einstellung vom Oszillator rum. Daher wackelt es auch weniger, je
> länger die Gate-Zeit des Counters ist, weil sich die Änderungen dann
> rausmitteln.
Sorry, aber liest du selbe was du schreibst? +-0,4kHz bei 615,5kHz sind 
1,3% Abweichung. Welchen Sinn soll den das CRS haben wenn der Oszillator 
am Ende um 1,3% wackelt. Lies dir den entsprechend Abschnitt im Manual 
durch. Da wird nicht ständig was verändert. Es wird einmal solange 
verändert bis die Differenz in einem gewissen Fenster bleibt und danach 
ist gut. Jedenfalls solange der Oszillator nicht soweit driftet, dass es 
aus dem Fenster läuft. Das passiert aber nicht jede ms und wenn doch 
liegt da aber massiv was daneben. Temperatur und Spannung haben einen 
Einfluss, ohne Frage. Beides sollte aber so stabil sein, dass hier 
nichts wackelt. Noch dazu im ms Takt.
Ich bleibe dabei, besorg dir eine vernünftige Vergleichshardware und 
such dann deine Fehler.

von Alex (Gast)


Lesenswert?

+-0,4 von 615 sind bei mir +-0,06% Abweichung, der Bereich ist dann 
0,12% groß.
Das 'sollte' auch deiner Meinung nach genügen, oder?

von temp (Gast)


Lesenswert?

Alex schrieb:
> +-0,4 von 615 sind bei mir +-0,06% Abweichung, der Bereich ist dann
> 0,12% groß.
> Das 'sollte' auch deiner Meinung nach genügen, oder?

ok, diesmal hast du Recht und ich die Tomaten auf den Augen.

von Alex (Gast)


Lesenswert?

dann geht uns jetzt beiden wieder besser :-)

Spiel grad mit der Compiler-Optimierung rum:
sobald die Optimierung ausgeschaltet ist, läuft die Sache.
Bei -Os (size) gehts mit max. 10 chars,
bei -O3 enumeriert das device nicht korrekt.

von temp (Gast)


Lesenswert?

Alex schrieb:
> Spiel grad mit der Compiler-Optimierung rum:
> sobald die Optimierung ausgeschaltet ist, läuft die Sache.
> Bei -Os (size) gehts mit max. 10 chars,
> bei -O3 enumeriert das device nicht korrekt.

Das nützt nur leider keinem was, solange du nicht deinen Code oder das 
Projekt hier rein stellst. Das was wir bisher haben ist ja was anderes 
mit PWM u.s.w.
Also, ohne dass du da eine 1:1 Kopie rüberwachsen lässt, und wir vom 
selben Code sprechen, kann man dir softwareseitig nicht mehr helfen.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

War schon in Arbeit.
Ist der Code von S.F. Echo-Test umgemünzt auf die neuen files von 
Thomas.
Der PWM-Teil ist da jetzt wieder auskommentiert (aber noch zu sehen).

von temp (Gast)


Lesenswert?

Wir kennen deine Umgebung nicht und der Startupcode fehlt, ebenso die 
HAL. Also bitte so vervollständigen dass man ein identisches Projekt 
bauen kann.
Ich werde mir jetzt das nicht irgendwo zusammentragen.
Ich arbeite mit der Segger IDE. Also entweder du lieferst alles oder ich 
ändere es für Segger und du installierst die mal zum Vergleich.

von temp (Gast)


Lesenswert?

So hab das probiert mit allen Optimierungsleveln. Keine Auffälligkeiten. 
Das gemessene LED toggeln im Systick schwankt zwischen 499.6 und 
499.7Hz.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Hast du dir das RefManual mal durchgelesen? Da steht eindeutig: "One 
wait state, if 24 MHz < SYSCLK ≤ 48 MHz"

das FLASH->ACR Register in deinem Code ist aber 0.

Da fehlt:
1
  // Enable Prefetch Buffer and set Flash Latency 
2
  FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;

Ausser dein Gefühl sagt auch hier, scheiß egal was im Manual steht, es 
dürfte auch so gehen.

von Alex (Gast)


Angehängte Dateien:

Lesenswert?

System: CubeIDE 1.4.2

bezgl. Flash-Zugriff: Punkt für dich!!!!
Ist bei der Anpassung vom Echo-Test-Beispiel verlorengegangen.
Habs eben getestet: der Fehler ab 11 Chars bleibt.
Mein Gefühl sagt mir, es ist nicht die Ursache für den Fehler.

von Alex (Gast)


Lesenswert?

Ich bin nicht sicher, ob das eine HAL-File (stm32f0xx_it.c) ausreichend 
ist, eine Referenz auf was anderes hab ich auf die Schnelle nicht 
gesehen.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Ne, Cube und Hal, damit baue ich mir jetzt kein Projekt zusammen. Soviel 
Zeit habe ich auch nicht. Ich hänge dir aber mal mein Projekt dran. Ist 
für stm32f042f6 gebaut. Wenn du willst kannst du das ja mal bei dir 
probieren.

von Thomas Z. (usbman)


Lesenswert?

da ich im Moment einiges umbaue (mit wechselndem Erfolg) macht es nicht 
so viel Sinn eine neue Variante einzustellen.

Mir ist aber bei den EP Tables noch ein potentielles Problem aufgefallen 
welches ich noch nicht zuordnen kann. Ich hatte ja weiter oben schon mal 
die Behauptung aufgestellt dass EpTable[0].TxCount  = 0; falsch sei. Dem 
ist nicht so. Nun gibt es Stellen wo bei TxCount in reservierte Bits 
geschrieben wird.

Beispiel:  EpTable[1].TxCount = (i & 0x3FF) | EpBulkLenId;

Das ist vermutlich schon sehr lange im Code drin. Ich habe keine blassen 
Schimmer ob und wie sich das auswirkt. Aufgefallen ist mir das weil ich 
Speicher im USB Mem sparen muss, und deshalb die EP Tables kräftig 
umbauen muss.

von Alex (Gast)


Lesenswert?

@Thomas
würdest du sagen, dass ich mit dem Fehlersuchen eher warten sollte, bis 
du das 'fertig' hast?
Weil meine Fehlersuchkompetenz (besonders was C-Code anbelangt) ist ja 
nicht die Beste (da muss ich temp definitiv Recht geben !!)

von Alex (Gast)


Lesenswert?

@temp
Ich hab aus deinem Zip-File das Release-ELF in einen 'schlechten' Chip 
reingespielt. Der Fehler ist auch da, sobald ich mehr als 10 Zeichen 
runterschicke, ist Schluss mit BulkOut.
Im 'guten' Chip läufts. Verhält sich exakt so, wie bei meinen ELFs.

von temp (Gast)


Lesenswert?

Thomas Z. schrieb:
> Dem
> ist nicht so. Nun gibt es Stellen wo bei TxCount in reservierte Bits
> geschrieben wird.
>
> Beispiel:  EpTable[1].TxCount = (i & 0x3FF) | EpBulkLenId;

Beim F103 steht im Manual:
1
Bits 15:10 These bits are not used since packet size is limited by USB specifications to 1023 bytes. Their 
2
value is not considered by the USB peripheral.
3
4
Bits 9:0 COUNTn_TX[9:0]: Transmission byte count
5
These bits contain the number of bytes to be transmitted by the endpoint associated with the 
6
USB_EPnR register at the next IN token addressed to it.
Den Grund warum das W.S. so gemacht hat weiß ich nicht. Man kann das mit 
0 definieren und es geht trotzdem alles. Negative Auswirkungen würde ich 
nicht befürchten. Vielleicht hat sich da mal einer ein paar Marker in 
den Speicher gebaut zu Debugzwecken um Überschreibungen zu detectieren 
o.ä.
1
#define EpCtrlLenId 0  //  ((1<<15)|(1<<10))
2
#define EpBulkLenId 0  //  ((1<<15)|(1<<10))

Alex schrieb:
> Ich hab aus deinem Zip-File das Release-ELF in einen 'schlechten' Chip
> reingespielt. Der Fehler ist auch da, sobald ich mehr als 10 Zeichen
> runterschicke, ist Schluss mit BulkOut.
> Im 'guten' Chip läufts. Verhält sich exakt so, wie bei meinen ELFs.

Eventuell solltest du bei den schlechten Chip den Fehler mit dem Hammer 
suchen. Einmal kräftig draufhauen und du weißt genau warum er nicht mehr 
geht...
Ich traue deiner Hardware immer noch nicht. Der Software schon. Alles 
was wir hier diskutieren hat mit deinen Problemen nichts zu tun. Wo hast 
du die Chips gekauft?

von Alex (Gast)


Lesenswert?

Chips sind von Digikey.

> Eventuell solltest du bei den schlechten Chip den Fehler mit dem Hammer
suchen.
Ich sehe du bist ein Jünger Bob Widlars :-)!!!
'to widlarize something'

Der Ansatz ist möglicherweise der einzig sinnvolle.
Bisher wars immer so, dass die Fehler sporadisch mal da waren, und dann 
wieder weg.
Lag möglicherweise an der CLK-Geschichte.
Bei einem von 3 'schlechten' ist es jetzt exakt reproduzierbar, die 
anderen hab ich jetzt nicht durchgecheckt.
Vielleicht sollte ich die Chips einfach eintüten und beschriften, wenn 
sie dann mal in der Ecke liegen wächst sowieso Gras drüber...

von Thomas Z. (usbman)


Lesenswert?

Alex schrieb:
> @Thomas
> würdest du sagen, dass ich mit dem Fehlersuchen eher warten sollte, bis
> du das 'fertig' hast?

Ich würde sagen, dass mein Code eigendlich bei dir keine Veränderung 
bringen sollte. Ich werde da am 1. VCP nichts wesentliches verändern. 
Wenn sich da was tun sollte ist es eher ein Seiteneffekt, jedenfalls 
nichts absichtliches. Der Code von W.S. ist soweit ja ok und 
funktioniert.

von Alex (Gast)


Lesenswert?

Moin Leute

Um die schlechten Chips eindeutig zu identifizieren hab ich mir 
PC-seitig ein Skript geschrieben, das in einer Schleife die Anzahl der 
Zeichen die runtergeschickt werden kontinuierlich erhöht.
Ich sehe dann, bei wievielen Zeichen der STM aussteigt.
Die 'Hello World' Zeile und die beiden Delays hab ich auskommentiert.
Bei den meisten Modulen komme ich auf 47-51 Zeichen, dann stehts.
Bei manchen komme ich auf 5, 7, mal auf 13 oder 19

Jetzt hab ich, um zu verifizieren dass das wirklich an der Hardware 
liegt, mit cube ein HAL-USB-Echo-Projekt gebaut, dass auch die Zeichen 
einfach zurückschickt.

Meine Schleife geht bis 512 Zeichen, das schafft mit dem HAL-USB auch 
jenes Modul problemlos, das mit W.S. / Thomas Code immer bei 5 
aussteigt.

Für mich schaut das schon sehr danach aus, dass da in der Programmierung 
irgendwas nicht so glatt läuft wie es sollte.
Ich weiß, die Buffer sind nicht exakt gleich groß, der HAL-Treiber nimmt 
standardmäßig 1k Buffer, aber in Thomas code sind es auch 512 Bytes.

von temp (Gast)


Lesenswert?

Dann schmeiß doch mal dein Script in die Runde, damit man das 
nachvollziehen kann.

von Alex (Gast)


Lesenswert?

Wenn hilft:
Matlab:
1
s = serial('COM3','InputBufferSize', 2^16');
2
fopen(s);
3
string = [];
4
for i2 = 1:512
5
    disp (i2);
6
    
7
    string = [string '0']; 
8
    fwrite(s, string);
9
    
10
    pause(0.3);
11
    if (s.BytesAvailable > 0)
12
        char(fread(s, s.BytesAvailable)');
13
    end;            
14
end;
15
fclose(s);

Wenn der STM aussteigt, dann kommt der Fehler beim Schreiben:
1
Error using serial/fwrite (line 199)
2
Unsuccessful write: An error occurred during writing.

von W.S. (Gast)


Lesenswert?

Alex schrieb:
> Ich weiß, die Buffer sind nicht exakt gleich groß, der HAL-Treiber nimmt
> standardmäßig 1k Buffer, aber in Thomas code sind es auch 512 Bytes.

Mir kommt da ein übler Verdacht auf:

Für die Richtung µC-->PC hatte ich ja den Wiederanlauf per Timertick 
gemacht, von euch wurde das in den Userbereich mit "flush.." verschoben, 
aber immerhin ist für diese Richtung ja etwas da, was der Datenfluß in 
Gang hält bzw. wieder in Gang bringt. Diese Richtung sollte also 
abgehakt sein, denke ich mir mal...

ABER: für die umgekehrte Richtung, also PC-->µC, ist da nichts 
vorgesehen, weil da eigentlich der PC immer wieder dran erinnert, daß 
der Transferpuffer entleert werden soll.

Kann das also sein, daß bei dir diese wiederholten Interrupts 
ausbleiben, während der Ringpuffer noch zu voll ist, um den 
Transferpuffer in ihn auszuleeren? Daß das also einfach ein Effekt von 
zu langsamem oder zu spätem Abholen der eintreffenden Zeichen ist, der 
die Situation aufkommen läßt, wo der Ringpuffer leer ist, der 
Transferpuffer von EpBulkOut noch nicht entleert ist und sich NIEMAND 
drum kümmert, ihn zu entleeren?

Vielleicht sollte man sich doch überlegen, all die Eingriffe vom 
Userland in den USB wieder zurückzubauen und stattdessen beim 1ms 
Timertick grundsätzlich beide (bzw. alle) Bulk-EP's nachzuschauen, ob 
es da etwas zu leeren oder zu füllen gibt.

W.S.

von Stefan F. (Gast)


Lesenswert?

Bedenke, dass andere Leute den Code erfolgreich getestet haben, auch mit 
vollen Puffern.

von W.S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Bedenke,...

Ja was kann/soll man sich denn sonst noch als Szenario für die Probleme 
des TO ausdenken, wenn bereits alles ausprobiert worden ist?

Mir ist da durchaus klar, daß die krampfhafte Suche nach irgend etwas, 
wo man annimmt, daß vielleicht noch keiner dran gedacht hat, irgendwann 
mal in die Irre gehen muß.

Also, wenn's nicht daran liegt, dann war dieser Gedanke umsonst und kann 
abgehakt werden.

W.S.

von Alex (Gast)


Lesenswert?

Ich hab jetzt den minimalen Echo-Test mit debuglevel -g1 und 
optimization -Os kompiliert, auf diese Weise ist der Fehler noch 
reproduzierbar und ich kann Breakpoints setzen.
Hab als ersten Versuch einen Breakpoint im OnEpBulkOut in die Zeile
1
avail = EpTable[1].RxCount & 0x3FF;
gesetzt.
Wenn ich nur ein Zeichen sende, dann komm ich an den Breakpoint,
wenn ich zu viele schicke dann kommt das Programm dort nicht hin.

von Alex (Gast)


Lesenswert?

Hab in der ISR ein
1
if (I & ~SOF_)
eingebaut und einen BP reingesetzt, um alle IRQs außer den SOF zu 
erkennen.

Hier ist es auch so, dass der BP nicht erreicht wird, wenn viele Zeichen 
geschickt werden.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Ich glaube ich kann noch was zur allgemeinen Verwirrung beitragen.
Gestern habe ich ein kleines Tool geschrieben das ungefähr das macht was 
Alex sein Script auch macht. Mit dem Ergebnis, dass es bei mir mit dem 
STM32F042 und STM32F103 nicht stabil läuft. Irgendwann steht die 
Geschichte immer.
Warum hat das noch keiner gemerkt? Weil niemand so etwas im realen Leben 
macht:
1
  while (1)
2
    {
3
        // Send echo of received characters back
4
        while (UsbRxAvail())
5
        {
6
            char c=UsbGetChar();
7
            UsbCharOut(c);
8
        }
9
    }

Bei mir geht das immer so: Packet hin als Commando, Packet zurück. Bei 
den SLCAN-Interfaces z.B. auch nur mit Längen < 64Byte. So etwas macht 
keine Probleme. Ich hänge das Programm mal hier dran und würde mich über 
Testergebnisse von anderen freuen. Einfach nur aufrufen "usbcdctest 
comx" oder ./usbcdctest /dev/ttyACM0
Bei mir ist es häufig aber nicht immer so, das die es bis 63 Byte geht 
und ab 64 klemmt es. Deshalb wartet das Programm vor der 64 auf Enter.
Wenn man sich da die Ringbuffer Variablen ansieht, sieht man, dass die 
alle genau die 64Byte weiterzählen, und trotzdem kommt nichts mehr am 
Host an.
Ich habe auch einige Versionsstände probiert, aber keine hat den Test 
bestanden. Ich habe das unter Windows und unter Linux (Raspi) probiert 
mit dem gleichen Ergebnis.
Wenn ich den Test nur bis 63Byte mache, läuft es stundenlang ohne 
Probleme.

Bitte keine Kommentare zur Qualität des Testprogramms. Das ist mit 
heißer Nadel zusammengebaut, aber so einfach, dass jeder selbst 
Änderungen machen kann.

von temp (Gast)


Lesenswert?

ups, da war was doppelt. Eins kann ja ein freundlicher Moderator ja 
löschen.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Eins kann ja ein freundlicher Moderator ja löschen.

Lohnt sich nicht, das File ist erfrischen klein.

Ich mache alles unter Linux, deswegen werde ich es nicht ausprobieren.
Ich habe aber eigene Tests unter Linuc gemacht, die liefen gut.

Die Zahl 63/64 macht mich allerdings stutzig. Ist das nicht die maximale 
Größe, die per USB am Stück übertragen werden? Dazwischen wird es wohl 
kleine Pause geben, wo das Programm warten muss.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich mache alles unter Linux, deswegen werde ich es nicht ausprobieren.
> Ich habe aber eigene Tests unter Linuc gemacht, die liefen gut.

Es ist doch eine Linux Version dabei? Auf build.sh kannst du doch noch 
drücken?

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Es ist doch eine Linux Version dabei? Auf build.sh kannst du doch noch
> drücken?

Huch! Dann mache ich das mal am Wochenende

von Thomas Z. (usbman)


Lesenswert?

Stefan ⛄ F. schrieb:
> Die Zahl 63/64 macht mich allerdings stutzig. Ist das nicht die maximale
> Größe, die per USB am Stück übertragen werden?

Das ist richtig alles kleiner 64 ist ein sogenannter short Transfer (bei 
USB1.1) und beendet die Übertragung bei 64 Bytes gehen die Treiber davon 
aus dass es weiter geht. Das ist zum Beispiel ein wesentlicher 
Unterschied zu den FTDI Protokollen, die haben immer nur 62 Bytes 
Nutzdaten + 2 Statusbytes.

Ich habe auf dem Control EP etwas ganz ähnliches erlebt als ich die 
EP0_SIZE auf 8 reduziert habe, weil mir der Speicher im USB Mem knapp 
wurde. Da waren plötzlich Vendor und Device String weg weil diese genau 
ein vielfaches von 8 waren.

Da könnte durchaus noch ein Bug vergraben sein. Noch habe ich mich 
allerdings nicht mit den Bulkdetails beschäftigt, da muss ich auch noch 
Mal in der Spec nachlesen, aber möglicherweise muss bei genau 64 Bytes 
ein ZLP hinterher kommen.

von temp (Gast)


Lesenswert?

Es ist nur leider so ein geht/geht nicht Fehler.
Ich habe noch was interessantes. Mit dem Code von Stefans Webseite läuft 
der Test auf dem f042 bei mir jetzt durch. Da waren aber die Änderungen 
von Thomas glaube ich nicht drin. Irgendwann blickt man durch die vielen 
Versionen nicht mehr durch.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Hier nochmal für Alex das Testprojekt für den STM32F042 das hier schon 
seit einer halben Stunde vor sich hin schnurrt.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Da waren aber die Änderungen von Thomas glaube ich nicht drin.

Doch teilweise schon. Zumindest die, wo er meinte, dass sie akute Fehler 
korrigieren.

Später kamen dann Erweiterungen für neue Funktionen dazu, die habe ich 
nicht mehr übernommen.

von Thomas Z. (usbman)


Lesenswert?

Ein paar Änderungen sind auch in Stefans Version von mir drin. Das 
bedeutet aber doch ganz einfach dass sich in meinen Versionen noch ein 
dicker Bug befindet....
Der kann dann ja nur in einer der beiden Copy Funktionen für die Bulk 
EPs stecken...

Ich schau mir das nochmal an.

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Ich schau mir das nochmal an.

Das finde ich super Thomas, du bist echt nett.

von temp (Gast)


Lesenswert?

@Thomas
Der Fehler ist mit deiner Version vom 12.3. rein gekommen. Mit der vom 
4.3. geht es bei mir auch noch.
Alex hatte die vom 12.3. verwendet, mit der Version von Alex hatte ich 
meine Tests mit dem stm32f042 gemacht und so ist die Falle zugeschnappt.

von Thomas Z. (usbman)


Lesenswert?

@temp danke für den Hinweis. Das hatte ich schon vermutet da in der 
Version neue Bulkcopy Funktionen eingebaut habe...
Hier hab ich die schon wieder verworfen. Ich bitte also um etwas Geduld.
Andere Frage:
Ich glaube du warst es der gefragt hat ob man irgendwie erkennen kann 
wenn der Host den Port geöffnet hat oder?
Ich glaube ich hab da eine Lösung mit Hilfe des SetLineCoding requests 
sollte man das realisieren können. Ich hab hier ein Test laufen der beim 
Öffnen eine LED in Main toggelt. Es gibt manchmal noch Fehlanzeigen, da 
muss ich wohl noch ein paar Extras einweben. Darauf bin ich beim 
Überprüfen der Class Requests gekommen.

von temp (Gast)


Lesenswert?

Thomas Z. schrieb:
> Ich glaube du warst es der gefragt hat ob man irgendwie erkennen kann
> wenn der Host den Port geöffnet hat oder?
> Ich glaube ich hab da eine Lösung mit Hilfe des SetLineCoding requests
> sollte man das realisieren können.

Das habe ich auch schon mal geprüft. Beim Öffnen wird SetLineCoding 
gerufen, beim Schließen nicht.
Ich hab das aber für mich mit der DTR Leitung gelöst.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> usbcdctest /dev/ttyACM0

Hallo temp,
ich habe dein Testprogramm mit meinem Projekt 
http://stefanfrings.de/stm32/STM32F303CC_usb_test.zip getestet, aber 
davon abweichend folgende Hauptschleife:
1
    while (1)
2
    {
3
        char c;
4
        if (UsbGetChar(&c, 10)) // warte max. 10ms
5
        {
6
            UsbSendChar(c, 10); // warte max. 10ms
7
        }
8
    }

Es läuft sowohl unter Debian 11 als auch Windows 10 tadellos durch.

UsbRxAvail() funktioniert auch.

Unter Windows sehe die Eingabeaufforderung "please press enter" nicht. 
Braucht Windows vielleicht ein "\r\n" am Ende der Zeile? Ach egal, 
scheiß drauf.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> ich habe dein Testprogramm mit meinem Projekt
> http://stefanfrings.de/stm32/STM32F303CC_usb_test.zip getestet

Vielen Dank.

Stefan ⛄ F. schrieb:
> Es läuft sowohl unter Debian 11 als auch Windows 10 tadellos durch.
>
> UsbRxAvail() funktioniert auch.
>
> Unter Windows sehe die Eingabeaufforderung "please press enter" nicht.
> Braucht Windows vielleicht ein "\r\n" am Ende der Zeile? Ach egal,
> scheiß drauf.

Das bestätigt meine Beobachtung.

Stefan ⛄ F. schrieb:
> Unter Windows sehe die Eingabeaufforderung "please press enter" nicht.
> Braucht Windows vielleicht ein "\r\n" am Ende der Zeile? Ach egal,
> scheiß drauf.

Am besten die gesamte Eingabeaufforderung auskommentieren. Das ist ja 
nur für den speziellen Fall gedacht den ich hatte.

von temp (Gast)


Lesenswert?

temp schrieb:
> Am besten die gesamte Eingabeaufforderung auskommentieren.

So, ich habe noch einen Nachtrag. Und zwar mache ich seit Gestern 
Dauertests.  Die Eingabeaufforderung aus dem Testprogramm habe ich raus 
geschmissen. Mir war gestern schon mal aufgefallen, dass der Code von 
Stefans Webseite original mit Stm32Cube auch Hänger hat (release Mode 
-O3). Hier mal 4 Beispiele
1
send 409 bytes
2
  -read 345 bytes
3
timeout, read 345 bytes, ges: 59212613 bytes
4
5
send 420 bytes
6
  -read 356 bytes
7
timeout, read 356 bytes, ges: 62487578 bytes
8
9
send 174 bytes
10
  -read 110 bytes
11
timeout, read 110 bytes, ges: 48809529 bytes
12
13
send 493 bytes
14
  -read 429 bytes
15
timeout, read 429 bytes, ges: 28770411 bytes
Mit anderen Worten, da steckt noch ein Bug drin.
Ich selbst baue seit geraumer Zeit an meiner eigenen Version des ganzen. 
Die hat von Gestern zu Heute ein paar GB durchgespült ohne Hänger. Die 
Variante von Stefan (und die anderen davor sicher auch) schafften nicht 
mal 100MB. Im realen Leben dürfte das keine große Rolle spielen, aber 
ich gebe mich erst dann zufrieden wenn so etwas nicht mehr auftritt. Wie 
man an den Zahlen aber schön sehen kann, fehlen immer 64Byte am Ende.

von temp (Gast)


Lesenswert?

Thomas Z. schrieb:
> Das ist richtig alles kleiner 64 ist ein sogenannter short Transfer (bei
> USB1.1) und beendet die Übertragung bei 64 Bytes gehen die Treiber davon
> aus dass es weiter geht. Das ist zum Beispiel ein wesentlicher
> Unterschied zu den FTDI Protokollen, die haben immer nur 62 Bytes
> Nutzdaten + 2 Statusbytes.

Das vermute ich auch als Ursache. Änderungsvorschlag wäre entweder alle 
Pakete auf < 64 zu begrenzen oder nur das letzte.
1
void EpBulkBeginTransmit(void)
2
{
3
    int i, n;
4
    UMEM_FAKEWIDTH L, A;
5
    UMEM_FAKEWIDTH* P;
6
7
    P = (UMEM_FAKEWIDTH*) EP1TxABuffer;
8
    i = txw - txr;
9
    if (i < 0)
10
    {
11
        i += USB_TXLEN; // i = number of bytes to send
12
    }
13
    if (i > EpBulkMaxLen)
14
    {
15
        i = EpBulkMaxLen;
16
    }
17
    // verhindern, dass als letztes! Packet eines mit 64byte gesendet wird
18
    else if (i==EpBulkMaxLen)
19
    {
20
      i=EpBulkMaxLen-2;
21
    }
Hier besteht aber noch das Restrisiko, wenn aus dem Userland jemand den 
tx- Ringbuffer genau nach diesem Zeitpunkt löscht, fehlt wieder das 
letzte kurze Paket.

von Thomas Z. (usbman)


Lesenswert?

Ich habe gestern die halbe Nacht nach einem Fehler gesucht der mir bei 
den Classrequests aufgefallen ist. Nichts was ich probiert habe hat 
funktioniert. Das war wie wenn ich das Programmieren verlernt hätte.

Irgendwo gibt's noch ein prinzipielles Problem im Code, oder im 
Verständniss des USB cores. Um auszuschliesen dass ich mir selbst ein 
Bein stelle bin ich dabei bis zurück zum Original von W.S. gegangen.

Gefunden hab ich bis jetzt nichts. Am WE geht's weiter.

von temp (Gast)


Lesenswert?

Mit meinen oben genannten Änderungen läuft der Test seit gestern Abend 
problemlos durch.

von Bernd N. (_bn_)


Angehängte Dateien:

Lesenswert?

temp schrieb:
> Ich glaube ich kann noch was zur allgemeinen Verwirrung beitragen.
> Gestern habe ich ein kleines Tool geschrieben das ungefähr das macht was
> Alex sein Script auch macht. Mit dem Ergebnis, dass es bei mir mit dem
> STM32F042 und STM32F103 nicht stabil läuft. Irgendwann steht die
> Geschichte immer.

Ich habe jetzt ebenfalls ein Minimal Beispiel für das Bluepill gebaut 
und habe das Projekt ausgegraben was ich vor einiger Zeit hier 
getriggert hatte, siehe auch 
Beitrag "USB CDC von Stefan Frings und WS"

Dann habe ich dein kleine Testprogramm verwendet und dies läuft ohne 
irgendwelche Probleme durch, kein einziger hänger.

Ich vermute das mit all den verschiedenen Versionen Chaos entsteht aber 
das wurde ja alles schon einmal aufgeräumt. Im Anhang mal ein Testfile 
für deine Versuche. Lass mich wissen ob es damit Probleme gibt dann 
grabe ich mal weiter. Ich glaube aber das funktioniert ohne Probleme. 
Dank gilt hierfür Niklas.

von Stefan F. (Gast)


Lesenswert?

Für mich sieht die Lage nicht so eindeutig aus, wie ich es gerne hätte. 
Ich hasse solche "Fehler" zutiefst.

Ich habe ja am Donnerstag berichtet, das ich den Fehler nicht 
reproduzieren konnte. Doch da hatte ich das Testprogramm nur wenige 
Minuten laufen lassen. Die Anmerkungen von temp animierten mich jedoch 
dazu nochmal genauer hin zu schauen, was ich heute morgen tat.

Nach nur 5 Minuten hatte ich den ersten Aussetzer. Der nächste ließ 
allerdings satte 4 Stunden auf sich warten. Dann hatte ich wieder einen 
quasi sofort nach nur wenigen Sekunden.

Also muss ich meine vorherige Aussage revidieren, ich kann das Problem 
doch reproduzieren. Und ja, auch bei mir fehlten immer genau 64 Bytes.

Nun habe ich die drei Zeilen Workaround in den Quelltext eingefügt und 
teste seit dem wieder. Das ist nun zwei Stunden her, ohne Aussetzer. Ich 
werde es wohl auch mindestens bis morgen laufen lassen, um Gewissheit zu 
bekommen.

Ich frage mich, ob temp hier auf einen Hardware-Bug gestoßen ist?

Frage an die 3-4 Kollegen, die sich mit USB auskennen: Wenn der µC die 
letzten 64 Zeichen an den PC sendet und sie dort (warum auch immer) 
nicht ankommen, wie funktioniert da der Wiederhol-Mechanismus?

von temp (Gast)


Lesenswert?

Bernd N. schrieb:
> Dann habe ich dein kleine Testprogramm verwendet und dies läuft ohne
> irgendwelche Probleme durch, kein einziger hänger.

Fakt ist eins, der Bug ist da noch drin. Ich habe das gesamte Projekt 
von Stefans Seite so genommen wie es ist. Optimierung O3. Wenn du was 
anderes hast, brauchen wir nicht drüber reden. Und Laufen lassen heisst 
ein paar Stunden und nicht 10s.

Es ist genau so wie Thomas es beschreibt. Werden vom STM genau 64 Byte 
in einem Usb-Endpoint-Paket verschickt und der PC will genau 64 Byte 
lesen steht die Geschichte augenblicklich. Sendet der STM fröhlich 
weiter, wird diese Klippe übersprungen. Verkleiner der STM das Packet 
auf 63 und 1 Byte im nächsten Usb-Endpoint-Paket tritt das Problem nicht 
auf.

Was die Fehlersuche an dieser Stelle erschwert ist die Tatsache, dass im 
STM-Testprogramm alles Byteweise abgehandelt wird.
1
   while (1)
2
      {
3
      char c;
4
      if (UsbGetChar(&c, 10)) // warte max. 10ms
5
        {
6
        UsbSendChar(c, 10); // warte max. 10ms
7
        }
8
      }
Hier wird im UsbSendChar() auch das Triggern des Endpointtransfers 
angestoßen. Somit ist es in Verbindung mit dem PC-Testprogramm völlig 
zufällig, was für Packetgrößen wirklich per USB übertragen werden. Die 
Wahrscheinlichkeit ist sogar ziemlich gering, dass das Device 64Byte am 
Block und noch dazu im letzten Block sendet und der PC genau auf diese 
64 Byte wartet. Hier spielt dann auch die Abhängigkeit von der 
Optimierung eine Rolle. Mit einem angepassten Testprogramm ist das mit 
dem ersten Senden reproduzierbar. Dieser Bug ist schon von der ersten 
W.S. Version drin. Zusätzlich einer der in den Endpoint schreibt, obwohl 
der noch den STAT_TX 0x03 hat. Das hat dann Niklas mit viel Gedöhns und 
Flags und Verlagern von Teilen in den Usercode gefixt. Nicht elegant, 
aber es half.

Ihr könnt das glauben oder nicht, ich habe damit kein Problem. Ich habe 
aber auch keinen Bock für jeden einzelnen noch ein Demoprogramm zu 
schreiben. Es war schon nervig genug den STMCubeMx Kram nur für die 
Spielerein hier zu installieren.

Bernd N. schrieb:
> Dank gilt hierfür Niklas
Niklas hat erst die Vermischung von User- und Interruptcode hier rein 
gebracht. Dafür gibt es von mir keinen Dank.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich frage mich, ob temp hier auf einen Hardware-Bug gestoßen ist?

Nein, das ist Spezifikation USB1.1 lt. Thomas. Wenn ein Endpoint-Packet 
genau 64Byte lang ist, geht der Host davon aus es kommt noch was und 
liefert die Daten noch nicht an das Userprogramm weiter. Also ist mein 
Trick, wenn der Ringbuffer noch genau 64 Byte hat, sende ich nur 62 und 
die nächsten 2 im nächsten Endpointpaket. Damit sind dann alle 
zufrieden.

von Bernd N. (_bn_)


Lesenswert?

temp schrieb:
> Fakt ist eins, der Bug ist da noch drin. Ich habe das gesamte Projekt
> von Stefans Seite so genommen wie es ist

Ich nicht, deswegen habe ich das Angebot gemacht. Probier es aus oder 
lass es, ich teste seit Stunden ohne Aussetzer.

von temp (Gast)


Lesenswert?

Bernd N. schrieb:
> Ich nicht, deswegen habe ich das Angebot gemacht. Probier es aus oder
> lass es, ich teste seit Stunden ohne Aussetzer.

Sorry, du kannst testen soviel wie du willst. Es ist mir auch Wumpe was 
du für Ergenisse erziehlst. Und ich will auch niemandem bekehren. Fakt 
ist, der Code hat diesen Bug, da er die o.g. Besonderheit der Spec nicht 
berücksichtigt. Mir reicht diese Erkenntnis für mich, und nur das ist 
mir wichtig. Ich wüsste auch nicht was mich deine Projekte interessieren 
sollten. Mehr als meine Erkenntnisse und Erfahrungen bringe ich hier 
nicht ein, und wer's nicht hören will, des lässt es halt bleiben. Punkt.

von temp (Gast)


Lesenswert?

Bernd N. schrieb:
> Ich nicht,
Genau das ist das Problem. Es spielen in dieser Konstellation zu viele 
Zufälliglkeiten rein und auch definitiv die Abhängikeit von der 
Optimierungsstufe.
Und nicht weil da falscher Code raus kommt, sondern weil er sich 
zeitlich anders verhält und bei dieser Testkonstellation der Bug nur 
selten auftritt.

Stefan ⛄ F. schrieb:
> Nach nur 5 Minuten hatte ich den ersten Aussetzer. Der nächste ließ
> allerdings satte 4 Stunden auf sich warten. Dann hatte ich wieder einen
> quasi sofort nach nur wenigen Sekunden.

Danke Stefan, das bestätigt, dass ich nicht an geistiger Umnachtung 
leide.

Ich habe vorhin schon geschrieben, dass ein passender Test das sofort 
reproduzieren kann. Ich wüsste nur nicht warum ich hier mit jemanden 
darum streiten sollte. Was das Problem ist habe ich geschildert. Wer es 
nicht glaubt baut sich bitte seine Tests selber oder denkt weiter es ist 
alles ok.
Und ja, viele realen Anwendungen, auch meine, laufen mit dem Bug ohne 
Probleme. Jedenfalls solange nicht jemand auf ein letztes Paket mit 64 
Byte wartet.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Es spielen in dieser Konstellation zu viele
> Zufälliglkeiten rein und auch definitiv die Abhängikeit von der
> Optimierungsstufe.

Ich konnte den Fehler auch mit -O1 reproduzieren.

Mit der Korrektur von temp lief es seit gestern ca 14:00 ohne Stopp 
durch. Selbst wenn sich heraus stellen sollte, dass die Änderung noch 
keine 100% Lösung ist, so macht sie zumindest nichts kaputt.

Ich habe die Downloads auf meine Homepage (unter 
http://stefanfrings.de/stm32/index.html) entsprechend aktualisiert.

von Bernd N. (_bn_)


Lesenswert?

Ich will hier nicht streiten sondern herausfinden was da falsch läuft.

temp schrieb:
> Ich habe vorhin schon geschrieben, dass ein passender Test das sofort
> reproduzieren kann.

Also dann her mit dem Test, kostet dich das Testen nur ne halbe Minute. 
Ich teste es auch gerne selbst.

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Bernd N. schrieb:
> Also dann her mit dem Test

Das hört sich etwas dummdreißt an...

trotzdem in die usb.c am Ende muss eine neue Methode:
1
bool UsbSendCharBlock(const char *pc, int len)
2
{
3
  for (int n=0; n<len; n++)
4
    {
5
  // check space
6
    int i = (txw + 1) & (USB_TXLEN - 1);
7
    if (i == txr)
8
      {
9
        return false;
10
      }
11
12
    // write into the buffer
13
    UsbTxBuf[txw] = pc[n];
14
    txw = i;
15
    }
16
  DisableUsbIRQ();
17
  EpBulkBeginTransmit();
18
  EnableUsbIRQ();
19
  return true;
20
}
Die füllt zuerst den Ringbuffer und triggert danach erst das 
EpBulkBeginTransmit an. Damit landen dann auch bis max 64byte im ersten 
Bulktransfer.

Die main sieht dann so aus:
1
bool UsbSendCharBlock(const char *pc, int len);
2
int main()
3
{
4
  init_clock();
5
  init_io();
6
  UsbSetup();
7
  // Initialize system timer
8
  SysTick_Config(SystemCoreClock/1000);
9
  while (1)
10
    {
11
    char buf[65];
12
    int n=0;
13
    while (n<64)
14
      {
15
      char c;
16
      if (UsbGetChar(&c, 10))
17
        {
18
        buf[n]=c;
19
        n++;
20
        }
21
      }
22
    UsbSendCharBlock(buf, 64);
23
    }
24
}
Mit anderen Worten, ich warte bis ich genau 64 Byte vom Host kriege, und 
sende die dann im Block zurück. Das angepasste PC Testprogramm ist im 
Anhang. Ohne meine Änderung kommt nicht mal der erste Block beim PC 
wieder an.
Im Anhang das frisch von Stefans Seite geladene Projekt mit den o.g. 
Änderungen. Die Zeile 1351 in usb.c ist auskommentiert um den Fehler zu 
zeigen. Wird der Kommentar entfernt funtioniert es.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Selbst wenn sich heraus stellen sollte, dass die Änderung noch
> keine 100% Lösung ist, so macht sie zumindest nichts kaputt.

Mittlerweile weiss ich was die 100% Lösung ist. Nachdem das letzte Paket 
mit 64byte raus ist und der Ringbuffer leer, muss ein weiteres leeres 
Paket an den Endpoint gesendet werden. Das funktioniert in meinem Code 
auch schon. Allerdings basiert der mehr auf der W.S. Version. In der 
Version von Stefan sind die ganzen Änderungen von Niklas drin, da ist es 
etwas schwieriger zu realisieren. Da wir nun die Ursache und Lösung des 
Problems kennen, können sie die Herren über dieser Version dem ja 
annehmen. Oder mit der 2.besten Lösung leben.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Mittlerweile weiss ich was die 100% Lösung ist.

Das du davon überzeugt bist, hast du bereits glaubwürdig rüber gebracht. 
Danke, dass du dich da so tief rein gehängt hast.

Interessant ist, dass der Code nach so vielen (weit über 5) Jahren immer 
noch reproduzierbare Bugs enthält. Selbst der HAL Code scheint nicht 
unproblematisch zu sein und Arduinos mit integriertem USB zicken auch 
herum.

Mich stört noch, dass die USB Schnittstelle sofort ausfällt, wenn ich 
das Programm im Debugger anhalte. Das schränkt den Nutzen des Debuggers 
massiv ein. Doch gerade das bessere (und damals erheblich billigere) 
Debugging war für mich der Hauptgrund, mir die STM32 überhaupt 
anzuschauen.

Was ich daraus für mich lerne ist, dass die externen USB-UART Chips noch 
lange nicht obsolet geworden sind.

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Mich stört noch, dass die USB Schnittstelle sofort ausfällt, wenn ich
> das Programm im Debugger anhalte. Das schränkt den Nutzen des Debuggers
> massiv ein.

Das Problem mit dem Debugger ist, meistens bleiben die nach dem Start in 
der main() stehen. Das kann man sicher anders konfigurieren. Wenn die 
USB Enumerierung einmal durch ist, kann man auf einem Breakpoint stehen 
bleiben ohne dass der USB-Kram ausfällt.
Bei den Bluepill-Boards mache ich immer folgendes. Vor der 
main()-Methode konfiguriere ich den PA12 (der mit dem 1.5k Widerstand) 
als OpenDrain Ausgang und auf LOW. Wenn der Debugger in der main anhält 
wird das USB-Device im PC entfernt. Nach dem USBInit() o.ä. Wird dann 
A12 wieder auf FloatInput gesetzt und ab da erst beginnt die 
Enumeration. Bei dir würde das so aussehen:
1
void SystemInit()
2
{
3
  // GPIOA12 auf OpenDrain und Low setzen
4
  SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);
5
  MODIFY_REG(GPIOA->CRH, GPIO_CRH_CNF12 + GPIO_CRH_MODE12, GPIO_CRH_CNF12_0 + GPIO_CRH_MODE12_1);
6
  WRITE_REG(GPIOA->BRR, GPIO_BRR_BR12);
7
}
8
9
int main()
10
{
11
  init_clock();
12
  init_io();
13
  UsbSetup();
14
15
  // Initialize system timer
16
  SysTick_Config(SystemCoreClock/1000);
17
18
  MODIFY_REG(GPIOA->CRH, GPIO_CRH_CNF12 + GPIO_CRH_MODE12, GPIO_CRH_CNF12_0);

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Wenn die USB Enumerierung einmal durch ist, kann man auf einem
> Breakpoint stehen bleiben ohne dass der USB-Kram ausfällt.

Aber wenn ich das Programm anhalte beantwortet er die SOF Interrupts 
nicht mehr. Das wertet der PC als Disconnect. Oder habe ich da etwas 
übersehen?

von temp (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Aber wenn ich das Programm anhalte beantwortet er die SOF Interrupts
> nicht mehr. Das wertet der PC als Disconnect. Oder habe ich da etwas
> übersehen?

Das Beantworten des SOF macht die Hardware, das hat nichts mit dem 
Interrupt zu tun. Der wird nur zur Information gerufen. Ebenso wie ESOF. 
Probiers doch aus und setze im laufenden Betrieb auf das
1
UsbSendChar(c, 10); // warte max. 10ms
einen Breakpoint. Da hängt sich nichts auf, auch wenn du ein paar 
Sekunden da stehen bleibst. Klar das PC-Programm geht irgendwann in den 
Timeout, aber selbst wenn das passiert kann man es neu starten und der 
USB Stack hängt sich nicht auf.
Kritisch ist bei mir immer nur die Enumeration am Anfang. Wenn da 
zeitlich was klemmt kommt es zu Fehlern. Deshalb der Trick die 
Enumeration nicht gleich beim Reset zu starten.

von Stefan F. (Gast)


Lesenswert?

temp schrieb:
> Da hängt sich nichts auf, auch wenn du ein paar
> Sekunden da stehen bleibst.
> Kritisch ist bei mir immer nur die Enumeration am Anfang.

Hmm, letztes Jahr hatte ich die vielen Trace-Meldungen eingebaut weil 
das Enumerieren nicht klappte.

Das war damals der Part, den ich Debuggen wollte. Darüber sind wir ja 
schon lange hinweg. Ich würde gerne mein Anwendungsprogramm debuggen. 
Habe ich danach gar nicht mehr versucht. Da hatte ich wohl ein Brett 
vorm Kopf.

von Thomas Z. (usbman)


Lesenswert?

Stefan ⛄ F. schrieb:
> Interessant ist, dass der Code nach so vielen (weit über 5) Jahren immer
> noch reproduzierbare Bugs enthält

Bugs lassen sich fast immer finden. Das ist aber auch kein Problem, es 
gibt keinen fehlerfreien Code. Der Code von W.S. war ja ursprünglich für 
eine ganz bestimmte Aufgabe gedacht, und das hat er ja auch gemacht. Im 
Laufe der Zeit sind viele zusätzliche Anforderungen und Wünsche dazu 
gekommen. So ist mir aufgefallen dass die Classrequests nicht arbeiten, 
was aber erst wichtig wird wenn man eine richtige ser. Schnittstelle 
ansprechen will.

Stefan ⛄ F. schrieb:
> Was ich daraus für mich lerne ist, dass die externen USB-UART Chips noch
> lange nicht obsolet geworden sind.

Ja dass ist sicherlich die einfachste Lösung. Wenn man aber sowieso 
einen USB fähigen Controller hat, kann der das gleich miterledigen. Ich 
mache das schon viele Jahre so. Ich gebe aber zu, dass ich bisher noch 
sehr wenig mit ARM gemacht habe. Was ich anfangs nicht erkannt habe ist 
die schlechte Umsetzung von USB bei den STMs und speziell den F103. 
Selbst die pobligen CH552 schaffen es einen internen Connect Widerstand 
auf den Bus zu legen, und bieten DMA von und zum USB core. Da ist z.B 
ein FX2 geradezu übersichtlich.

Ich jedenfalls habe mir fest vorgenommen wenn meine Umsetzung fertig 
ist, das gleiche auch mal auf einem F407 auf dem Discovery Board from 
Scratch zu probieren.

Noch ein Update zu meinem VCP:
Ich hab das Ding hier soweit am laufen, bis zu 3 VCPs sind möglich mehr 
gibt das USB Mem nicht her. Der erste arbeitet wie bisher, die anderen 
gehen auf 2 Comports. Ich arbeite gerade an den ser. Schnittstellen.
Parallel baue ich das gleiche auch für die WCH CH552.

von Stefan F. (Gast)


Lesenswert?

Thomas Z. schrieb:
> Ich jedenfalls habe mir fest vorgenommen wenn meine Umsetzung fertig
> ist, das gleiche auch mal auf einem F407 auf dem Discovery Board from
> Scratch zu probieren.

Über das Ergebnis würden sich bestimmt viele Leute freuen, falls du es 
veröffentlichst. Ich werde die F4 in diesem Leben wohl nicht mehr 
einsetzen, da mir die kleineren schon mehr als ausreichend sind.

von Alex (Gast)


Lesenswert?

ich hatt gestern endlich wieder die Möglichkeit, an dem USB 
weiterzuwerkeln.

Wenn ich euch richtig verstanden habe, betrifft die 64-Byte-Geschichte 
ja den EpBulkIn (µC -> PC).

Der Fehler bei mir (Breakpoint-Test, Posting vom 25.3. ) ist ja beim 
EpBulkOut, der µC empfängt die Daten dann ja garnicht richtig.
Konnte dieses Verhalten schon irgend jemand von euch reproduzieren?

Ich hab die Version von temp vom 28.3. ( mit Zeile 1351 in der usb.c) 
jetzt mal auf einem Problemkandidaten laufen lassen:

Der µC wartet ja, bis 64 chars beisammen sind, und schickt die wieder 
hoch.
Das funktioniert auch, wenn die einzelnen EpBulkOut-Transfers nur wenige 
Zeichen lang sind.
Sobald ich einmal einen Block mit 30 Zeichen runterschicke, ist es 
vorbei.

Da muss noch irgendwas anderes drinstecken, das verhindert dass ein 
EpBulkOut IRQ kommt.

von temp (Gast)


Lesenswert?

Alex schrieb:
> Sobald ich einmal einen Block mit 30 Zeichen runterschicke, ist es
> vorbei.

Ich denke wir können dir hier nicht mehr weiterhelfen. Mehrere Leute 
haben unabhängig von einander den Test so gemacht wie du ihn uns 
beschrieben hast. Dabei wurde ein Problem erkannt und gefixt was schon 
lange im Code geschlummert hat und nur bei bestimmten Konstellationen 
auftritt, die häufig niemals eintreffen. Dazu musste das Testprogramm 
auch noch teilweise stundenlang laufen. Nach meiner Änderung traten 
keine Probleme mehr auf.

Das hat mit deinen Problemen nichts zu tun denke ich. Irgendetwas ist 
bei dir anders. Wenn du willst, kannst du mir ja mal eins von deinen 
sowieso schlechten Modulen zum Testen überlassen.

Hast du die Tests mit dem Testprogramm von mir auch mal gemacht?

von Alex (Gast)


Lesenswert?

hab dein Programm jetzt auch mal kurz drüberlaufen lassen.
Bei einem guten Modul läufts, kommen Ausgaben, scheinen ok zu sein.
Bei einem schlechten stehts, keine Ausgab (nicht eine Zeile).

Ist im Grunde das, was nach meinen Tests auch zu erwarten ist, oder 
nicht?
Dein Testprogramm schickt sofort 64 bytes runter, die kommen unten dann 
nicht an (kein IRQ).

von temp (Gast)


Lesenswert?

Alex schrieb:
> Ist im Grunde das, was nach meinen Tests auch zu erwarten ist, oder
> nicht?
> Dein Testprogramm schickt sofort 64 bytes runter, die kommen unten dann
> nicht an (kein IRQ).

Wie gesagt, ich wüsste nicht wie man dir noch helfen kann. Vor allem 
weil du der einzige seit Jahren mit so einem Problem bist.

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.