Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

How can I detect a missed trigger (i.e. 2nd trigger arrives before the task completes)

Solved!
Go to solution

Is there any way to find out whether a trigger pulse has been missed, because the device is busy?

 

To give a specific example: 

  I'm using an NI4462 board, with falling-edge digital triggers on the PFI0 input.

  I have an external clock, at exactly 1kHz square wave.

  On each falling edge of that clock, I (re)start a task that samples 200 times, (at 200 kHz).

 

Normally, this works OK (provided I'm careful to keep the stop-task and start task in a tight loop, and not do too much processing in the 5ms that remains after the last sample.)

 

BUT, if something were to go wrong (consider the external clock running 1% too fast), the 2nd trigger would arrive during the running task, (say, at sample 198).

The NI4462 would (I think) simply ignore that trigger, because the task is still running, and I'd miss out on an entire frame of data, getting only the 1st and 3rd groups of 200,

 

Is there any way to detect when this has happened, and at least throw an error?

 

Thanks for your help.

 

 

P.S. I also have to worry about the 63-sample filter-delay: is there a better solution than post-processing to cut 63 samples off the start of one group and onto the end of the previous one? This works ok, but it embeds a timing glitch after the 63rd sample.

0 Kudos
Message 1 of 8
(3,701 Views)
Solution
Accepted by RichardNeiill

Hello,

 

I can't think of a way of solving this problem within your AI DAQmx task. This should be relatively straightforward in FPGA or maybe even Real-Time. I will come back if I do come up with something.

 

You could verify your trigger clock with a counter (simply gate your counter with your 1kHz signal) and throw an error if it drifts.

 

Could I maybe ask a little bit more of the context of this question - why do you need this architecture? I am not sure why you can't just continuously acquire samples - this may lead us to a different solution!

 

I will mention that your timings are very tight as that 5uS spare is at best as I don't think your sample clock will be synchronized with your trigger clock.

 

In answer to your question about the delay, can you pre-load the filter before your main acquisition to loose the delay?

A little bit like the solution described in this KB (http://digital.ni.com/public.nsf/allkb/F989B25FF6CA55C386256CD20056E27D?OpenDocument), obviously you would have to set-up your triggers appropriately. A reference trigger could be using with a pre-triggersample size of 63 maybe.

 

I hope this is of help - let me know how you get on.

 

Best Regards,

Nick
0 Kudos
Message 2 of 8
(3,677 Views)

Dear Nick,

 

Thanks for your helpful reply.

 

I think that the simplest workaround for me is actually to call gettimeofday() each time I receive a trigger pulse, and check that the elapsed interval is < 1.5 ms.  This would allow me to know whether a trigger pulse has been missed.

 

What I'm actually doing is a control loop for a photodetector system (We're using an IR CCD as a photon counter on a telescope, just 4 pixels, each used as a photo-diode responding at 2um).

 

Every 1ms or so (this is sometimes longer, never shorter), an external digital timing card (a "PulseBlaster") resets the pixel to black. It then sends a trigger pulse to the NI4462, telling it to sample as many times as it can within the next 1 ms. We sample 200 times (I'll reduce this to 190 if margin is needed). During this time, the pixel is being exposed to light, and the voltage is slowly falling (like a quantised, noisy, descending sawtooth). I find the average gradient (linear regression of the 200 samples), and this gives a best estimate of the number of photons that arrived in that 1ms. This value is then sent onward to another system where it is used both for measurement and in a feedback loop.

 

In other words,  I need to sample like this:

 

     _-_-_-_-_-_......._-_-_-_-_-_.......

      A          B         C          D

 

where:

   points A, C, etc represent triggers for 200 samples (or slightly fewer)

   the time A-B  and C-D is known at 1ms

   the time  A-C  is vary variable, sometimes many ms (but always guaranteed to leave at least 5us between B-C).

   Slightly after B, D,  etc, I need to output a value to the next program.

 

 

As for the 63 sample delay, the problem isn't the delay per se, it's that the 63 samples that we discard from frame n  need to have belonged to the end of frame n-1. This would be reasonably simple as a cut-and-paste, excepting that the time interval between frames n-1 and n  is not exactly known, nor synchronised.  I think the best solution for me is to delay the digital trigger pulse before it arrives at the NI4462 (this is easy in the pulseblaster).

 

 

Best wishes,

 

Richard

0 Kudos
Message 3 of 8
(3,673 Views)

On a related note, I'm having a major problem with erroneous error  -200278.  It's complaining (randomly) that the acquisition has stopped, even though I can confirm that it shouldn't have.

In simplified-code (omitting irrelevant details and parameters):

 

DAQmxCfgSampClkTiming  (  DAQmx_Val_Rising,  DAQmx_Val_FiniteSamps , 100 )         //Finite sampling, 100 samples per task. Rising edge ext trigger.

DAQmxSetReadReadAllAvailSamp ( TRUE )                                                                     //Make reads non-blocking.

DAQmxTaskControl ( DAQmx_Val_Task_Commit )                             

 

while (1) {

    DAQmxStartTask()

 

        inner_total = 0

        while (1) {

                DAQmxReadAnalogF64 ( DAQmx_Val_Auto, 0,  &num_read )     //non-blocking read, may return 0 samples.

                inner_total +=  num_read

                

                /* process data */

 

                if (inner_total == 100){             //once we have read 100 samples, break out of the inner loop.

                    break;

                }

         }

 

    DAQmxStopTask()

 

    usleep(10)

}

 

 

 

This should run forever, processing 100 samples for every time it receives a trigger pulse. Instead, it runs for a random number of cycles before crashing out with -200278. 

 

If I make the final usleep take 1000000 us, the crashes go away - but I can't wait that long in the application.

 

Any thoughts?

 

 

 

0 Kudos
Message 4 of 8
(3,671 Views)

Here is the full program I'm running, and a capture of  stdout/stderr. 

 

If you look at the comments at the start, it shows the result of running this multiple times: it is failing in the same way each time, but at different points, and with different states of alleged task_doneness.

Download All
0 Kudos
Message 5 of 8
(3,669 Views)

On further investigation, I'm reasonably sure I've found a bug in DAQmxReadAnalogF64(). 

 

In finite sampling mode,  with 100 samples per task, and DAQmxSetReadReadAllAvailSamp = FALSE,  (and a sufficient buffer size), the documentation makes it clear that

DAQmxReadAnalogF64 (DAQmx_Val_Auto, DAQmx_Val_WaitInfinitely)  should block till 100 samples are available, and then return all 100.

 

This doesn't happen reliably, if we are repeatedly running, completing, stopping, starting  the same task.

 

Attached is the simplest code I could write to demonstrate this.  (Below, is the truncated version without my comments: )

 


DAQmxCreateTask("Arbitrary_name",&taskHandle);

 

DAQmxCreateAIVoltageChan(taskHandle, "Dev1/ai0:3", "Random_name", DAQmx_Val_Diff, -0.316, 0.316, DAQmx_Val_Volts, NULL);

 

DAQmxCfgDigEdgeStartTrig (taskHandle, "PFI0", DAQmx_Val_Falling);

DAQmxCfgSampClkTiming(taskHandle, 0, sample_rate, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, (NUM_SAMPLES_PER_FRAME) ) 

 

DAQmxSetReadReadAllAvailSamp (taskHandle, FALSE);

 

DAQmxTaskControl ( taskHandle, DAQmx_Val_Task_Commit);

while (1) {

 

    DAQmxStartTask(taskHandle);
 

    DAQmxReadAnalogF64(taskHandle, DAQmx_Val_Auto, DAQmx_Val_WaitInfinitely, DAQmx_Val_GroupByScanNumber, data,

                                       (sizeof(data)/(sizeof(data[0])*4)), &samples_read_thistime, NULL);
 
    if ( (unsigned int)samples_read_thistime != NUM_SAMPLES_PER_FRAME) {
            printf ("ERROR: requested all %lld samples in a single pass with infinite timeout. But only got %d.  (Failed at frame %d, Doneness: %d)\n",

                     NUM_SAMPLES_PER_FRAME, (int)samples_read_thistime, frame, (int)isdone );
            exit (1);
    }

     DAQmxStopTask(taskHandle);

    frame++ ;

}

 

 

 

The above code should loop forever, getting 100 samples each time it's triggered. But actually it tends to either crash out with - 200278, or hit the error-check for samples_read_thistime being too small.

 

0 Kudos
Message 6 of 8
(3,659 Views)

Hello,

 

Looks like this is getting dealt with here too:

http://forums.ni.com/t5/Multifunction-DAQ/Bug-DAQmxReadAnalogF64-DAQmx-Val-Auto-DAQmx-Val-WaitInfini...

 

Thanks

 

Nick
0 Kudos
Message 7 of 8
(3,635 Views)

Looks like this is getting dealt with here too:

http://forums.ni.com/t5/Multifunction-DAQ/Bug-DAQmxReadAnalogF64-DAQmx-Val-Auto-DAQmx-Val-WaitInfini...

 


 

Yes - seemed worth changing the thread title for change in topic. Thanks for your help.

0 Kudos
Message 8 of 8
(3,628 Views)