Serielle Kommunikation mit niedriger Latenz unter Linux

8

Ich implementiere ein Protokoll über serielle Ports unter Linux. Das Protokoll basiert auf einem Anforderungsantwortschema, so dass der Durchsatz durch die Zeit begrenzt ist, die benötigt wird, um ein Paket an ein Gerät zu senden und eine Antwort zu erhalten. Die Geräte sind meist armbasiert und laufen unter Linux & gt; = 3.0. Ich habe Probleme, die Umlaufzeit unter 10ms zu reduzieren (115200 Baud, 8 Datenbit, keine Parität, 7 Byte pro Nachricht).

Welche I / O-Schnittstellen bieten mir die geringste Latenzzeit: Auswählen, Abfragen, E-Mail oder Polling von Hand mit ioctl? Beeinflusst blockierendes oder nicht blockierendes IO die Latenz?

Ich habe versucht, das low_latency-Flag mit setserial zu setzen. Aber es schien, als hätte es keine Wirkung.

Gibt es noch andere Dinge, die ich versuchen kann, die Latenz zu reduzieren? Da ich alle Geräte kontrolliere, wäre es sogar möglich, den Kernel zu patchen, aber es ist nicht zu bevorzugen.

---- Bearbeiten ----

Der serielle Controller verwendet einen 16550A.

    
JustMaximumPower 29.10.2012, 16:53
quelle

7 Antworten

5

Nachdem ich mit einigen anderen Ingenieuren über das Thema gesprochen hatte, kam ich zu dem Schluss, dass dieses Problem im Benutzerraum nicht lösbar ist. Da wir die Brücke ins Kernel-Land überqueren müssen, planen wir, ein Kernel-Modul zu implementieren, das unser Protokoll spricht und uns Latenzen & lt; 1ms.

--- bearbeiten ---

Stellt sich heraus, dass ich völlig falsch lag. Alles was nötig war, war die Kerneltickrate zu erhöhen. Die standardmäßigen 100 Ticks haben die Verzögerung von 10 ms hinzugefügt. 1000Hz und ein negativer Wert für den seriellen Prozess gibt mir das Zeitverhalten, das ich erreichen wollte.

    
JustMaximumPower 15.11.2012, 10:31
quelle
9

Anforderungs- / Antwortschemata sind in der Regel ineffizient und werden am seriellen Port schnell angezeigt. Wenn Sie sich für Throughput interessieren, schauen Sie sich das gefensterte Protokoll an, wie das Protokoll zum Senden von Kermit-Dateien.

Wenn Sie jetzt bei Ihrem Protokoll bleiben und die Latenz reduzieren möchten, wählen Sie, pollen, lesen, das gibt Ihnen ungefähr die gleiche Latenz, denn wie Andy Ross anmerkte, liegt die tatsächliche Latenz in der Hardware-Fifo-Handhabung.

Wenn Sie Glück haben, können Sie das Treiberverhalten optimieren, ohne zu patchen, aber Sie müssen sich trotzdem den Treibercode ansehen. Wenn der ARM jedoch eine Interrupt-Rate von 10 kHz verarbeitet, wird dies sicherlich nicht gut für die Gesamtleistung des Systems sein ...

Eine weitere Möglichkeit besteht darin, Ihr Paket so aufzufüllen, dass Sie jedes Mal die Fifo-Schwelle erreichen. Es wird auch bestätigt, ob es ein FIFO-Schwellenwertproblem ist oder nicht.

10 ms @ 115200 reicht aus, um 100 Bytes zu übertragen (angenommen 8N1). Was Sie also sehen, liegt wahrscheinlich daran, dass das Flag low_latency nicht gesetzt ist. Probieren Sie

aus %Vor%

Es wird das Flag low_latency gesetzt, das beim Verschieben von Daten in der tty-Ebene vom Kernel verwendet wird:

%Vor%

Der Aufruf schedule_work ist möglicherweise für die 10-ms-Latenz verantwortlich, die Sie beobachten.

    
shodanex 30.10.2012 09:51
quelle
5

