10-06-2015 09:17 AM
I am trying to create a digital-only task which will do digital reads at a hardware-timed rate using a PCIe-6509. However, when I try to set the task timing as follows (which works on a PCIe-6509), I get the following error:
Requested value is not a supported value for this property. The property value may be invalid because it conflicts with another property.
Property: NationalInstruments.DAQmx.Timing.SampleTimingType
Requested Value: NationalInstruments.DAQmx.SampleTimingType.SampleClock
Possible Values: NationalInstruments.DAQmx.SampleTimingType.OnDemand, NationalInstruments.DAQmx.SampleTimingType.ChangeDetection
Task Name: DigitalInputTask
Status Code: -200077
The relevant parts of my code are:
public class DigitalInputReader : IDisposable
{
public DigitalInputReader() { dataReadyHandler = new System.AsyncCallback(DataReadyEventHandler); daqmxTask = new DigitalInputTask(); daqmxTask.Configure(Globals.NI); daqmxTask.Control(TaskAction.Verify); daqmxTask.Control(TaskAction.Commit); daqmxReader = new DigitalMultiChannelReader(daqmxTask.Stream); } public class DigitalInputTask : Task { public DigitalInputTask() : base("DigitalInputTask") { } public virtual void Configure(NiConfiguration niConfig) { for (int i = 0; i <= niConfig.DigitalInputs.Count - 1; i++) { string physicalChannelName = niConfig.Device + "/port" + niConfig.DigitalInputs[i].Port.ToString() + "/line" + niConfig.DigitalInputs[i].Channel.ToString(); string nameToAssignToChannel = niConfig.DigitalInputs[i].Name; DIChannel ch = this.DIChannels.CreateChannel(physicalChannelName, nameToAssignToChannel, ChannelLineGrouping.OneChannelForEachLine); ch.InvertLines = niConfig.DigitalInputs[i].InvertLines; } var signalSource = ""; this.Timing.ConfigureSampleClock(signalSource, Globals.MachineSettings.SampleRate, SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples);// Globals.MachineSettings.SamplesPerChannel); } }
That last call to Task.Timing.ConfigureSampleClock is what throws the errors.
Of the available options, neither SampleTimingType.OnDemand or NationalInstruments.DAQmx.SampleTimingType.ChangeDetection provide the same precisely timed calls that I'm used to with analog input interrupts.
How can this be done in a digital task? I mean, it looks like I could set up another task to do hardware-timed output of a clock signal and use the ChangeDetection timing mode, but that seems a little convoluted for what should be easy to do. What am I missing?
Solved! Go to Solution.
10-06-2015 10:13 AM
I just noticed: Visual Studio Intellisense (and the NI help) seem to indicate that the fourth parameter to ConfigureSampleClock should be of type "SampleQuantityMode", and that SampleQuantityMode has three members: ContinuousSamples, FiniteSamples, and HardwareTimedSinglePoint
However, the error message suggests that the fourth parameter should be of type "SampleTimingType", with possible values of OnDemand and ChangeDetection. When I enter
this.Timing.ConfigureSampleClock(signalSource, Globals.MachineSettings.SampleRate, SampleClockActiveEdge.Rising, SampleTimingType.OnDemand);
which should (if the error message is accurate) work at least once, or I can call it (temporarily, while we're figuring this out) from a low-accuracy software timer, I get compilation errors:
The best overloaded method match for 'NationalInstruments.DAQmx.Timing.ConfigureSampleClock(string, double, NationalInstruments.DAQmx.SampleClockActiveEdge, NationalInstruments.DAQmx.SampleQuantityMode)' has some invalid arguments
and
Argument 4: cannot convert from 'NationalInstruments.DAQmx.SampleTimingType' to 'NationalInstruments.DAQmx.SampleQuantityMode'
Casting it to (SampleQuantityMode) produces errors that the various other SampleQuantityModes with values equal to their respective SampleTimingTypes are also invalid.
It looks more like this is a real bug than the configuration mistake I initially expected it to be!
10-14-2015 07:07 AM
Update: I figured it out. You can't call ConfigureSampleClock when the digital input card is a 650x device, because those devices don't have automated sample clocks at all. They are configured to run in finite samples mode by default. You must do all sample clocking with these devices in software.
Be careful, though, because .NET timers only guarantee that they will tick no faster than their programmed interval. In practice, they're typically 5-10 ms slow per tick. This means that if you intended to read samples every 100 ms by sample clock, you'd end up reading samples every 108 ms. Any counters based on the elapsed time and sample count would be way off after just a few seconds of this.
Instead, you need to do one of four things: Write a doggone driver that runs in ring 0 and interfaces with the PCIe card at the required interval (that's on NI, not you, in practice), tolerate the clock skew, use a multimedia timer like an audio or video interrupt that's more likely to respond at the correct interval, or, my solution, use an accurate clock to adjust the timer interval. I wrote the following timer code:
var CorrectiveStopwatch = new System.Diagnostics.Stopwatch();
var CorrectedTimer = new System.Timers.Timer()
{
Interval = targetInterval,
AutoReset = true,
};
CorrectedTimer.Elapsed += (o, e) =>
{
var actualMilliseconds = ;
// Adjust the next tick so that it's accurate
// EG: Stopwatch says we're at 2015 ms, we should be at 2000 ms
// 2000 + 100 - 2015 = 85 and should trigger at the right time
var newInterval = StopwatchCorrectedElapsedMilliseconds +
targetInterval -
CorrectiveStopwatch.ElapsedMilliseconds;
// If we're over 1 target interval too slow, trigger ASAP!
if (newInterval <= 0)
{
newInterval = 1;
}
CorrectedTimer.Interval = newInterval;
StopwatchCorrectedElapsedMilliseconds += targetInterval;
};
I hope that helps someone.