Anforderungs-/Antwortschemata sind in der Regel ineffizient und werden schnell an der seriellen Schnittstelle angezeigt. Wenn Sie am Durchsatz interessiert sind, schauen Sie sich das Fensterprotokoll an, wie das Kermit-Protokoll zum Senden von Dateien.
Wenn Sie nun an Ihrem Protokoll festhalten und die Latenz reduzieren möchten, erhalten Sie mit select, poll, read ungefähr die gleiche Latenz, da, wie Andy Ross angedeutet hat, die tatsächliche Latenz in der Hardware-FIFO-Verarbeitung liegt.
Wenn Sie Glück haben, können Sie das Treiberverhalten ohne Patchen optimieren, aber Sie müssen sich immer noch den Treibercode ansehen. Wenn der ARM jedoch eine Unterbrechungsrate von 10 kHz handhabt, ist dies sicherlich nicht gut für die Gesamtsystemleistung ...
Eine weitere Option besteht darin, Ihr Paket so aufzufüllen, dass Sie jedes Mal den FIFO-Schwellenwert erreichen. Es wird auch bestätigen, ob es sich um ein FIFO-Schwellenwertproblem handelt oder nicht.
10 ms @ 115200 reichen aus, um 100 Bytes zu übertragen (unter der Annahme von 8N1), was Sie also sehen, liegt wahrscheinlich am low_latency
Flag ist nicht gesetzt. Versuchen Sie es
setserial /dev/<tty_name> low_latency
Es setzt das low_latency-Flag, das vom Kernel verwendet wird, wenn Daten in der tty-Schicht nach oben verschoben werden:
void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
spin_unlock_irqrestore(&tty->buf.lock, flags);
if (tty->low_latency)
flush_to_ldisc(&tty->buf.work);
else
schedule_work(&tty->buf.work);
}
Die schedule_work
Der Anruf könnte für die beobachtete Latenz von 10 ms verantwortlich sein.
Serielle Ports unter Linux werden in Terminalkonstrukte im Unix-Stil "verpackt", was Sie mit einer Verzögerung von 1 Tick, dh 10 ms, trifft. Versuchen Sie es mit stty -F /dev/ttySx raw low_latency
hilft, aber keine Garantien.
Auf einem PC können Sie Hardcore spielen und direkt mit seriellen Standardanschlüssen sprechen, geben Sie setserial /dev/ttySx uart none
aus um den Linux-Treiber vom seriellen Port hw zu lösen und den Port über inb/outb
zu steuern Register zu portieren. Das habe ich 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, dasselbe auf der Seite des Armgeräts zu tun, möglicherweise ist dies bei exotischen seriellen Port-HW viel schwieriger.
Nachdem ich mit einigen weiteren Ingenieuren über das Thema gesprochen hatte, kam ich zu dem Schluss, dass dieses Problem nicht im Benutzerraum lösbar ist. Da wir die Brücke ins Kernel-Land überqueren müssen, planen wir die Implementierung eines Kernel-Moduls, das unser Protokoll spricht und uns Latenzen <1 ms gibt.
--- Bearbeiten ---
Es stellte sich heraus, dass ich völlig falsch lag. Dazu musste lediglich die Tickrate des Kernels erhöht werden. Die standardmäßigen 100 Ticks fügten die Verzögerung von 10 ms hinzu. 1000Hz und ein negativer netter Wert für den seriellen Prozess gibt mir das Zeitverhalten, das ich erreichen wollte.
Hier ist was setserial
tut, um eine niedrige Latenz für einen Dateideskriptor eines Ports festzulegen:
ioctl(fd, TIOCGSERIAL, &serial);
serial.flags |= ASYNC_LOW_LATENCY;
ioctl(fd, TIOCSSERIAL, &serial);