2013-07-01 13 views
6

Sto cercando un modo semplice per attivare il mio software di acquisizione dati utilizzando un impulso TTL esterno. Ho bisogno di campionare i dati da più fonti in modo sincrono con un clock di riferimento a 5 Hz. L'acquisizione non ha bisogno di priorità in tempo reale, ma voglio assicurarmi che il mio software sia attivato il più presto possibile e esattamente una volta per ciclo di clock esterno. Preferirei farlo in qualche modo ottenendo un interrupt dal trigger esterno senza dover utilizzare un ciclo di polling veloce. Per quanto posso dire, non si può semplicemente usare un pin di porta parallela per un interrupt in un sistema operativo moderno come Linux. Qualche idea?Interrupt hardware per acquisizione dati sincrona

Sto anche pensando di generare pacchetti di trasmissione sulla mia rete per notificare ad altre macchine sulla rete che si è verificato un evento di attivazione. A causa della latenza della rete, tuttavia, potrebbe non esserci abbastanza tempo disponibile nel periodo di 200 ms tra i trigger per eseguire l'acquisizione.

risposta

7

Invece di utilizzare la porta parallela, avete pensato di utilizzare un dispositivo seriale? Dato che hai un segnale TTL, avrai probabilmente bisogno di un convertitore di livello per convertire i livelli da TTL a RS232 +/- 12V. Una volta che si utilizza un dispositivo seriale, è possibile utilizzare le chiamate standard di serie ioctl() per rilevare una modifica dello stato del segnale di controllo.

In particolare, è possibile utilizzare l'ioctl TIOCMIWAIT sul dispositivo seriale collegato per attendere una modifica sulla linea DCD, che si connetterà alla sorgente dell'orologio.

tua applicazione utente sarebbe stato bloccato in attesa della chiamata di sistema ioctl TIOCMIWAIT finché non ci sarà un cambiamento di status sulla linea di clock, a quel punto la vostra applicazione sarebbe diventato eseguibile e tornare dal ioctl. Potrebbe essere necessario assicurarsi di gestire il caso in cui si ottiene un cambiamento di interrupt di stato sui fronti di salita e di discesa dei segnali di controllo seriale. Su alcuni hardware UART (es. TL16C554A UART) è possibile che si ottenga un interrupt solo per un segnale che passa in una singola direzione. Ad esempio, per il modello TL16C554A, lo TIOCMIWAIT si sovrapporrà solo sul fronte di salita di qualsiasi variazione del segnale di Indicazione dell'anello.

Usando i ioctl seriali in questo modo ha anche il vantaggio che è possibile utilizzare un adattatore USB-seriale che supporta TIOCMIWAIT se necessario (ad es PL2303), e mantenere ancora utente compatibilità software livello, sia pure a scapito di una maggiore latenza dovuta su USB.

Se è necessaria una latenza inferiore a quella che può essere raggiunta attraverso lo spazio utente, è preferibile scrivere un modulo del driver del kernel in grado di gestire i tempi e il campionamento, ma non suggerirei questo percorso a meno che non sia assolutamente necessario. È più facile sviluppare il codice spaziale dell'utente.

Ecco alcuni snippet di codice C di esempio incompleto per l'utilizzo dell'ioctl TIOCMIWAIT.

int serial_fd = open(cmdline.device_name, O_RDWR | O_NONBLOCK | O_NOCTTY); 
static const unsigned int ri_flag = TIOCM_RNG; 

/* Set up serial port here using tcsetattr. Set CRTSCTS | CLOCAL to ensure status interrupts 
* are generated. 
*/ 

while (1) { 
     /* Wait for positive RI transition. TIOCMIWAIT takes a mask 
     * as argument, only returning when the appropriate signal has changed. 
     */ 
     if (ioctl(serial_fd, TIOCMIWAIT, ri_flag)) { 
      fprintf(stderr, "ioctl() failed waiting for RI edge [%s]\n", strerror(errno)); 
      break; 
     } 

     /* Do sensor sampling here. You could use TIOCMGET to first verify that 
     * the clock line is in the expected state, eg high, before continuing. 
     */ 
} 
+0

Questo è esattamente quello che mi piacerebbe fare. Non ero a conoscenza del fatto che potessi ancora utilizzare gli interrupt RS232 su un adattatore USB. Questo sicuramente semplifica le cose. Sembra che posso facilmente implementarlo in Python usando la domanda http://stackoverflow.com/questions/5904895/python-monitor-serial-port-rs-232-handshake-signals – Mike

