Forum: PC-Programmierung USB-Serial C++ Timing Probleme


von Fabske E. (eksbaf)


Lesenswert?

Hallo Zusammen :)

Ich habe ein C++ Programm geschrieben um einen Sensor unter Linux 
auszulesen. Es handelt sich um den CHR-6dm, der per USB angeschlossen 
wird, aber per serieller Schnittstelle (/dev/ttyUSB0) ausgelesen.
Es handelt sich um einen USB Serial Converter: Future Technology Devices 
International, Ltd FT232 USB-Serial (UART) IC
Ich kann über diese Schnittstelle mit dem CHR-6dm kommunizieren, was 
auch schon sehr gut klappt. Im Prinzip geht es mir nur darum, möglichst 
schnell Daten auszulesen. Dies ist von 20-300Hz möglich:
"The CHR-6dm is factory-configured to broadcast angles and angular rates 
at 200 Hz over a TTL UART at 115200 baud. The serial protocol uses 8 
data bits, 1 stop bit, and no parity."
Der Sensor schickt mir genau 39 Byte die ich lesen möchte.

Ich öffne also eine serielle Verbindung:

  // Seriell Schnittstelle öffnen und konfigurieren
  int fd_seriell = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY | 
O_NONBLOCK);
  int flags = fcntl(fd_seriell, F_GETFL);
  flags = ( O_DIRECT | O_FSYNC | O_RSYNC | O_DSYNC);
  if (fd_seriell == -1) perror("open_port: Unable to open serial port 
");
  else fcntl(fd_seriell, F_SETFL, 0);
  leselaenge = 39;
  setzeOptionen(&fd_seriell);

und konfiguriere sie: 
http://nopaste.immersight.de/?3ad970837b6016ae#JIN32+w5cj4O6EhvYbu8beE6u+2dB//u0T7NkLi+Qig=
Die Zeit zwischen dem Lesen von der Schnittstelle messe ich dabei. Das 
Gerät ist auf 300 Hz eingestellt uns sendet mir damit alle 5,5ms 39 
Byte.
read((*p_fd_seriell),&stream,leselaenge);//Stream lesen

Das Ergebnis ist leider nicht zufriedenstellend. Anstatt alle 5,5ms 
einen Wert auszulesen, ergibt sich dieses komische Muster: 
http://nopaste.immersight.de/?d00eb0eb88bf16d7#Z5esix5wkbu1+993riyPpYDuYtWa6m5Bxk8FEGKV60Y=

Als hässliche Lösung habe ich das nun so gemacht. Vor dem Read setze ich 
den Thread einfach 3ms schlafen:
boost::this_thread::sleep(boost::posix_time::microseconds(3000));
Dann ergibt sich ein regelmäßiges Muster wie ich es gerne hätte (der 
Beweis dass es geht): 
http://nopaste.immersight.de/?95e44e07fbf177f3#BmXWN2Lj2QGzd1B9NeObSuUPIfUp4YRjUNiZMxT3AHQ=

Ich frage mich warum der read-Aufruf nicht einfach wartet bis wieder 39 
Byte vorhanden sind. Wie kann denn in 3 mal nacheinander in 0.05ms etwas 
ausgelesen werden?

Vielen Dank schonmal im Voraus! :)

von Peter II (Gast)


Lesenswert?

warum mit O_NONBLOCK?

ich würde es blockierend in einem Thread mit read machen.

Wo sieht man denn den code vom auslesen?

von Rolf M. (rmagnus)


Lesenswert?

Durch O_NONBLOCK kehrt der read-Aufruf immer sofort zurück, unabhängig 
davon, ob was da ist und wieviel.

Fabske Eksbaf schrieb:
> int flags = fcntl(fd_seriell, F_GETFL);
>   flags = ( O_DIRECT | O_FSYNC | O_RSYNC | O_DSYNC);

