07-10-2017 05:59 PM
This post is a narrowed scope version of a previous unresolved post titled:
"What are valid combinations of sampling rate and number of samples using a NI PCIe 6363 Device via the DAQmx API"
The details of the setup may be found in the original post.
Question:
Why doesn't the following setup work?
(the registered callback using DAQmxRegisterEveryNSamplesEvent is never called)
float64 SamplingRate = 180000.0; // 180K Hz set via DAQmxCfgSampClkTiming
uInt32 nSamples = 60000; // 60K set via DAQmxCfgSampClkTiming
Given that the following (similar) setup works fine
float64 SamplingRate = 150000.0; // 150K Hz set via DAQmxCfgSampClkTiming
uInt32 nSamples = 50000; // 50K set via DAQmxCfgSampClkTiming
Solved! Go to Solution.
07-11-2017 01:08 PM
Hi big.tuna,
I used the ContAcq-IntClk-EveryNSamplesEvent.c DAQmx API example and was unable to replicate this behavior. Does the example behave this way on your system as well?
Justin
Applications Engineer
07-11-2017 05:17 PM
Hi Justin,
Thank you for the help. Perhaps you can run my code (pasted below), but I think it is the same as your test. I am still having problems as reported before.
Here is what I did:
(0) obtained and built ContAcq-IntClk-EveryNSamplesEvent.c into a console, this uses 3 Analog channels and started with 10K ADC and 1K buffer to give us 10 callbacks per second. This worked.
(1) modified ContAcq-IntClk-EveryNSamplesEvent.c so we can test my parameters:
(a) modified the code to use only one analog channel (as in my original test, should not be an issue)
(b) modified the code to allow a test of either DAQmxReadBinaryI16 or DAQmxReadAnalogF64
(c) parameterized the code to allow easy changes to the ADC rate and samples
I ran the code (see below for a full copy), using all configurations I mentioned:
configuration that does work (either with DAQmxReadBinaryI16 or DAQmxReadAnalogF64)
float64 SamplingRate = 150000.0;
uInt32 nSamples = 50000;
here is the console trace:
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
configuration that does not work: (neither with DAQmxReadBinaryI16 nor DAQmxReadAnalogF64)
float64 SamplingRate = 180000.0;
uInt32 nSamples = 60000;
here is the console trace:
DAQmx Error: Requested Every N Samples Event Interval is not supported for the given Data Transfer Mechanism and buffer size.
To keep DMA or USB Bulk as the Data Transfer Mechanism, modify the buffer size and/or the Every N Samples Event Interval so the buffer size is an even multiple of the Every N Samples Event Interval. To keep the same Every N Samples Event Interval and buffer size, change the Data Transfer Mechanism to Interrupts if supported.
Property: DAQmx_Every N Samples Acq Into Buffer Event Interval
Requested Value: 60000
Buffer Size: 100000
Task Name: _unnamedTask<0>
Status Code: -200877
Below is the complete source code used, this should allow anyone to reproduce the test.
You should be able to drop this into a console app replacing main.cpp, and build in Visual Studio.
You will need the NIDAQmx.lib and NIDAQmx.h
#include "stdafx.h"
#include "NIDAQmx.h"
#include <stdio.h>
constexpr int NI_SAMPLES = 60000; // <- change this to 50000 for working code
constexpr double NI_ADC_RATE = (double)(3 * NI_SAMPLES);
#define _USE_INT_FOR_DATA_BUFFER_ 314 // <- comment out this line to use a double for each Analog element in the array/sample buffer
#ifdef _USE_INT_FOR_DATA_BUFFER_
static int16 NI_data[NI_SAMPLES];
#else
static float64 NI_data[NI_SAMPLES];
#endif
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
/*********************************************/
// Error handler
/*********************************************/
static void ErrorHandler(TaskHandle& taskHandle, int32 error)
{
char errBuff[2048] = { '\0' };
if (DAQmxFailed(error))
{
DAQmxGetExtendedErrorInfo(errBuff, 2048);
if (taskHandle != 0)
{
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
taskHandle = 0;
}
printf("DAQmx Error: %s\n", errBuff);
char ch = getchar();
}
}
/*********************************************/
// Callback Code
/*********************************************/
static int32 CVICALLBACK EveryNSamplesCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error = 0;
int32 read = 0;
#ifdef _USE_INT_FOR_DATA_BUFFER_
DAQmxErrChk(DAQmxReadBinaryI16(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#else
DAQmxErrChk(DAQmxReadAnalogF64(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#endif
if (read > 0)
{
printf("Acquired %d samples\n", read);
}
Error:
ErrorHandler(taskHandle, error);
return 0;
}
/*********************************************/
// Console Code
/*********************************************/
int main()
{
TaskHandle taskHandle = 0;
int32 error = 0;
DAQmxErrChk(DAQmxCreateTask("", &taskHandle));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "Dev2/ai4", "", DAQmx_Val_Diff, -10.0, 10.0, DAQmx_Val_Volts, NULL));
DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "", NI_ADC_RATE, DAQmx_Val_Rising, DAQmx_Val_ContSamps, NI_SAMPLES));
DAQmxRegisterEveryNSamplesEvent(
taskHandle,
DAQmx_Val_Acquired_Into_Buffer,
NI_SAMPLES,
0,
EveryNSamplesCallback,
NULL);
DAQmxErrChk(DAQmxStartTask(taskHandle));
char ch = getchar();
DAQmxErrChk(DAQmxStopTask(taskHandle));
Error:
ErrorHandler(taskHandle, error);
}
07-12-2017 05:42 PM
Hi big.tuna,
I haven't had a chance to try running your code yet, but when you say that you were able to obtain and build the example and that it worked, was that for this combination of sample rate and number of samples as well? Is it only once changes were made that it stopped working?
07-12-2017 06:49 PM
ContAcq-IntClk-EveryNSamplesEvent.c using 3 Analog channels, 10K ADC, 1K samples works (unmodified)
ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 10K ADC, 1K samples works
ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 150K ADC, 50K samples works
ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 180K ADC, 60K samples does not work
My previous post has the complete details, including the exact source code, and console error trace.
The console error trace may offer some clues.
The combination that does not work (180K ADC, 60K samples) is the problem I am trying to solve.
07-13-2017 03:54 PM
Hi Big Tuna,
The console trace reveals the issue.
Requested Value: 60000
Buffer Size: 100000
I believe you are not pulling samples off of your buffer fast enough. you are sampling at 180k and requesting 60k samples, leaving 120k data points and overflowing your 100k buffer. All of the other combinations you mentioned did not exceed a 100k difference.
Regards,
Finch Train
07-13-2017 06:49 PM
First, the buffer was allocated as 60K, not 100K, I do not know where the 100K buffer comes from.
Second, the ADC Rate is 180K per second, and I have requested a callback at 60K samples, so that after 0.333 seconds I am expecting a callback, which should keep up with the data collection. I am not spending much time in the callback (which is a potential source of overrun) .
Third, I had originally posted other cases that worked, such as 200K ADC and 50K samples being read 4 callbacks per second. Using the logic applied to your response, I would expect that (if the mysterious buffer was 100K) after requesting 50K samples, this should leave 150K data points (following your analysis) and overflow the 100k buffer, but this does not happen. The 200K ADC and 50K sample buffer works fine.
Interestingly, some combinations work, others do not, I have not found a pattern.
Could you please explain why the following setup works
ADC=200K, 50K samples -> does work
and this one does not?
ADC=180K, 60K samples -> does not work, no callbacks ever
The documentation for DAQmxReadBinaryI16 indicates:
numSampsPerChan
The number of samples, per channel, to read. The default value of -1 (DAQmx_Val_Auto) reads all available samples. If readArray does not contain enough space, this function returns as many samples as fit in readArray.
Since I used 60K for the numSampsPerChan parameter, the same as the nSamples configured using DAQmxRegisterEveryNSamplesEvent , I would expect that this should work.
The documentation for DAQmxRegisterEveryNSamplesEvent indicates:
nSamples
The number of samples after which each event should occur.
Therefore, it appears we should get an event after 60K samples arrive, as generated by the 180K/second sampling of the analog channel, which means this should fire every 1/3 second. The 1/N timing is exactly what I get when other combinations are used, such as ADC=200K, samples=50K
Notice in the sample code I provided, I setup the code to make sure the ADC is a multiple of the samples, hence:
constexpr int NI_SAMPLES = 50000;
constexpr double NI_ADC_RATE = (double)(4 * NI_SAMPLES);
07-14-2017 04:46 PM
Hi big.tuna,
Have you taken a look at the following forum post?
http://forums.ni.com/t5/Multifunction-DAQ/Error-200877/td-p/500381
From the error trace, it seems like the buffer is getting set to 100k automatically. We need to change this to a multiple of the number of samples manually with the DAQmxSetBufInputBufSize function as mentioned in the above post.
07-14-2017 05:28 PM
Adding DAQmxSetBufInputBufSize() worked.
Thank you very much.
Here is the code snippet with the problem config:
constexpr int NI_SAMPLES = 6000;
constexpr double NI_ADC_RATE = (double)(3 * NI_SAMPLES);
DAQmxErrChk(DAQmxCreateTask("", &taskHandle));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "Dev2/ai4", "", DAQmx_Val_Diff, -10.0, 10.0, DAQmx_Val_Volts, NULL));
DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "", NI_ADC_RATE, DAQmx_Val_Rising, DAQmx_Val_ContSamps, NI_SAMPLES));
DAQmxErrChk(DAQmxSetBufInputBufSize(taskHandle, NI_ADC_RATE));
DAQmxRegisterEveryNSamplesEvent(
taskHandle,
DAQmx_Val_Acquired_Into_Buffer,
NI_SAMPLES,
0,
EveryNSamplesCallback,
NULL);
static int32 CVICALLBACK EveryNSamplesCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error = 0;
int32 read = 0;
#ifdef _USE_INT_FOR_DATA_BUFFER_
DAQmxErrChk(DAQmxReadBinaryI16(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#else
DAQmxErrChk(DAQmxReadAnalogF64(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#endif
if (read > 0)
{
printf("Acquired %d samples\n", read);
}
Error:
ErrorHandler(taskHandle, error);
return 0;
}