Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Misunderstanding NIDAQmx Timebase Divisor?

Hi,

I'm using CVI version 7 and a PCI 6023E.

I have used the wizard to set up a task monitoring 16 channels continuously, coordinated by an external signal on PFI0.

This is working fine.

However, I don't wish to gather data every pulse of the signal on PFI0, but every 16 pulses. I used the command DAQmxSetTiming(myTask, DAQmx_SampClk_TimebaseDiv, 16); thinking that it would achieve what I wanted, but it made no difference.

Any ideas?

Thanks in advance,
Chris
0 Kudos
Message 1 of 11
(4,063 Views)
I've attached a screen shot of an example that should do what you want. The example is in LabVIEW, but I think it will get across the idea of what you need to do. I've also attached a diagram of the timing engine that is used on an ESeries card which might help. This same diagram is included in the DAQmx Help file, but I've included it here for convenience.

In order to use an external sample clock timebase, there are two pieces of information that are required. The first is the sample timebase source. By default the sample timebase source will be the Master Timebase or the onboard 20 MHz Timebase. I suspect you are not setting the timebase source property and are dividing down the 20 MHz Timebase instead of the external signal on PFI0. T
he second piece of information required is the sample timebase rate or sample timebase divisor. If you specify a sample timebase divisor, the timebase will be divided down by the specified factor to produce the sample clock, and the sample clock rate attribute will be ignored. If you specify a sample timebase rate, the driver will use this rate in conjunction with the sample clock rate to program the correct divisor for you. If you supply both the sample timebase rate and sample timebase divisor, the driver will always use the divisor attribute and ignore the rate attribute. Generally, you will only want to use the sample timebase divisor attribute if you want to divide down an aperiodic external signal, or you want to override the default divisor chosen by the driver.
Download All
Message 2 of 11
(4,064 Views)
Reddog,

Thanks for your detailed and helpful comments.

I think that I have configured my application to use PFI0 as the timebase source - the code generated by the wizard is:

DAQmxCfgSampClkTiming(myTask, "PFI0", 5000, DAQmx_Val_Rising, DAQmx_Val_ContSamps, 100);

I'm not sure what the 100 signifies, but the 5000 is the number of samples to hold in the buffer.

My external signal could well be aperiodic, and I do want to divide it down.

I think I'm doing the right things, but I'm not entirely sure.
0 Kudos
Message 3 of 11
(4,064 Views)
The DAQmxCfgSampClkTiming function is used for setting properties of the sample clock and not the sample clock timebase. With the current parameters being passed, the task should be set up to use an external sample clock on PFI0. The 5000 indicates you expect the maximum speed of the external clock to be 5000 Hz, and the 100 is the number of samples you wish to acquire. However, since you want to do a continuous acquisition, the 100 is largely ignored in this case. I'm guessing when you ran your program, you were getting a sample on every edge of the clock instead of every 16 like you wanted.

To attain what you want, you need to make a sequence of calls like the following:

DAQmxCfgSampClkTiming(myTask, "OnboardClock", 5000, DAQmx_Val_Ri
sing, DAQmx_Val_ContSamps, 100);
DAQmxSetSampClkTimebaseSrc(myTask, "PFI0");
DAQmxSetSampClkTimebaseDiv(myTask, 16);

Notice I changed the clock source in the DAQmxCfgSampClkTiming function from "PFI0" to "OnboardClock". If you leave the source of the sample clock as an external clock, you'll bypass the use of the sample clock timebase and you still won't be able to divide down your signal. Look at the timing diagram again to see why this is true. With this sequence of calls, you should now have an external sample clock timebase on PFI0 which is divided down by 16 to act as your sample clock. I hope this helps. Good luck!
0 Kudos
Message 4 of 11
(4,064 Views)
Sorry, my mistake about the 5000 - it is the expected maximum rate - however, I do wish to divide this by 16, so should the expected maximum rate now fall to 312.5 or say 400?

I have tried the code you suggested (or something very close) and I get an error stating that the Sample Rate exceeds the maximum sample rate for the number of samples specified, as shown in the attached bitmap.



The relevant lines of code are:

DAQmxErrChk(DAQmxCfgSampClkTiming (taskOut, "OnboardClock", 5000, DAQmx_Val_Rising, DAQmx_Val_ContSamps, 100));

From the code generated by the task wizard, and

DAQmxCreateTask ("Read Analogue Inputs", &ReadAITask);
CreateReadAnalogInputs(&ReadAITask);
DAQmxSetTimingAttribute (ReadAITask, DAQmx_SampC
lk_Timebase_Src, "PFI0");
DAQmxSetTimingAttribute (ReadAITask, DAQmx_SampClk_TimebaseDiv, 16);

from within my program. CreateReadAnalogInputs calls the code generated by the wizard and ultimately runs the first line typed above. The error occurs when the task is started.

I couldn't find the exact functions you quoted, but assume that the ones that I am using are right.

