Apparently calling DAQmxRegisterEveryNSamplesEvent can generate a Win32 floating point exception in a VC++ program. Here is sample code for the simplest Win32 console mode app that reproduces the problem. The device corresponding to "/PXI2Slot2/ai0:15" is a PXI-6250 in a PXI-1033 chassis.
// float.h needed for _control87
#include <float.h>#include <NIDAQmx.h>
int32 CVICALLBACK DAQmxEveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
int32 CVICALLBACK DAQmxDoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
static DWORD DAQmxCallbackData = 0;
int _tmain(int argc, _TCHAR* argv)
// unmask floating point exceptions
DWORD fpmask = _control87(0, 0);
fpmask &= ~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW);
TaskHandle th; res = DAQmxCreateTask("", &th);
res = DAQmxCreateAIVoltageChan(th, "/PXI2Slot2/ai0:15", "", DAQmx_Val_NRSE, -5.0f, 5.0f, DAQmx_Val_Volts, NULL);
// note: the call to DAQmxRegisterEveryNSamplesEvent crashes regardless of whether the following calls are made//res = DAQmxCfgSampClkTiming(th, "/PXI2Slot2/RTSI2", 80000.0, DAQmx_Val_Rising, DAQmx_Val_ContSamps, 100000);
//res = DAQmxSetSampClkTimebaseDiv(th, 80000/40000);//res = DAQmxCfgDigEdgeStartTrig(th, "/PXI2Slot2/RTSI1", DAQmx_Val_Rising);
//res = DAQmxRegisterDoneEvent(th, 0, DAQmxDoneCallback, (void*)&DAQmxCallbackData);
res = DAQmxRegisterEveryNSamplesEvent(th, DAQmx_Val_Acquired_Into_Buffer, 1000, 0, DAQmxEveryNCallback, (void*)&DAQmxCallbackData);
For simplicity, code to check the return values for errors is not shown, but stepping through it in the debugger shows that there are no errors returned until the crash happens. Note that all the sample-timing setup code can be commented out and it crashes exactly the same way, on the call to DAQmxRegisterEveryNSamplesEvent.
By process of elimination, I found that both the denormal and underflow exceptions were being thrown. Obviously, a workaround is to mask those two exceptions, but our application is fairly math-heavy and we really need to know when they occur in our own code. Plus, it makes me a little nervous that a floating point underflow would occur during a DAQmx configuration call that I wouldn't expect to have anything to do with floating point math. Or am I doing something stupid that I've overlooked?
I was able to reproduce this problem on my machine (with a PCIe-6259), and have filed a corrective action request (CAR #141892).
The reason why you're seeing this problem in that specific part of your code is interesting. DAQmxRegisterEveryNSamplesEvent() doesn't directly do any floating point math, but it does need to get the value of an internal property from the DAQmx task. The task isn't already in the verified state, so getting the property value causes the task to transition to the verified state. Transitioning to the verified state for the first time causes the task to look at all of its properties, many of which are floating point properties (such as AI.Max, SampClk.Rate, etc.). Thus a call to register an event callback ends up doing some floating point math.
It may not be much of a relief, but you would see the same floating point exception if you replaced the call to DAQmxRegisterEveryNSamplesEvent() with the following code:
res = DAQmxTaskControl(th, DAQmx_Val_Task_Verify);
You may be able to limit the scope of the workaround by only masking exceptions when configuring and starting the DAQmx task, not during reads. It appears that you also need to _clear87() when you unmask the exceptions, otherwise the status bit that would have caused the exception (had it not been masked at the time) will still be set.
I had the same problem. It was solved by creating the task and then starting the task before calling the DAQmxRegisterEveryNSamplesEvent.