Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Generating precision software wakeup intervals using PCI-6602?

Solved!
Go to solution

I'm using NI-DAQmx within Visual Studio 2005 C++ under Windows XP.

I'm NOT using LabView.

I'm making an executable with elevated process priority and wish to have a real-time thread wake up at precision time intervals.

Presently the time interval is 0.1 second (10 Hz).

I'd like the wakeup to have low jitter, a few dozen microseconds or better.

 

Presently, I'm using a kludge from previous work, generating a pulse with a 0.1 sec period on one counter and wiring it back to another counter to measure it. 

I use the DAQmxReadCounterU32() function with a 2-second timeout value to pause and then reactivate my thread after the measurement is complete.

This "works" but the jitter is terrible: up to as much as 15 milliseconds for a freshly booted PC and up to 2 milliseconds after I enable MultiMedia timer functionality.

 

What I want is a DAQmx function that just returns control to my application immediately following a timer interrupt with optional output wiring of that timer pulse.

So how do I do this?

 

0 Kudos
Message 1 of 4
(5,366 Views)

Hi, 

     From what it sounds like to me, you may be interested in using a DAQmx Read Property node to set whether you Poll, Yield, or Sleep. 

Poll:  Repeatedly check for available buffer space as fast as possible. This mode allows for the highest sampling rates at the expense of CPU efficiency.

Yield:  Repeatedly check for available buffer space, but yield control to other threads after each check. This mode offers a balance between sampling rate and CPU efficiency.

Sleep: Check for available buffer space once per the amount of time specified in SleepTime.

 

With that property node, you can also select the option, "Wait for Interupt".  By default, DAQmx uses "sleep".  Hope this helps!

 

0 Kudos
Message 2 of 4
(5,345 Views)

OK, I gave DAQmxSetReadWaitMode() a try. What I do is generate a pulse on a different channel/task using DAQmxWriteDigitalLines() and thereby see how much delay there is between the 10 Hz trigger event and my software's response to it.

 

The "Poll" wait mode caused CPU usage to hit 50% under WinXP, but gave me response timing of between 37 and 55 microseconds, which is quite good.

 

The "Yield" wait mode also hits 50% but gave response timing between 37 and 75 microseconds, similar to "Poll".

 

The 50% CPU usage is not desirable.  I have this thread running with RealTime priority.  So I was hoping the "WaitForInterrupt" wait mode would solve that problem.

But I can't get this mode to work with the PCI-6602 when I create a measurement channel using DAQmxCreateCIPeriodChan().

 

First error message is: "Buffered operations are not compatible with the requested Wait Mode. Do not configure a buffer, or set Wait Mode to Yield."

So I tried using DAQmxSetBufInputBufSize() to set buffer size to zero.

Then I get a different error message: "Non-buffered operations cannot use a Data Transfer Mechanism of Interrupts or DMA for this device and Channel Type."

 

So I guess I'm out of luck trying to use the interrupt wait mode.  Let me know if any ideas how to get around this, thanks...

0 Kudos
Message 3 of 4
(5,331 Views)
Solution
Accepted by topic author tschamp

I stumbled upon a good solution.

I set up one task to count the 10 Hz rising edges coming into ctr 4.

This 10 Hz pulse is being generated by another task on ctr 6 and is wired to ctr 4's gate.

But then the trick is to setup Sample Clock timing using that same edge:

 

rv = DAQmxCreateTask("",&taskHandle1);
rv = DAQmxCreateCICountEdgesChan(taskHandle1, "Dev2/ctr4", "", DAQmx_Val_Rising, 0, DAQmx_Val_CountUp);
rv = DAQmxSetCICountEdgesTerm(taskHandle1, "Dev2/ctr4", "/Dev2/PFI22");
rv = DAQmxCfgSampClkTiming(taskHandle1, "/Dev2/Ctr6InternalOutput", 100.0,

      DAQmx_Val_Rising, DAQmx_Val_HWTimedSinglePoint, 1);
rv = DAQmxStartTask(taskHandle1);       

 

The realtime thread then simple loops indefinitely around the following read statement which has a 2 second timeout:

 

rv = DAQmxReadCounterScalarU32(taskHandle1, 2.0, data, NULL);

 

This read returns immediate after a new rising edge occurs and then I have another task which toggles a digital output line which lets me determine the latency between the rising edge and my code getting activated.

 

I recorded and plotted a few minutes of timing data and find that my latency varies between 50 and 110 microseconds which I think is as good as I'm going to get here.

See attached data plot.

 

The other good news about this method is that is uses less than 1% of CPU time.

 

 

 

 

0 Kudos
Message 4 of 4
(5,319 Views)