Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

DAQReadCounter Problems

Hello,


I have run into an interesting situation that I can't figure out. We have two computers running Windows 7, collecting data from a NIDAQmx task that is configured to read frequency. One computer is Windows 7 64bit version, and the other is 32bit version, our application is 32 bit, written in CVI 8.0. Both computers have the same task setup, although the daq cards are different. The task is setup to read a frequency using 1 Counter (Low Frequency) measurement method, range of 2 to 2Khz, acquisition mode set to 1 Sample (On Demand).

After running into the problem, I used the sample program that comes with CVI and it has the same result.

Code Sample:

DAQmxStartTask(taskHandle);

do
{
    Delay( 0.010 );

    t1  = Timer();
    error = DAQmxReadCounterF64(taskHandle,-1,0.001,&data[0],100,&count32,NULL);
    t2 = Timer() - t1;

    printf("Delay: %.3f Error: %i Frequency: %.3f Hz\n", t2, error, data[0]);

} while ( ! KeyHit() );


Results:

I input a signal at approxiametely 25 Hz, generating a pulse every 40ms. Since I have a delay of 10 ms in my loop I would expect to get an updated reading every 4th time that I request a read from the counter (give or take, I know there are other latencies etc..) Instead I get responses as follows...

Delay: 0.155 Error: -200474 Frequency: 0.000 Hz
Delay: 0.033 Error: -200474 Frequency: 0.000 Hz
Delay: 0.021 Error: -200474 Frequency: 0.000 Hz
Delay: 0.012 Error: 0 Frequency: 25.526 Hz
Delay: 0.022 Error: -200474 Frequency: 25.526 Hz
Delay: 0.013 Error: 0 Frequency: 25.413 Hz
Delay: 0.029 Error: -200474 Frequency: 25.413 Hz
Delay: 0.028 Error: -200474 Frequency: 25.413 Hz
Delay: 0.006 Error: 0 Frequency: 25.583 Hz
Delay: 0.018 Error: 0 Frequency: 25.413 Hz

Things are not working as expected:
- the first call to DAQmxReadCounterF64 takes 0.155 seconds to complete, much more than the 0.001 seconds passed as the timeout argument
- the first call does return a frequency even though there should have been 3 pulses at least during that time
- the second call takes 0.033 seconds to complete, and it still times out
- the fourth call returns a frequency, but it still takes 0.012 seconds

As I increase the frequency, the ReadCounter function takes less time to complete, but even at 500 Hz it still takes up to 5ms to return a frequency value. Since each frequency task can only have a single channel, reading from many frequency tasks will consume a large amount of program time.  

 

Things are even worse on the 64bit computer.

Am I doing something wrong, or not understanding the settings ?
Thanks.

0 Kudos
Message 1 of 9
(6,902 Views)

Hi Mande,

 

I am sorry to hear that you are having this problem. I notice that you are using software timing to control the sampling rate. Have you considered trying to use hardware timing?

 

Also, what daq cards are you using?

 

Which example program are you running?

 

Regards,

Nathan S.
Applications Engineer
National Instruments
0 Kudos
Message 2 of 9
(6,882 Views)

Hi, thanks for the reply.

 

My sample here is just showing a small loop with a software to demonstrate the problem.  I am not sure that hardware timing would change anything with regards to the function call not returning values in a timely manner.

 

This is being tested on a 6024E and a 6602 counter card.

 

I took the code from the sample program: Dig Freq-Low Freq 1 Ctr

 

Regards,

Ed. 

0 Kudos
Message 3 of 9
(6,880 Views)

Is there any more information I can supply?  There is definitely a problem with how this function is behaving and it is really starting to hurt.

0 Kudos
Message 4 of 9
(6,853 Views)

Hi Ed,

 

What are you using to generate the 25 Hz signal? How fast does it run if you remove the delay from the loop altogether?

 

Regards,

Nathan S.
Applications Engineer
National Instruments
0 Kudos
Message 5 of 9
(6,845 Views)

 Hi,

 

I am just using a function generator to provide the input signal.  I removed the delay and things behave much the same way with some longer timeouts. 


Delay: 0.182 Error: -200474 Frequency: 0.000 Hz
Delay: 0.023 Error: -200474 Frequency: 0.000 Hz
Delay: 0.031 Error: -200474 Frequency: 0.000 Hz
Delay: 0.019 Error: -200474 Frequency: 0.000 Hz
Delay: 0.023 Error: 0 Frequency: 22.423 Hz
Delay: 0.024 Error: -200474 Frequency: 22.423 Hz
Delay: 0.031 Error: -200474 Frequency: 22.423 Hz
Delay: 0.031 Error: -200474 Frequency: 22.423 Hz
Delay: 0.023 Error: -200474 Frequency: 22.423 Hz
Delay: 0.032 Error: -200474 Frequency: 22.423 Hz
Delay: 0.016 Error: 0 Frequency: 22.436 Hz
Delay: 0.024 Error: -200474 Frequency: 22.436 Hz
Delay: 0.032 Error: -200474 Frequency: 22.436 Hz
Delay: 0.022 Error: -200474 Frequency: 22.436 Hz
Delay: 0.029 Error: -200474 Frequency: 22.436 Hz
Delay: 0.020 Error: -200474 Frequency: 22.436 Hz
Delay: 0.028 Error: -200474 Frequency: 22.436 Hz
Delay: 0.028 Error: -200474 Frequency: 22.436 Hz
Delay: 0.026 Error: -200474 Frequency: 22.436 Hz
Delay: 0.025 Error: -200474 Frequency: 22.436 Hz
Delay: 0.017 Error: -200474 Frequency: 22.436 Hz
Delay: 0.006 Error: 0 Frequency: 22.301 Hz
Delay: 0.029 Error: -200474 Frequency: 22.301 Hz
Delay: 0.029 Error: -200474 Frequency: 22.301 Hz
Delay: 0.028 Error: -200474 Frequency: 22.301 Hz
Delay: 0.027 Error: -200474 Frequency: 22.301 Hz
Delay: 0.026 Error: -200474 Frequency: 22.301 Hz
Delay: 0.026 Error: -200474 Frequency: 22.301 Hz
Delay: 0.025 Error: -200474 Frequency: 22.301 Hz

 