So, I'm still stuck - well, not entirely as I could just read in all the samples but then discard 15/16s of them - not very elegant though.
0 Kudos
Message 5 of 11
(4,064 Views)
Without seeing the rest of the code that was generated by the wizard, it's hard for me to see what might be going wrong. If you want to include the generated code, I can look at it and see if I can spot a problem. I created a LabVIEW program with the exact same inputs you are using, and I didn't receive an error (I'm using NI-DAQ 7.2). From the error reported, it looks like the driver thinks you are trying to sample at 1.25 MHz across 16 channels which is probably too fast for your convert clock. However, this error is usually only reported if you have explicitly set your convert rate or delay from sample clock property.

If all else fails, you can always use a counter to accomplish what you want. It will involve generating
a continuous pulse train on ctr0 in another task. You will need to use an external counter timebase source on PFI0 and set a number of other counter properties such as idle state and output behavior. However, once you have the counter programmed correctly, you can use the resultant pulse train as an external clock for your AI task. It's not as clean as getting the AI sample clock timebase to work, but it might be better than throwing away 15 points out of every 16. If you want to pursue this route, I can point you to some examples that should be a good starting point.
0 Kudos
Message 6 of 11
(4,064 Views)
The code generated by the wizard (apart from the header file which just contains a function prototype) is:

/**************************************************************************/
/* WARNING: This file was automatically generated. Any changes you make */
/* to this file will be lost if you generate the file again. */
/**************************************************************************/
#pragma DisableUnreferencedIdentifiers

#include
#include

#define DAQmxErrChk(functionCall) {DAQmxError = (functionCall); {if (DAQmxError < 0){goto Error;}}}
#define DEFAULT_TIMEOUT DAQmx_Val_Infinite
#define ONE_SAMPLE_PER_CHANNEL 1
#define DEFAULT_DATA_LAYOUT DAQmx_Val_GroupByChannel
#define DEFAULT_FILL_MODE DAQmx_Val_GroupByScanNumber
#define SINGLE_ELEMENT_SIZE 1


/**************************************************************************/
/* Begin Generated Code */
/**************************************************************************/
int32 CreateReadAnalogInputs(TaskHandle *taskOut0)
{
int32 DAQmxError;
TaskHandle taskOut;

DAQmxError = 0;

DAQmxErrChk(DAQmxCreateTask("ReadAnalogInputs", &taskOut));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai0", "Voltage0",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai1", "Voltage1",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai2", "Voltage2",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai3", "Voltage3",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai4", "Voltage4",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai5", "Voltage5",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai6", "Voltage6",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai7", "Voltage7",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai8", "Voltage8",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai9", "Voltage9",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai10", "Voltage10",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai11", "Voltage11",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai12", "Voltage12",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai13", "Voltage13",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai14", "Voltage14",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskOut, "Dev1/ai15", "Voltage15",
DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, ""));

DAQmxErrChk(DAQmxCfgSampClkTiming(taskOut, "PFI0",
5000, DAQmx_Val_Rising,
DAQmx_Val_ContSamps, 100));

*taskOut0 = taskOut;

Error:
return DAQmxError;
}

/**************************************************************************/
/* End Generated Code */
/**************************************************************************/

Although I have now changed it back to using PFI0 to pursue the 'read 16 drop 15' strategy.

The code in my main app. to do with this task is as follows:

DAQmxCreateTask("Read Analogue Inputs", &ReadAITask);
CreateReadAnalogInputs(ReadAITask);

I start the task with:

DAQmxStartTask(ReadAITask);

I am then reading in the data with the line:

DAQmxReadAnalogF64(ReadAITask, 2400, 10.0, DAQmx_Val_GroupByChannel, AIResults, 38400, &iNumRead, 0);

finally I stop the task;

I am interested in programming a counter to do the job, and so any information about that would be greatly appreciated.

Thanks again,
Chris
0 Kudos
Message 7 of 11
(4,064 Views)
Wow, I've stared at your code for a while now and can't figure out why you're seeing the error in CVI and I'm not through LabVIEW. I don't have CVI installed, so I can't try running your program to see if I see similar results. The only other thing I can think of is their might be a behavioral difference in the driver versions if you're not using NI-DAQ 7.2.

I did notice one thing in your program that you might want to correct. In the following lines,

DAQmxCreateTask("Read Analogue Inputs", &ReadAITask);
CreateReadAnalogInputs(ReadAITask);

the DAQmxCreateTask call is redundant and in fact will probably produce a small memory leak. The CreateReadAnalogInputs function already calls DAQmxCreate
Task and will overwrite anything done with the previous task. You should be able to remove the DAQmxCreateTask call without any harm.

I've attached a picture that illustrates how to program a counter to produce the timing signal you desire. Again, it's in LabVIEW, but performing the translation to C should be straight forward. The diagram also explains what is being done at each step in the example. Using the counter in this fashion should give you a clock signal with a falling edge every 16 ticks of the external signal on PFI0. Given this, you'll want to modify the timing of your AI task to acquire on the falling edge of the signal instead of the rising edge, and the source of your clock should now be Ctr0InternalOutput instead of PFI0. If you have other questions on how the counter works, I encourage you to look in the NI-DAQmx Help. The Common Applications -> Pulse Generation chapter has a lot of helpful information in it.
0 Kudos
Message 8 of 11
(4,064 Views)
I'll give that a go - thanks again for your help.
0 Kudos
Message 9 of 11
(4,064 Views)
Hi ,

Could you please let me know, what was the outcome of trying the suggestions from reddog.I would provide you with further feedback on it, once I know how you are getting on with the problem.

Best Regards

Atul Wahi
Applications Engineer.
www.ni.com
0 Kudos
Message 10 of 11
(4,064 Views)