Raspberry Pi può eseguire in modo affidabile il bit di un seriale da 9600 baud e esiste un codice di esempio?


29

Mi chiedo quanto sia possibile utilizzare il bitbanging per pilotare un seriale da 9600 baud tramite i pin GPIO sul Raspberry Pi.

Ovviamente, Linux non è una piattaforma terribilmente valida per il bitbanging, poiché esiste un gran numero di driver e altri interrupt che possono bloccare la CPU per lunghi periodi di tempo (1-10 ms). Tuttavia, la situazione è migliorata molto di recente e alcune prelazioni sono ora regolarmente abilitate nei kernel. Sospetto anche che un kernel con patch in tempo reale possa essere facilmente utilizzato su Raspberry Pi e che l'hardware e i driver collegati possano essere selezionati con cura.

Il mio standard di affidabilità è che dovrebbe rimanere entro le normali tolleranze seriali a 9600 baud per la maggior parte del tempo. Al momento non sono sicuro di quanti errori siano tollerabili nella pratica, ma ci sono ritrasmissioni e riconoscimenti nel protocollo, quindi è almeno in qualche modo tollerante.

Quindi, le mie domande sono:

  • Il software userland è in grado di bit-bang 9600 baud in modo affidabile?
  • È necessario un kernel con patch in tempo reale?
  • Quanti errori dovrei aspettarmi in generale?

Inoltre, c'è qualche codice di esempio che fa seriale tramite bit banging GPIO? Conosco Arduino SoftSerial, ma questo è tutto.

Nel caso, per limitare la domanda: questa non è un'interfaccia seriale standard e l'UART di Raspberry Pi è già utilizzato per un altro collegamento seriale. Non desidero risposte che suggeriscano hardware esterno (come Gertboard o Arduino) né risposte che dipendono da UART.


1
+1 Buona domanda. Sarei anche interessato alla risposta a questo. Tuttavia, la questione reliabilitypotrebbe dipendere dall'azione e dalle aspettative.
Jivings,

2
RS-232 richiede tensioni negative, ma questo collegamento seriale non utilizza tensioni RS-232. Non lo so, ma credo che RPi richieda il convertitore standard da TTL a RS-232, come MAX232 o una qualsiasi delle dozzine di scelte. Tuttavia, solo per essere chiari, questo non è rilevante per la mia domanda, volevo solo rispondere.
Nakedible,

4
C'è un secondo UART anche sui pin GPIO 14 e 15. Non è così completo come quello principale
John La Rooy,


1
@Nakedible potresti condividere il tuo lavoro per favore? Ho un problema simile e vorrei vedere come hai fatto un secondo seriale via SPI. grazie MSP

Risposte:


15

Alla fine l'ho risolto, ma in un modo abbastanza poco ortodosso. Ho abbandonato il bit-banging come troppo inaffidabile e ho cercato di trovare altre soluzioni che mi permettessero la stessa cosa senza aggiungere altro hardware. Stavo pensando di scrivere un driver del kernel, che avrebbe innescato un interrupt su GPIO e quindi riconfigurato il pin in SPI e avrei usato SPI per leggere un intero byte di dati, ma poi ho avuto un'idea migliore.

Uso SPI per campionare le linee a 20 volte la velocità di trasmissione. Ignoro del tutto i pin SCLK e SS, collego la linea RX a MISO e la linea TX a MOSI. Questo mi dà una vista simile ad un oscilloscopio (1 bit) nella linea RX e vedere chiaramente i bit che vengono trasmessi nella linea seriale:

00 00 00 00 00 00 
00 00 00 00 01 FF 
FF FF FF FF 00 00 
01 FF FF FF FF FF 
FF FF E0 00 00 00 
00 00 07 FF FF FF 
FF FF 

Da questo, è una semplice questione di codifica capire le posizioni corrette da cui campionare i bit di dati effettivi. Il lato di invio è altrettanto banale, ho solo bisogno di convertire ogni byte in un lungo flusso di bit con il bit iniziale e il bit di stop inclusi.

La ragione per cui funziona meglio del bit-banging è che SPI ha il suo clock che non si blocca con il kernel e che le linee di invio e ricezione SPI hanno un FIFO a 16 byte per il trasferimento che sono anche indipendenti dai blocchi del kernel. Per 9600 baud, sto usando un clock SPI a 250 kHz e questo significa che posso dormire anche per un millisecondo tra il riempimento e lo svuotamento degli FIFO senza errori di trasmissione. Tuttavia, per sbagliare sul sicuro, sto usando 300 µs di sonno. Ho testato brevemente fino a che punto avrei potuto spingerlo e almeno un clock SPI da 2 MHz era ancora utilizzabile, quindi questa soluzione si adatta anche a baud rate più alti.