+0

L'esempio di ioctl Python ha funzionato perfettamente con un vero serial porta! ioctl ha restituito un "errore di argomento" ogni volta che ho provato questo con un adattatore USB Keyspan, ma meglio non avere comunque la latenza e usare una vera porta com. Ora è sufficiente costruire il TTL su un cambio di livello +/- 12V. – Mike

+1

@Mike Ho dato un'occhiata all'origine, il driver keyspan non supporta 'TIOCMIWAIT'. Solo alcuni driver USB-seria supportano questo, cercare '.tiocmiwait' nei file del driver nella directory di origine Linux' drivers/usb/serial'. Il PL2303 è un adattatore seriale USB molto comune. Potrebbe essere in grado di trovare uno di questi e modificare la parte anteriore +/- 12V del dongle. In alternativa, Maxim produce una serie di circuiti integrati di conversione di livello. –

3

Il polling è un metodo eccellente per una velocità di trasmissione dati così bassa. Sondare a 1 ms. Dovrebbe andare bene Provare a usare un interrupt hardware causerà molto dolore.

Google per "Interrompi GPIO Linux" se si vuole farlo nel modo più difficile. :)

https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals

+0

Per ora ho trovato che uno dei miei moduli DAQ USB ha un contatore a 32 bit che si attiverà direttamente dal mio segnale TTL. Sono in grado di interrogare questo valore in 0,7 ms e cercare le modifiche. – Mike

2

ho finito per usare la porta della linea CTS di serie per il trigger utilizzando il TIOCMIWAIT ioctl per Austin Phillips risposta. Poiché RS232 richiede livelli +/- 12V, sono riuscito ad ottenere la potenza necessaria per questo dispositivo di cambio livello dalle altre linee di controllo seriali.

Level shifter schematic

codice

La Python per implementare questa soluzione può essere trovata in questione: Python monitor serial port (RS-232) handshake signals

2

consideri che collega la sorgente di impulsi esterna al ping 'CD' di un vero e proprio (non un convertitore da USB a RS232!) porta seriale. Quindi è possibile utilizzare "PPS api" per ottenere una data/ora esatta da cui il pin "è andato alto" il più possibile.

Potrebbe essere necessario un trasduttore di segnale TTL; non tutte le porte seriali funzionano correttamente con i livelli di segnale TTL.

L'aPS PPS viene normalmente utilizzata per il mantenimento del tempo. Per esempio. collega il pin PPS di un modulo GPS al tuo pc e lascia che NTP si sincronizzi con quello. Questo ti dà precisione microsecondo.

Questa API PPS dovrebbe essere più accurata di qualsiasi altra soluzione di spazio utente (ad esempio l'ioctl di TIOCMIWAIT) poiché viene completamente gestita nel kernel, immediatamente quando l'interruzione (attivata dal cambiamento del segnale del CD) entra in gioco. la soluzione ioctl hai almeno un interruttore di contesto. Ho fatto alcuni test su un raspberry pi e una soluzione userspace da almeno 6us jitter.

L'aPS PPS fornisce un timestamp da quando è stato rilevato l'impulso.

Perché non utilizzare un convertitore da USB a RS232: ho letto da qualche parte (in relazione all'ora) che i dispositivi USB vengono interrogati una volta ogni +/- 1 ms. Questa frequenza di polling dipende anche da quanto il sistema è occupato con altri dispositivi USB e penso che anche il clock interno del dispositivo USB possa influenzare le cose. Non ho mai misurato questo però.

URL pertinenti:

Per quanto riguarda la funzionalità di rete: utilizzare trasmissioni UDP, non utilizzare TCP.

+0

Ho scelto di usare CTS (vedi la mia risposta) per nessun motivo particolare. Mi sembrava che tutte le linee di controllo fossero trattate in modo equivalente rispetto agli interrupt. Cercherò sicuramente l'API PPS e se può dare un tempismo migliore rispetto al mio attuale sistema basato sugli interrupt. – Mike

+0

Non ho avuto fortuna con l'utilizzo di convertitori USB a RS232. – Mike

+0

A un certo punto dovrei catturare i timestamp per ogni evento di interrupt per vedere quanto jitter ho finito con il mio trigger di precisione. – Mike