01-25-2010 08:46 AM
Hi all,
I am developing an application which uses 5 out of 8 counters of a 6602 to perform independent two-edge separation measurements on input signals to measure insertion delay on some switches under test. Times to measure varies from 1 sec to 120 sec. The problem I am facing is that sometimes separation measurement ends prematurely on the first counter (actually CTR2) while another switch is turning on. It always happens on the first counter regardless the cycling time; other counters read without problems.
I have tried to enable on-board digital filtering, checking with filtering time from 5 microsec up to 5 msec, but without success. I am using CVI 8.5 with DAQmx 8.9.5f6.
Here the loop that prepares counter measurements:
for (nc = 1; nc < 6; nc++) {
// Prepare task and channel
DAQmxChk (DAQmxCreateTask ("", &bc.misH[nc]));
DAQmxChk (DAQmxCreateCITwoEdgeSepChan (bc.misH[nc], bc.ctrChan[nc], "", 0.5, 120.0, DAQmx_Val_Seconds,
DAQmx_Val_Falling, DAQmx_Val_Falling, ""));
// Measure in interrupt (not enough DMA channels available)
DAQmxChk (DAQmxSetChanAttribute (bc.misH[nc], "", DAQmx_CI_DataXferMech, DAQmx_Val_Interrupts, 0));
DAQmxChk (DAQmxCfgImplicitTiming (bc.misH[nc], DAQmx_Val_ContSamps, 2));
// Enabledigital filtering
DAQmxChk (DAQmxSetChanAttribute (bc.misH[nc], "", DAQmx_CI_TwoEdgeSep_First_DigFltr_MinPulseWidth, 5e-06, 0));
DAQmxChk (DAQmxSetChanAttribute (bc.misH[nc], "", DAQmx_CI_TwoEdgeSep_First_DigFltr_Enable, 1, 0));
DAQmxChk (DAQmxSetChanAttribute (bc.misH[nc], "", DAQmx_CI_TwoEdgeSep_Second_DigFltr_MinPulseWidth, 5e-06, 0));
DAQmxChk (DAQmxSetChanAttribute (bc.misH[nc], "", DAQmx_CI_TwoEdgeSep_Second_DigFltr_Enable, 1, 0));
}
Measures are read in a separate thread that loops through the counters:
// Read counter status
for (bp = 1; bp < 6; bp++) {
// Measure only if task running
if (bc.misH[bp] && started[bp]) {
daqerr = DAQmxReadCounterF64 (bc.misH[bp], 1, 0.0, d, 2, &sRead, 0);
if (daqerr && (daqerr != DAQmxErrorOperationTimedOut && daqerr != DAQmxErrorSamplesNotYetAvailable && daqerr != DAQmxErrorCounterNoTimebaseEdgesBetweenGates)) {
line = __LINE__; goto Error;
}
if (sRead > 0) {
time[bp] = d[0];
started[bp] = 0;
}
}
}
DAQmxChk macro tests for instruction return code, so I am sure no error is found neither while setting nor while reading.
Here macro definition:
#ifndef DAQmxChk
#define DAQmxChk(fCall) if (DAQmxFailed(daqerr = (fCall))) \
{ line = __LINE__; \
goto Error; } \
else
#endif
Anybody has some suggestion on how to avoid false measurements?
01-26-2010 10:22 AM
Sorry, no solution here, but for what it's worth, I'd agree that it sounds like some kind of signal glitch caused by the other switch contact. I'd also agree that the digital filtering was a good approach for a fix.
You've probably already done more troubleshooting than described in your post, but here are a few random-ish thoughts in hopes something might help.
-Kevin P
01-27-2010 11:14 AM
Hi Kevin, thank you for your response.
Yes, I already made some of the tests you suggested, especially exchanging counters (using ctr3 for the first switch under test and ctr2 for the 2nd), with no success. Unfortunately it's not easy to use completely different counters as several PFIs on board are used for digital I/O (alarms, controls and so on). Since the counter on error was always the first in the scan I tried also to read an unused counter at the very beginning of the reading loop in the hope that for some reason the first reading could be incorrect, but of course this was only an attempt born on my desperation and had no effect at all.
Noise is not so easy to catch with a scope but indeed there is: when the counter reads incorrectly the scope triggers even if I'm not able to see the noise on the screen (too fast? too high? don't know!).
Long story short, I solved my problem by adding some hardware RC filter on the coils of the driving switches, thus avoiding noise to propagate in the system. We are used to put those filters on all switchs in our equipments but for some reason they were missing form this one and I have lost a lot of time on this!
But I am still wondering why digital filtering was not able to bypass the noise: I had progressively enlarged filtering window up to 20 msec so I should be able to see such a wide disturb on the scope screen but I wasn't able to do.
02-18-2010 04:57 AM
As a follow-up on this subject, in case somebody else has similar problems, I am posting here an alternative solution I have designed: under some (not infrequent) conditions, infact, RC filters seem not to have totally eliminated the noise. For these reason, some incorrect reading have left as if the counters have intercepted some slope that stops 2-edge separation counting before it should do. As noted before, built-in digital filtering was unable to eliminate this problem so I have found an alternative method to perform this calculation, using event counting instead of 2-edge separation.
The problem to start and stop counting on different signals and on different slopes was solved by using both an arm start trigger and a pause trigger: the counter starts counting on the first one and stops on the second. Residual noise that can drive a fake slope on the pause trigger has the only effect to stop the count for a while. Nevertheless, the system seemed less sensitive to noise so I ended up commenting out digital filtering on triggers.
This is the code for setting up the system (error checking was removed for clarity):
DAQmxCreateTask ("", &taskHandle);
// Create event counting channel
DAQmxCreateCICountEdgesChan (taskHandle, "Dev1/ctr2", "", DAQmx_Val_Rising, 0, DAQmx_Val_CountUp);
DAQmxSetChanAttribute (taskHandle, "", DAQmx_CI_CountEdges_Term, "/Dev1/20MHzTimeBase", 0);
DAQmxSetChanAttribute (taskHandle, "", DAQmx_CI_CountEdges_ActiveEdge, DAQmx_Val_Rising, 0);
// Digital filtering on trigger signals
// DAQmxSetTrigAttribute (taskHandle, DAQmx_DigEdge_ArmStartTrig_DigFltr_MinPulseWidth, 2e-03);
// DAQmxSetTrigAttribute (taskHandle, DAQmx_DigEdge_ArmStartTrig_DigFltr_Enable, 1);
// DAQmxSetTrigAttribute (taskHandle, DAQmx_DigLvl_PauseTrig_DigFltr_MinPulseWidth, 2e-03);
// DAQmxSetTrigAttribute (taskHandle, DAQmx_DigLvl_PauseTrig_DigFltr_Enable, 1);
// Configure start trigger on a digital input (here I am using counter AUX input, but other PFIs can be used as well)
DAQmxSetTrigAttribute (taskHandle, DAQmx_ArmStartTrig_Type, DAQmx_Val_DigEdge);
DAQmxSetTrigAttribute (taskHandle, DAQmx_DigEdge_ArmStartTrig_Src, "/Dev1/PFI29");
// Configure pause trigger on a digital input (I am using counter GATE input, so no need to configure the source PFI)
DAQmxSetTrigAttribute (taskHandle, DAQmx_PauseTrig_Type, DAQmx_Val_DigLvl);
Slope direction for both triggers can be determined on the fly once the task is created. It can be modified freely on either input, provided the task is not running (in effect in my application I continuously change trigger slopes on both inputs without any problem). The corresponding code is the following:
// Configure start trigger
DAQmxSetTrigAttribute (taskHandle, DAQmx_DigEdge_ArmStartTrig_Edge, DAQmx_Val_Falling);
// Configure pause trigger (here counting is gated on a high level)
DAQmxSetTrigAttribute (taskHandle, DAQmx_DigLvl_PauseTrig_When, DAQmx_Val_Low);
// At this point task can be started
DAQmxStartTask (taskHandle);
As a side effect, I can note that counter count can be queryed while the task is running: this is relevant since it permits me to give to the user a visual representation of the running process that was not possible with 2-edge separation measurement (which returns only the final time once the count has stopped).
Time elapsed during counting can be determined this way:
daqerr = DAQmxReadCounterScalarU32 (taskHandle, 0.01, &data, NULL);
if (daqerr && (daqerr != DAQmxErrorOperationTimedOut)) {
line = __LINE__; goto Error;
}
time = (double)data / (double)20e6;