L'unica parte brutta di questa soluzione è che il driver SPI del kernel non supporta tale trasferimento di bit di streaming. Questo significa che non posso farlo scrivendo il mio modulo del kernel usando il driver SPI del kernel, e non posso nemmeno farlo usando /dev/sdidev0.0 dalla terra dell'utente. Tuttavia, su Raspberry Pi, SPI e altre periferiche sono accessibili direttamente da userland da mmap (): n / dev / mem, ignorando del tutto il controllo del kernel. Non sono terribilmente contento di questo, ma funziona perfettamente e offre l'ulteriore vantaggio che gli errori di segmentazione nell'area utente non possono causare l'arresto anomalo del kernel (a meno che non si verifichino casualmente con le altre periferiche). Per quanto riguarda l'uso della CPU, 300 µs di sleep sembrano darmi circa il 7% di utilizzo costante della CPU, ma il mio codice è molto non ottimale. L'aumento della durata del sonno ovviamente riduce direttamente l'utilizzo della CPU.

Modifica: ho dimenticato di menzionare, ho usato la bella libreria bcm2835 per controllare la SPI da userland, estendendola dove necessario.

Quindi, per riassumere: posso trasmettere e ricevere in modo affidabile su un collegamento seriale da 9600 baud interamente dall'area utente utilizzando direttamente il chip SPI tramite / dev / mem a 250kHz sul Raspberry Pi.


@ Nakedible - Puoi elaborare un po 'o fornire collegamenti sulla parte mmap (). Sto lavorando alla stessa cosa.
Jay K,

Stai usando l'hardware SPI anche per fare la trasmissione?
Ghepardo,

Sì, anche la trasmissione funziona.
Nakedible,

3
Potete per favore dare istruzioni dettagliate su come inviare e ricevere codice e condividere tutti i pacchetti modificati se utilizzate qualcosa che avete patchato voi stessi ... TIA!
valentt,

10

Sembrerebbe che almeno senza le patch in tempo reale (CONFIG_PREEMPT_RT), il Raspberry Pi non possa eseguire il bit-bang affidabile di un seriale da 9600 baud.

Ho usato un semplice tester di latenza che ha configurato in modo ottimale tutte le cose lato Linux (sched_fifo, priorità 99, cpu_dma_latench 0us, mlockall). Ho provato a dormire per 100 µsec (circa 9600 baud) e a controllare i sovraccarichi di latenza su un sistema silenzioso per 2 minuti. I risultati furono:

Min: 12 µsec Media: 24 µsec Max: 282 µsec

Sembrava il risultato comune. Il massimo variava in misurazioni più lente tra 100 µsec e 300 µsec. Ho anche controllato la distribuzione e sembra che la stragrande maggioranza sia nell'intervallo 24 µsec. Ce ne sono solo alcuni che superano i 50 µsec, ma ce ne sono quasi sempre alcuni. A volte ci sono anche latenze enormi, come 4000 µsec, ma queste sono abbastanza rare da essere ignorate, almeno per ora.

Immagino che le latenze massime dovrebbero essere inferiori a 50 µsec per 9600 baud per non ottenere errori e qualsiasi latenza di oltre 100 µsec causa la mancanza di un po 'completamente nella trasmissione o nella ricezione.

Questo è tutto senza nemmeno toccare i pin GPIO. Dal momento che non sono riuscito a ottenere una corsa pulita anche con solo 2 secondi, sembra sicuro dire che senza patch in tempo reale il Raspberry Pi non può battere un collegamento seriale a 9600 baud senza generare errori per un periodo di tempo grave.

Più tardi testerò le patch in tempo reale se avrò tempo.

(Strumento utilizzato: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary )

Aggiornamento: il kernel RPi si blocca all'avvio senza rilevare la scheda SD se compilato con il set di patch CONFIG_PREEMPT_RT. Potrebbe essere una cosa semplice da risolvere, ma vedendo le differenze disordinate nel sorgente RPi, penso di voler aspettare fino a quando non ne sarà più nel kernel mainline.

Quindi, testare questo è troppo difficile e lo sto abbandonando.


0

Non è necessario il bit bang. È possibile impostare un interrupt di terra utente in rx gpio per rilevare la caduta del bit di avvio. quindi impostare un intervallo di tempo per campionare nel mezzo dei bit. Un modulo del kernel che lo fa è fattibile.


Ma questo continua a battere un po '. In effetti è così che di solito fai un po 'di colpi.
Philippos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.