Gli schemi di richiesta/risposta tendono ad essere inefficienti e si presentano rapidamente sulla porta seriale. Se sei interessato al throughtput, guarda il protocollo con finestra, come il protocollo di invio file kermit.
Ora, se vuoi attenerti al tuo protocollo e ridurre la latenza, select, poll, read ti daranno all'incirca la stessa latenza, perché come ha indicato Andy Ross, la vera latenza è nella gestione del FIFO hardware.
Se sei fortunato, puoi modificare il comportamento del driver senza patch, ma devi comunque guardare il codice del driver. Tuttavia, il fatto che l'ARM gestisca una frequenza di interruzione di 10 kHz non sarà certamente positivo per le prestazioni complessive del sistema...
Un'altra opzione è riempire il pacchetto in modo da raggiungere ogni volta la soglia FIFO. Confermerà anche se si tratta o meno di un problema di soglia FIFO.
10 msec @ 115200 sono sufficienti per trasmettere 100 byte (supponendo 8N1), quindi quello che stai vedendo è probabilmente dovuto al low_latency
flag non è impostato. Prova
setserial /dev/<tty_name> low_latency
Imposterà il flag low_latency, che viene utilizzato dal kernel quando si spostano i dati nel livello tty:
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);
}
Il schedule_work
call potrebbe essere responsabile della latenza di 10 msec che osservi.
Le porte seriali su Linux sono "avvolte" in costrutti terminali in stile unix, che ti colpiscono con 1 tick lag, ovvero 10 ms. Prova se stty -F /dev/ttySx raw low_latency
aiuta, ma nessuna garanzia.
Su un PC, puoi diventare hardcore e parlare direttamente con le porte seriali standard, problema setserial /dev/ttySx uart none
per separare il driver linux dalla porta seriale hw e controllare la porta tramite inb/outb
ai registri portuali. L'ho provato, funziona alla grande.
Lo svantaggio è che non ricevi interruzioni quando arrivano i dati e devi eseguire il polling del registro. spesso.
Dovresti essere in grado di fare lo stesso sul lato del dispositivo del braccio, potrebbe essere molto più difficile su una porta seriale esotica hw.
Dopo aver parlato con altri ingegneri dell'argomento, sono giunto alla conclusione che questo problema non è risolvibile nello spazio utente. Dal momento che dobbiamo attraversare il ponte verso la terra del kernel, abbiamo in programma di implementare un modulo del kernel che comunichi il nostro protocollo e ci dia latenze <1ms.
--- modifica ---
Si scopre che mi sbagliavo completamente. Tutto ciò che era necessario era aumentare la frequenza di tick del kernel. I 100 tick predefiniti hanno aggiunto il ritardo di 10 ms. 1000Hz e un bel valore negativo per il processo seriale mi danno il comportamento temporale che volevo raggiungere.
Ecco cosa setserial
fa per impostare una bassa latenza su un descrittore di file di una porta:
ioctl(fd, TIOCGSERIAL, &serial);
serial.flags |= ASYNC_LOW_LATENCY;
ioctl(fd, TIOCSSERIAL, &serial);