I tried to attach the c file that I have used for this output but it your form said it wasn't acceptable for some reason.  I have made so many variations to it, trying everything to get a proper response and figuring out it responses to different settings.

 

Thanks for taking the time to read this.   

Ed.

 

0 Kudos
Message 6 of 9
(6,842 Views)

Hi Ed,

 

You should be able to make your reads execute much faster by configuring Implicit timing on the counter input task.  Try using this:

 

 

DAQmxCfgImplicitTiming (taskHandle, DAQmx_Val_ContSamps , 1000);  //Configures software buffer


DAQmxSetReadRelativeTo(taskHandle, DAQmx_Val_MostRecentSamp );  //Only read the most recent sample from the buffer

DAQmxSetReadOffset(taskHandle, 0);


DAQmxStartTask(taskHandle);

do
{
    Delay( 0.010 );

    t1  = Timer();
    error = DAQmxReadCounterF64(taskHandle,1,0.001,&data[0],100,&count32,NULL);  // Read 1 sample instead of -1 to avoid returning empty buffer
    t2 = Timer() - t1;

    printf("Delay: %.3f Error: %i Frequency: %.3f Hz\n", t2, error, data[0]);

} while ( ! KeyHit() );

 

 

Configuring timing allocates kernel memory for the hardware to transfer samples to as the data becomes available. Calls to DAQmx Read will read back samples from this kernel buffer rather than asking the hardware to send back the next measurement that it takes.

 

In your case I think you want to read back the most recent sample and ignore any samples you might have missed (in case your input frequency is higher than the loop rate), which is why I have set the ReadRelative property to "most recent sample".  The default behavior (read relative to "current read position") is to attempt to read every sample that comes in and if the loop does not keep up you will receive an overwrite error.

 

The downside to this method is that you still cannot make the hardware tolerant to overwrites--every sample must be transferred from the hardware to the PC buffer successfully or you will receive errors (requires restarting the task to clear them).  The hardware you are using does not have a dedicated on-board FIFO for the counters, so the device must transfer each sample as it comes in.  Benchmarks have been made for these transfers to be sustainable to ~200 kHz-300 kHz or so (using DMA), so you'll probably be fine for the rates that you seem to be interested in. 

 

One caveat is that the 6024E only has a single DMA channel and the 6602 only has 3, I'm not sure offhand if the buffered counter task will default to DMA or not.  If you get any errors regarding the DMA channels being in use or otherwise not available, you can change the transfer mechanism to interrupts using DAQmxSetAIDataXferMech, but the maximum frequency you will be able to measure using interrupts would likely be only in the 10s of kHz (somewhat CPU dependant).  This is still way faster than the frequencies you have mentioned so far but I wanted to point it out anyway just in case.

 

 

Best Regards,

John Passiak
0 Kudos
Message 7 of 9
(6,830 Views)

Thank you very much for your reply.

 

That sounds promising, but I think that is the same as setting the task in NIDAQmx to collect continuous samples. We started doing that but we could only configure 3 tasks that way and then ran into the problem that there were not enough DMA channels.  Since each frequency task can only have a single channel, there is no way to get all the channels on the 6602 configured to transfer data that way.

 

I will look into the hardware interupts, but I am not sure the PC will be able to handle that for the 8 tasks as well.

 

I guess I have to renew my service subscription to contact NI directly to see what the timeout in the Read function is not honored ?

 

Thanks again,

Ed. 

0 Kudos
Message 8 of 9
(6,815 Views)

Hi Ed,

 

To set a channel to use interrupts you just need to set the single property before starting the task (DAQmxSetAIDataXferMech).  What is the maximum rate you expect your input signal(s) to be?  DMA is preferable to interrupts but I wouldn't expect an issue if your input signals are slow.

 

When using on-demand timing (instead of Implicit) you have to query the hardware when DAQmx Read is called to ask the hardware to return back a sample when the next period completes (could be up to 1 period of your input before this happens).  The hardware then has to transfer the sample back to software for you to return the data.  This is not going to execute within the 1 ms timeout that you have requested.  It's possible that the more desirable use case in your example would be to timeout every single time and have the function return sooner, but doing this wouldn't give any usable data anyway so I'm not sure if it's a very good example of how one might want to configure the hardware in a typical application.

 

You can get much improvement by reading from the software buffer instead (the read should probably execute on the order of a few ms regardless of the timeout value if configuring the task exactly as I did in my previous post).  I still can't guarantee that the read will return in 1 ms every single time as software calls are inherently non-deterministic when running on a non-realtime OS like Windows.  If (for example) Windows decides to schedule some other task before handling the read call you could get several ms of delay.

 

 

Best Regards,

John Passiak
0 Kudos
Message 9 of 9
(6,810 Views)