Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hardware interrupt for synchronous data acquisition

I am looking for a simple means of triggering my data acquisition software using an external TTL pulse. I need to sample data from multiple sources synchronously with a 5 Hz reference clock. The acquisition does not need real-time priority but I want to ensure that my software is triggered as soon as possible and exactly once per external clock cycle. I would prefer to do this by somehow getting an interrupt from the external trigger without needing to use a fast polling loop. As far as I can tell, you can't just use a parallel port pin for an interrupt in a modern OS like Linux. Any ideas?

I am also thinking of generating broadcast packets on my network to notify other machines on the network that a trigger event has occurred. Due to network latency however there may not be enough time available in the 200ms period between triggers to do the acquisition.

like image 676
Mike Avatar asked Jul 01 '13 23:07

Mike


2 Answers

Rather than use the parallel port, have you considered using a serial device? Since you have a TTL signal, you'll possibly need a level converter to convert TTL to RS232 +/- 12V levels. Once you're using a serial device, you can use the standard serial ioctl() calls to detect a change in control signal status.

Specifically, you could use the TIOCMIWAIT ioctl on the connected serial device to wait for a change on say the DCD line, which you would connect to your clock source.

Your user space application would be blocked waiting in the TIOCMIWAIT ioctl system call until there is a change of status on your clock line, at which point your app would become runnable and return from the ioctl. You might have to take care to ensure that you handle the case where you get a change of status interrupt on both rising and falling edges of your serial control signals. On some UART hardware (eg TL16C554A UART) it's possible that you'll only get an interrupt for a signal transitioning in a single direction. For the TL16C554A for example, the TIOCMIWAIT would only fall through on the rising edge of any Ring Indicate signal change.

Using the serial ioctls in this manner also has the advantage that you could use a USB-Serial dongle that supports TIOCMIWAIT if required (eg PL2303), and still retain user level software compatibility, albeit at the expense of increased latency due to USB.

If you require lower latency than can be achieved through user space, you'd be best to write a kernel driver module which can handle the timing and sampling, but I wouldn't suggest this route unless absolutely needed. It's easier to develop user space code.

Here's some incomplete sample C code snippets for using the TIOCMIWAIT ioctl.

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.
         */
}
like image 80
Austin Phillips Avatar answered Sep 17 '22 00:09

Austin Phillips


Polling is a fine method for such a slow data rate. Poll at 1 ms. That should be fine. Trying to use a hardware interrupt is going to cause much pain.

Google for "Interrupt Linux GPIO" if you want to do it the hard way. :)

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

like image 38
Mark Lakata Avatar answered Sep 21 '22 00:09

Mark Lakata