Es ist wenig sinnig, die Flags zu lesen und dann den gelesenen Wert zu 
verwerfen und komplett zu überschreiben. Da sollte ein |= verwendet 
werden, sonst werden einige der schon gesetzten Flags mit dieser 
Operation wieder gelöscht, unter anderem z.B. das oben gesetzte 
O_NONBLOCK.
Und O_DIRECT ist generell eine etwas dubiose Option. Ich denke 
allerdings nicht, daß die bei Schnittstellen überhaupt eine Wirkung hat. 
Die ist eher dafür gedacht, beim Zugriff auf Dateien den 
Festplatten-Cache zu umgehen.
Ähnliches gilt für diese *_SYNC-Flags.

von Fabske E. (eksbaf)


Lesenswert?

Aha, jemand liest also meinen Quellcode! ;) Genau Rolf, weil wenn ich 
die flags einkommentiere liest er mir gar nix mehr aus :( nur noch -1
(Hab nun die Ausgabe um eine Angabe der gelesenen Byte erweitert):
http://nopaste.immersight.de/?686db1250afb625e#6NWiaMZWAFtZIGjmx4e95II0POgXguego7ELLHNrB+A=

Und das liegt am O_NDELAY und O_NONBLOCK. Hab das nun rausgeworfen. Ich 
hatte es nur alles reingemacht um damit zu experimentieren. Natürlich 
will ich eigentlich einen blockierenden Aufruf haben der 4 MilliSekunden 
blockiert (sollte) und mir dadurch einen super Takt liefert. (Diese Kode 
läuft in einem eigenen Thread!).
Es ergibt sich nun das Bild vom Anfang, das Lesen dauert einfach immer 
unterschiedlich lange:
http://nopaste.immersight.de/?5a40863665485dd0#1z84uxEzXxHnjDgX6ImBSpSaCAOLHF/BwCyH4vg5v5Q=

von Uwe (Gast)


Lesenswert?

Tja wieder jemand der gemerkt hat das USB nicht wirklich echtzeitfähig 
ist.
Echtzeitfähig bedeutet : die Zeit einer Bestimmten Operation ist 
deterministisch (Berechenbar bzw. Abschätzbar). Dies ist bei USB nicht 
der Fall. Da sind zuviele Puffer und FIFOs und Treiber, Caches, 
Betriebsystemeigenarten usw. dazwischen. Du kannst das Verhalten jedoch 
optimieren:

1. Stell im Gerätemanager unter Einstellungen unter Erweitert beim FTDI 
Device die Puffer auf 64 Bytes und die Wartezeit auf 1ms.

2. Spendier dem Ding einen eigenen USB Controller an dem kein anderes 
Gerät hängt also nicht nur einen anderen USB Port, Denn intern ist 
zumeist nur ein USB Controller da, der die 480MBit mit einem internen 
HUB auf die ganzen onboard Ports aufteilt (so kann es nicht zu 
kappeleien zwischen Devices kommen).

3. Versuch dem USB Service Prozess oder was auch immer mehr Priorität zu 
geben
4. Versuch das System sowenig wie möglich mit anderem Krempel zu 
belaßten.

Ansonsten nimm nen Echtzeitbetreibstystem und eine echte RS232

von Christian R. (supachris)


Lesenswert?

Naja, da Windows an sich erst mal gar nicht echtzeitfähig ist, ist es in 
dem Fall auch egal, was USB macht. USB ist halt auch gar nicht dafür 
konzipiert. Umgekehrt hilft aber auch ein Echtzeit OS mit USB da wenig.

von Rolf M. (rmagnus)


Lesenswert?

Christian R. schrieb:
> Naja, da Windows an sich erst mal gar nicht echtzeitfähig ist, ist es in
> dem Fall auch egal, was USB macht.

Da es allerdings gar nicht um Windows geht, ist auch egal, ob dieses 
echtzeitfähig ist.

> USB ist halt auch gar nicht dafür konzipiert.

Das ist für sehr vieles nicht konzipiert, wofür es heute eingesetzt 
wird.

von Christian R. (supachris)


Lesenswert?

Rolf Magnus schrieb:
> Da es allerdings gar nicht um Windows geht, ist auch egal, ob dieses
> echtzeitfähig ist.

Hach, Tatsache. Mea culpa. Naja, ändert aber nichts am Sachverhalt. Auch 
ein Standard-Linux ist nicht echtzeitfähig.

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.