Serielle Ports auf Linux werden in Unix-artige Terminalkonstrukte "eingepackt", was Sie mit 1 Tick-Verzögerung, d. h. 10 ms, trifft. Probieren Sie es aus, wenn stty -F /dev/ttySx raw low_latency hilft, aber keine Garantie.

Auf einem PC können Sie hardcore gehen und direkt mit seriellen Standard-Ports sprechen, setserial /dev/ttySx uart none ausgeben, um den Linux-Treiber vom seriellen Port hw zu lösen und den Port über inb/outb an die Port-Register steuern. Ich habe das ausprobiert, es funktioniert super.

Der Nachteil ist, dass Sie keine Interrupts erhalten, wenn Daten ankommen und Sie das Register abfragen müssen. oft.

Sie sollten in der Lage sein, dies auf der Seite des Armgerätes zu tun, kann viel schwieriger auf exotischen seriellen Port hw sein.

    
Dima Tisnek 22.01.2013 16:21
quelle
2

Keiner dieser Systemaufrufe wirkt sich auf die Latenz aus. Wenn Sie ein Byte so schnell wie möglich aus dem Benutzerbereich lesen und schreiben wollen, werden Sie es wirklich nicht besser machen als ein einfaches read()/write() -Paar. Versuchen Sie, den seriellen Datenstrom durch einen Socket aus einem anderen Userspace-Prozess zu ersetzen, und überprüfen Sie, ob sich die Latenzzeiten verbessern. Wenn dies nicht der Fall ist, sind Ihre Probleme CPU-Geschwindigkeit und Hardware-Einschränkungen.

Sind Sie sicher, dass Ihre Hardware das überhaupt kann? Es ist nicht ungewöhnlich, UARTs mit einem Buffer-Design zu finden, das viele Bytes Latenz bringt.

    
Andy Ross 29.10.2012 17:54
quelle
0

Bei diesen Zeilengeschwindigkeiten sollten Sie keine so großen Latenzen sehen, unabhängig davon, wie Sie die Bereitschaft prüfen.

Sie müssen sicherstellen, dass der serielle Port im Raw-Modus ist (also "noncanonical reads") und dass VMIN und VTIME korrekt eingestellt sind. Sie möchten sicherstellen, dass VTIME Null ist, so dass ein Inter-Character-Timer nie startet. Ich würde wahrscheinlich beginnen mit VMIN auf 1 setzen und tune von dort.

Der Syscall-Overhead ist nichts im Vergleich zu der Zeit auf der Leitung, so dass select () vs. poll () usw. wahrscheinlich keinen Unterschied macht.

    
janm 30.10.2012 10:15
quelle
0

Mit setserial wird eine niedrige Latenz für einen Dateideskriptor eines Ports festgelegt:

%Vor%     
Kuba Ober 19.04.2017 13:00
quelle
0

Kurz gesagt: Verwenden Sie einen USB-Adapter und ASYNC_LOW_LATENCY.

Ich habe einen FT232RL-basierten USB-Adapter bei Modbus mit 115,2 kB verwendet. Ich bekomme ca. 5 Transaktionen (bis 4 Geräte) in ca. 20 mS mit ASYNC_LOW_LATENCY. Dies beinhaltet zwei Transaktionen zu einem Slow-Poke-Gerät (4 ms Antwortzeit). Ohne ASYNC_LOW_LATENCY beträgt die Gesamtzeit ca. 60 ms. Bei FTDI-USB-Adaptern setzt ASYNC_LOW_LATENCY den Inter-Character-Timer auf dem Chip selbst auf 1 ms (anstelle der Standard 16 ms). Ich verwende derzeit einen selbstgebrauten USB-Adapter und kann die Latenz für den Adapter selbst auf den von mir gewünschten Wert einstellen. Bei einer Einstellung von 200 μS wird ein weiterer mS-Wert von 20 ms eingestellt.

    
Renate 04.09.2017 12:54
quelle