Come decodificare in modo efficiente il segnale seriale non standard


11

Sono un membro universitario di un gruppo di ricerca che lavora su un progetto che coinvolge un ASIC a trasmissione RF e il suo ricevitore wireless che dovrebbe infine inviare dati a un PC.

Il ricevitore emette un segnale seriale veloce , continuo, asincrono, non standard (cioè non SPI, I2C, UART, ecc.), Quindi il mio compito è quello di scrivere un software di microcontrollore per interfacciare il ricevitore al computer. Attualmente il mio approccio è quello di utilizzare gli interrupt trigger-edge per posizionare i dati in un buffer circolare ed eseguire l'intero processo di decodifica bit per bit nel loop principale. Il microcontrollore deve trasmettere contemporaneamente questi dati tramite USB (porta COM virtuale) al computer.

Ecco un problema che sto riscontrando e uno che sto anticipando:

  1. Non riesco a elaborare i dati bufferizzati abbastanza velocemente anche con il mio processore ARM Cortex M3 da 72 MHz piuttosto potente. Il bitrate è di 400 Kbps (2,5 us / bit). Per riferimento che lascia solo 180 cicli per bit (inclusa la decodifica E ISR, che ha circa 30 cicli di sovraccarico!). L'MCU deve anche gestire molte altre attività per le quali esegue il polling nel loop principale.

  2. Anche il driver della porta COM virtuale USB è basato su interrupt. Questo mi rende quasi certo che il driver alla fine avrà il processore interrotto per così tanto tempo che manca la finestra di 2,5 microsecondi (180 cicli) in cui un bit può essere trasmesso. Non sono sicuro di come i conflitti di interruzione / razze come questa siano normalmente risolti.

Quindi la domanda è semplicemente: cosa si potrebbe fare per risolvere questi problemi o non è affatto l'approccio giusto? Sono disposto a prendere in considerazione anche approcci meno incentrati sul software. Ad esempio, l'utilizzo di un chip USB dedicato con una sorta di macchina a stati hardware per la decodifica, ma questo è un territorio sconosciuto.


Devo dire che è raro che vedo che molti suggerimenti che mi piacciono hanno una risposta così rapida, parlano bene alla tua domanda. Sarei interessato a saperne di più sui burst dei dati. Sono frastagliati, improvvisamente a piena velocità e quindi periodi di dati bassi o è plausibile che passeresti un periodo prolungato con dati continui?
Kortuk,

Finché l'ASIC è alimentato, invia un flusso continuo di dati. Non è affatto scoppiato. È un'applicazione di rilevamento medico in tempo reale con una lettura del computer. Hai mai visto un elettrocardiogramma?
Keegan Jay,

Così tante grandi risposte qui. Ho visto una chiara divisione tra soluzioni che comportano modifiche agli interrupt e soluzioni che coinvolgono hardware / logica digitale dedicata. Cose come FPGA e Verilog sono familiari, ma non ancora sperimentate, quindi ciò significa che devono essere salvate a lungo termine. Nel breve termine @rocketmagnets va bene il metodo meno pesante di interruzione. Mi piace l'eleganza di dedicare compiti mentali alla logica digitale e salvare l'ARM per un vero calcolo. In futuro la potenza di ARM verrà utilizzata per l'analisi e il filtraggio dei dati seriali wireless.
Keegan Jay,

Il segnale è sincrono o asincrono?
segna il

Asincrono. 4 bit di avvio, 10 bit di dati, 2 bit di arresto. A causa della natura dell'ASIC che sta trasmettendo, i tempi HI e LO variano notevolmente da chip a chip. Ho già scritto un algoritmo per dedurre il baud rate.
Keegan Jay,

Risposte:


5

Un'altra risposta: smettere di usare gli interrupt.

Le persone saltano per usare gli interrupt troppo facilmente. Personalmente, li uso raramente perché in realtà perdono molto tempo, come stai scoprendo.

Spesso è possibile scrivere un ciclo principale che esegue il polling di tutto così rapidamente che è la latenza è all'interno delle specifiche e si perde molto poco tempo.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

Potrebbero esserci alcune cose nel circuito che accadono molto più spesso di altre. Forse i bit in arrivo, ad esempio, nel qual caso, aggiungono più di quei test, in modo che più del processore sia dedicato a quel compito.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

Potrebbero esserci degli eventi per i quali la latenza di questo approccio è troppo elevata. Ad esempio, potresti aver bisogno di un evento a tempo molto preciso. Nel qual caso, l'evento deve essere interrotto e avere tutto il resto nel loop.


Mi piace la tua risposta più di qualsiasi altra persona di Rocketmagnet. Invece di più adrware, hardware più veloce, più di qualcos'altro, Rocketmagnet, suggerisce: fai di meno, meglio, più semplicemente.

