Ich übertrage von einem STM32F4 per FTDI USB-Kabel Daten an den PC.
Diese werden am PC „sortiert“ und als Kurve ausgegeben. Mir ist aber die
Anzeige auf dem PC zu langsam. Vielleicht könnt ihr mir helfen wie man
da üblicher Weise vorgeht. Hier mal eine kurze Beschreibung wie ich es
gelöst haben.
Die es werden vom STM32F4 Datenblöcke von 18 Byte Größe mit folgendem
Aufbau verschickt:
BYTE 1 : Anfang Erkennung „0xff“
BYTE 2: Größe+“Art“ der Daten
BYTE 3-14: Daten
BYTE 15-18: CRC32 Prüfsumme
Am PC gibt es 4 Threads:
Thread 1: Mainthread für die Oberfläche
Thread 2: FTDI empfangen per “FTD2XX.dll”
Thread 3: Datenpakete raus sortieren und CRC32 prüfen
Thread 4: Daten verarbeiten und an Mainthread für Anzeige übergeben
Am PC programmiere ich mit VS2008 C++/CLI. Mein PC ist schnell genug.
VG Deepdiver99
Die Baudrate ist auf 3.000.000 eingestellt.
Sobald vom STM32F4 mehr Datenblöcke geschickt werden fängt die Ausgabe
der Kurve auf dem Bildschirm an zu stocken. Teilweise dauert es einige
Sekunden bis es weiter geht. Dann aber alles auf einmal. Also am Empfang
liegt es nicht. Meine CPU ist super schnell und 16GB RAM sollten auch
reichen. Vermute mal das die Verarbeitung zwischen dem empfangen und der
Ausgabe nicht effektiv ist. Wie wird sowas sonst in der Praxis gelöst?
Bei anderen Systemen werden doch teilweise viel mehr Daten verarbeitet.
Deepdiver99 schrieb:> Vermute mal das die Verarbeitung zwischen dem empfangen und der> Ausgabe nicht effektiv ist.
Ich vermute, daß sich die Threads gegenseitig behindern, so wie du das
beschreibst. Der Empfangsthread muß die Daten in einen Buffer schreiben
können und parallel dazu muß ein anderer Thread unabhängig davon die
Daten aus dem Puffer holen, sie verarbeiten und dann darstellen. Und
wenn du sagst, daß während des Datenempfanges keine Aktualisierung der
Darstellung erfolgt, dann wird dein Empfangsthread die anderen Threads
blockieren.
Deepdiver99 schrieb:> Sobald vom STM32F4 mehr Datenblöcke geschickt werden fängt die Ausgabe> der Kurve auf dem Bildschirm an zu stocken. Teilweise dauert es einige> Sekunden bis es weiter geht.
Hatte ich auch mal, als ich die Bytes von der Seriellen byteweise
abgeholt habe (also zuerst auf EV_RXCHAR gewartet und dann aber immer
nur Länge 1 im ReadFile()-Aufruf. Das ging dann mit manchen
rs232-Adaptern immer noch problemlos (z.B. ein Arduino-Uno ging
problemlos, sogar mit hohem Durchsatz) aber bei nem FTDI-basierten
Adapter begann es plötzlich im Sekundentakt zu stottern sobald das
Datenvolumen größer wurde, er hing dann jedesmal im
WaitForSingleObject() fest obwohl längst neue Daten hätten da sein
sollen, kurz danach kamen sie dann alle auf einmal, bis zum Nächsten
Hänger.
Dann baute ich das um, so daß jedesmal soviele Daten gelesen werden wie
da sind, lese sie in meinen eigenen Puffer und entnehme sie später von
dort byteweise so wie ich sie brauche. Seitdem erreiche ich den vollen
Datendurchsatz ohne Probleme.
Also Kurzfassung: Niemals die Bytes einzeln mit ReadFile() lesen, immer
in großen Blöcken soviel lesen bis nichts mehr kommt, erst dann erneut
warten lassen.
Hallo,
wenn du Daten darstellst z.B. mit 1024 x 768 Pixeln, dann ist ein
Bildschirm mit 1k x 16 bit vollgeschrieben, und da weder dein Auge noch
dein Verstand mehr als 10 Bilder pro Sekunde erfassen kann, ist dafür
eine Datenrate von 20 kB / s ausreichend, warum also überträgst du 300
kB / s?
Es kann durchaus sein, dass die Empfangsinterrupts deine CPU-Leistung
auffressen, besonders wenn der Treiber schlecht programmiert ist und
z.B. für jedes Zeichen einen Interrupt auslöst. Ich halte es daher für
möglich, dass die Sache mit niedrigerer Datenrate besser funktioniert,
Baudraten sind nicht nach dem Prinzip viel hilft viel festzulegen,
sondern das Gesamtsystem sollte ausgewogen sein. Jedenfalls kannst du
das mal probieren. Am besten wäre es natürlich, wenn du zuerst mal
messen würdest, welcher Thread wieviel CPU-Zeit verbraucht.
Du kannst natürlich auch mit Prioritäten spielen, aber das verdeckt eher
ein bestehendes Problem als dass es gelöst wird.
Georg
10 fps könnten u.U. ruckelig wirken, mehr als 30 sind aber für diesen
Zweck Rechenzeit- und Energieverschwendung. Um eine Begrenzung
umzusetzen, muss man natürlich die Ausgabe vom Einlesen der Daten
komplett entkoppeln und auch den Bildschirminhalt korrekt
synchronisieren. Eine einfache Strategie wäre, die neuesten Daten
anzuzeigen, die vorhanden sind (falls zwischen den Frames nicht genug
reinkommt, um das Bild zu füllen, muss ein Teil der "alten" Daten
verwendet werden, so dass das Bild scrollt). Alternativ könnte man alle
Daten zeigen, ohne etwas zu überspringen; dann hinkt die Anzeige immer
weiter hinterher. Irgendwann ist dann allerdings Schluss, weil der
Buffer nicht beliebig groß sein kann.
> "Diese werden am PC „sortiert“ und als Kurve ausgegeben."
Bei einer hohen Datenrate muss man für eine sinnvolle Anzeige u.U.
"richtig" synchronisieren - ähnlich wie bei einem Oszilloskop - was das
Ganze natürlich komplexer macht.
Albert schrieb:> Alfred war knapp daneben :)>> Beitrag "Projekt: Virtuelle Instrumente an serielle Schnittstelle">> Neueste Version 0.48e
Danke für den Link, Albert! Sieht sehr interessant aus, den Thread muß
ich mir mal in Ruhe zu Gemüte führen...
Beim anzeigen kann man auch noch Fehler machen. zB
-mach pixel hin -refresh -mach pixel hin -refresh -mach pixel hin
-refresh -mach pixel hin -refresh
..
oder
alloziere neues pixel, alles malen, nochmals ein pixel, alles malen,
nochmals ein pixel, alles malen
Mach dir Gedanken wie die Daten zu so einem Bild gespeichert, so ein
Bild aufgebaut und ge-refresht wird.
Deepdiver99 schrieb:> Teilweise dauert es einige> Sekunden bis es weiter geht. Dann aber alles auf einmal.
Das deutet nicht wie die anderen Schreiber hier irreführenderweise
vermuten wollen auf einen CPU-Engpass hin, das deutet eher deutlich auf
ein Synchronisationsproblem und verpasste EV_RXCHAR Events, also das was
ich bereits weiter oben schrieb. Wie hoch ist Deine CPU-Auslastung
(damit ist ruckzuck geklärt wo man weitersuchen muss).
Was sagt der Profiler, wo wird die meiste Zeit verbracht? Könnte man
vielleicht mal systematisch vorgehen?
Wenn Du keinen Sampling-Profiler hast und zu faul bist Dir endlich einen
zu installieren dann geht auch poor-man's profiling: Drück im Debugger
auf Pause, schau in den Callstack und schreib Dir auf in welcher
Funktion (und wenn Du es ganz genau haben willst in welcher Zeile) jeder
Thread gerade war. Mach das 10 bis 100 mal, mach ne Strichliste und Du
weißt wo welcher Prozentsatz der Zeit verbraten wird.