Ok, ho visto molti casi in cui gli interrupt rendono la soluzione molto migliore. Fanno grandi cose, consentono codice ben strutturato, bassa latenza e molti altri vantaggi, ma devo essere d'accordo con te qui. Sembra che il processo sia così intenso 1 controller potrebbe dover dedicare tutta la sua attenzione alla gestione del flusso seriale. Il front-end digitale mi sembra ideale, ma molte volte hai dei micro e nessun FPGA in giro quando è un progetto scolastico, probabilmente dedicherei un micro a gestirlo prima per me e proverei a inserirmi in un FPGA in seguito per sostituirlo con costo.
Kortuk,

Questa è probabilmente la soluzione che seguirò a breve termine. Speravo di evitarlo perché implica riscrivere un bel po 'dei driver seriali esistenti, ma è una soluzione elegante che rientra nelle mie capacità in un breve lasso di tempo.
Keegan Jay,

1
@JayKeegan - Sì, è probabilmente il percorso più veloce per una soluzione. PSoC e FPGA potrebbero essere l'approccio per il prossimo progetto.
Rocketmagnet,

6

È possibile utilizzare un FPGA anziché un microcontrollore per decodificare e bufferare il flusso di dati wireless. Quindi utilizzare il processore ARM per svuotare i buffer FPGA (ad esempio utilizzando un'interfaccia SPI) e inviare il contenuto dalla porta di comunicazione USB. Funziona, ma un FPGA dovrebbe essere in grado di tenere il passo facilmente fintanto che sei in grado di ripararlo abbastanza spesso da garantire che i suoi buffer hardware non si sovraccarichino (o se puoi gestire i dati rilasciati a un livello superiore del protocollo ).


Questa potrebbe essere un'ottima soluzione a lungo termine. Speravo di aver ricevuto molte soluzioni logiche / hardware digitali oltre alle soluzioni software perché ora ho una scusa per conoscere queste cose! Purtroppo non ho ancora esperienza con FPGA.
Keegan Jay,

6

Semplice: utilizzare un microcontrollore PSoC5 .

PSoC

Hai tutta la facilità d'uso di un microcontrollore, inoltre contiene un CPLD, quindi puoi scrivere le tue periferiche hardware in Verilog. Scrivi il tuo decodificatore seriale di dati in verilog e usa DMA per trasmetterlo alla porta USB.

Nel frattempo, il potente core ARM a 32 bit può modificare le istruzioni di Thumb.


La pagina panoramica non elenca le frequenze di clock, il che ha sollevato il mio sospetto. La scheda tecnica dice 40MHz (ho anche notato 6mA a 6MHz). Questa è la metà di ciò che OP ha ora. "L'MCU deve anche gestire molte altre attività", quindi può dipendere da quali siano se questa è una buona idea o meno.
Stevenvh,

Salgono a 67MHz. Quindi è quasi veloce come l'attuale processore dell'OP, tranne per il fatto che la maggior parte del lavoro sarà svolto in hardware, lasciando alla CPU molto più tempo libero.
Rocketmagnet,

1
Non ho guardato tutti i fogli dati. Il primo che ho scelto diceva 40MHz.
Stevenvh,

@stevenvh - Hanno diversi gradi di velocità. Il terzo numero nella PN è il grado di velocità. (4 = 48 MHz, 6 = 67 MHz).
Rocketmagnet,

1
Questa è anche una soluzione fantastica a lungo termine, proprio come l'idea FPGA. Non ho mai sentito parlare di questo tipo di chip ma porta molte funzionalità sul resto della mia scheda in un unico chip. In futuro questo potrebbe significare che l'intero ricevitore si adatta a qualcosa delle dimensioni di una chiavetta USB, che è la visione del mio progetto. Imparerò Verilog il prossimo semestre.
Keegan Jay,

4

Penso che tu abbia una classica scelta ingegneristica da fare: veloce, economica, funziona: scegline due.

La soluzione di @ vicatcu è sicuramente buona, ma se non puoi o non vuoi aggiungere altro hardware (e questo include un processore più veloce) devi fare una scelta. Se questo collegamento seriale è il più importante di quanto dovrebbe rimanere nell'ISR fino a quando tutti i bit non sono stati raccolti. 180 istruzioni per bit in realtà non sono affatto male, ma non provare a fare tutto. Quando si rileva l'inizio di un trasferimento, ruotare fino al completamento del trasferimento. Riempi il risultato in un FIFO e poi riprendi la normale elaborazione.

Non dici quanto è lunga ogni trasmissione, ma se sono brevi e scoppiate questa sarebbe una soluzione praticabile. Sono disposto a scommettere che l'implementazione della porta COM virtuale ha anche un po 'di buffering hardware, quindi un servizio di interruzione "ritardato" perché non dovrebbe presentare troppi problemi. Per quanto riguarda il resto di ciò che l'MCU deve fare ... hai alcune decisioni di progettazione da prendere.


Questo tipo di soluzione completa l'approccio software di rocketman con la riduzione del numero di driver basati su interrupt. Potrei mantenere il driver seriale principale che ho citato come basato su interrupt. Inoltre proverò a girare fino a quando l'intero fotogramma non viene letto come dici tu.
Keegan Jay,

3

Prima di tutto, mi piacciono già alcune delle risposte qui e alcune hanno ottenuto il mio voto.

Ma solo per aggiungere un'altra possibile soluzione: dati i vincoli del tuo progetto, l'aggiunta di un secondo microcontrollore sarebbe dannosa (ciò implicherebbe un'altra corsa della scheda)? Forse un semplice microcontrollore a 8 bit che si collega al tuo Cortex-M3 tramite una periferica veloce come SPI. Il controller a 8 bit di tua scelta eseguirà il polling di bit e formerà byte proprio come nella risposta selezionata, ma quando ha un byte, potrebbe scaricarlo nel registro dati SPI per il trasferimento.

Il lato corteccia-M3 semplicemente interromperebbe i dati SPI ricevuti. Ciò riduce il precedente interrupt triggerato da 400 KHz esterno a 50 KHz.

I due motivi per cui sto suggerendo questo è perché alcuni degli altri metodi (PSoC o FPGA aggiunto) sono un po 'costosi (anche se questo probabilmente non ha importanza per un progetto accademico a basso volume) e perché potrebbe consentire di preservare alcuni dei la struttura del tuo codice attuale.

Oltre a ciò, penso che l'idea di PSoC sia fantastica con il tuo trasferimento di periferiche personalizzate da DMA a USB.


Questo è in realtà il piano che avevo in mente di pubblicare questo. Se non riesco a semplificare il software riducendo la dipendenza dagli interrupt (risposta selezionata) di sicuro, questo è quello che farò. Ma sì, richiederà un'altra tavola, probabilmente due perché faccio schifo per ottenere i miei progetti giusti la prima volta.
Keegan Jay,

@JayKeegan, haha ​​benvenuto nel club!
Jon L

2

Se il formato dei dati è simile a quello di un UART, ma con una velocità di trasmissione imprevedibile ma coerente, la mia inclinazione sarebbe quella di utilizzare un CPLD per convertire ogni parola di dati in arrivo in formato SPI o asincrono standard. Non penso che sia necessario spingersi fino in fondo nel regno dei CPLD. In realtà, anche la logica discreta potrebbe essere quasi praticabile. Se riuscissi a generare un clock che fosse un margine di oltre 5 volte la tua velocità di dati desiderata, potresti usare un contatore divide per cinque e divide per 16 con alcune porte. Disporre il contatore di divisione per cinque in modo che venga mantenuto in reset ogni volta che l'ingresso è inattivo e il contatore di divisione per 16 è a zero. Altrimenti genera un impulso di clock SPI e bump il contatore di divisione per 16 ogni volta che il contatore di divisione per cinque colpisce 2.

Dato l'orologio 5x, si potrebbe generare l'orologio SPI usando un 16V8 (il dispositivo logico programmabile attualmente più piccolo e più economico). Un secondo 16V8 o 22V10 potrebbe essere usato come un divisore di velocità frazionata per generare il 5x clock, oppure si potrebbe usare un chip leggermente più grande (CPLD) e fare tutto in uno.

Modifica / Addendum

Su alcune ulteriori considerazioni, se si intende utilizzare un CPLD, è possibile aggiungere facilmente alcuni miglioramenti aggiuntivi al circuito. Ad esempio, si può facilmente aggiungere la logica per far arrestare il circuito fino a quando non riceve almeno 1,5 bit di bit di stop, seguito da 3,5 bit di bit di start; se riceve un bit di avvio troppo breve, dovrebbe tornare a cercare il bit di stop. Inoltre, se si utilizza SPI, è possibile utilizzare il segnale / CS per assicurarsi che il dispositivo ricevente visualizzi i dati correttamente inquadrati. Se il dispositivo che riceve i dati SPI è in grado di gestire frame a 10 bit, è possibile inviare direttamente tali frame. Altrimenti, ogni frame a dieci bit potrebbe essere inviato come frame a 8 bit con il set LSB (7 bit di dati) e un frame con tutti i frame di LSB (3 bit di dati); l'orologio SPI verrebbe accelerato durante i bit di stop in modo da inviare tutti i dati.

Alcuni microcontrollori hanno moduli di generazione PWM piuttosto versatili che includono cose come la capacità di essere tenuti in reset da un segnale esterno e sincronizzare i loro tempi al rilascio di tale segnale. Se il tuo microcontrollore può farlo, a seconda delle sue esatte caratteristiche, ciò potrebbe semplificare considerevolmente il CPLD o i circuiti di generazione dei tempi.

Un altro approccio su cui Rocketmagnet ha in qualche modo accennato sarebbe quello di avere un piccolo micro il cui unico scopo è decodificare i dati seriali e convertirli in un formato utilizzabile dal micro principale. La velocità dei dati a 400 KHz è piuttosto rapida per la decodifica software, ma qualcosa come un PIC potrebbe gestirla se non dovesse fare altro allo stesso tempo. A seconda dei dispositivi che conosci, questo potrebbe essere più semplice o più difficile rispetto all'utilizzo di un CPLD.


Tutto ciò sarà molto prezioso quando si progetta la logica digitale per la decodifica. Effettivamente presenterò come SPI. Per ora, sto solo facendo la decodifica usando un MCU standalone (vincoli temporali). Grazie!
Keegan Jay,
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.