Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Analog Output: some devices need 3 of the same value to hold last value written in idle state

This post discusses 2 problems:
1. Last value not held on certain devices
2. DAQmxGetWriteTotalSampPerChanGenerated() does not return correct number.

Truth is if #1 gets fixed I can live with #2.

For devices that do not support DAQmxSetAOIdleOutputBehavior() I expected that the device would hold the last value written.
This seems to be true for the PCI-6014 and USB-6211.
But with other devices like PCI-6251 and PCI-6711 I need to write 3 of the same value in order for the value to be held.

For example, with a sample rate of 1kHZ I write 1000 samples to channel 0 of the device.
If I write 999 samples of 0V followed by 1 sample of 2V I want to see 2V held on the scope.
With PCI-6014 and USB-6211 this is indeed the case. It just works as expected.

With PCI-6251 and PCI-6711 the 2V value is held ONLY when I write 3 2V samples.
So with PCI-6251 and PCI-6711 I write 997 samples of 0V followed by 3 samples of 2V and my scope will show the idle state of the device holding at 2V.
With just 1 or 2 2V samples the value is not held.
Note that I always write just 1000 samples, never more than that.

I really need to find out how to get the idle state of these devices to hold the last value without having to repeat it. This is my major problem.

A secondary problem is that I don't think that DAQmxGetWriteTotalSampPerChanGenerated() is working.
I suspected that not all the data from the buffer may be transmitted to the device, so I added a call to DAQmxGetWriteTotalSampPerChanGenerated() but this call never shows me that I really wrote all 1000 samples.  For the USB-6211 it shows that I wrote 1002 samples! In all other cases it shows I wrote only 825 or so samples.
Again, I write 1000 samples in both cases. Never more, never less.

I am attaching a very pared down program that shows this issue.
It is based on C:\Program Files\National Instruments\NI-DAQ\Examples\DAQmx ANSI C\Analog Out\Generate Voltage\Volt Update
so you can compile it with those project files. I am using Visual Studio 2005.

Run it by specifying the device ID and number of 2V samples to write at the end.
Example:

VC_VoltUpdate.exe Dev4 1

will write 999 samples of 0V then 1 2V sample to Dev4.
If you have AO0 of Dev4 hooked up to your scope you'll see the 0V followed by the jump to 2V only for the USB-6211 and PCI-6014.
If you're using a PCI-6251, PCI-6711 and I suspect some others you will need to specify
 
VC_VoltUpdate.exe Dev2 3

to see the 2V held.

Here is output that shows that DAQmxGetWriteTotalSampPerChanGenerated() never shows us 1000 samples, even though that's all we wrote.

R:\NI Example Code\G425667_OutOfDataMode_Hold_Samples\Debug>VC_VoltUpdate.exe Dev4 1
Writing stream of 0V samples followed by 1 2V sample(s) to channel Dev4/ao0 (device PCI-6014) at sample rate 1000.00
Samples to write = 1000, Writing 64 samples
Samples to write =  936, Writing 64 samples
Samples to write =  872, Writing 64 samples
Samples to write =  808, Writing 64 samples
Samples to write =  744, Writing 64 samples
Samples to write =  680, Writing 64 samples
Samples to write =  616, Writing 64 samples
Samples to write =  552, Writing 64 samples
Samples to write =  488, Writing 64 samples
Samples to write =  424, Writing 64 samples
Samples to write =  360, Writing 64 samples
Samples to write =  296, Writing 64 samples
Samples to write =  232, Writing 64 samples
Samples to write =  168, Writing 64 samples
Samples to write =  104, Writing 64 samples
Samples to write =   40, Writing 40 samples
SamplesGenerated: 826
SamplesGenerated: 826
SamplesGenerated: 826
End of program, press Enter key to quit


R:\NI Example Code\G425667_OutOfDataMode_Hold_Samples\Debug>VC_VoltUpdate.exe Dev5 1
Writing stream of 0V samples followed by 1 2V sample(s) to channel Dev5/ao0 (device USB-6211) at sample rate 1000.00
Samples to write = 1000, Writing 64 samples
Samples to write =  936, Writing 64 samples
Samples to write =  872, Writing 64 samples
Samples to write =  808, Writing 64 samples
Samples to write =  744, Writing 64 samples
Samples to write =  680, Writing 64 samples
Samples to write =  616, Writing 64 samples
Samples to write =  552, Writing 64 samples
Samples to write =  488, Writing 64 samples
Samples to write =  424, Writing 64 samples
Samples to write =  360, Writing 64 samples
Samples to write =  296, Writing 64 samples
Samples to write =  232, Writing 64 samples
Samples to write =  168, Writing 64 samples
Samples to write =  104, Writing 64 samples
Samples to write =   40, Writing 40 samples
SamplesGenerated: 347
SamplesGenerated: 632
SamplesGenerated: 916
SamplesGenerated: 1002
SamplesGenerated: 1002
End of program, press Enter key to quit


R:\NI Example Code\G425667_OutOfDataMode_Hold_Samples\Debug>VC_VoltUpdate.exe Dev2 1
Writing stream of 0V samples followed by 1 2V sample(s) to channel Dev2/ao0 (device PCI-6251) at sample rate 1000.00
Samples to write = 1000, Writing 64 samples
Samples to write =  936, Writing 64 samples
Samples to write =  872, Writing 64 samples
Samples to write =  808, Writing 64 samples
Samples to write =  744, Writing 64 samples
Samples to write =  680, Writing 64 samples
Samples to write =  616, Writing 64 samples
Samples to write =  552, Writing 64 samples
Samples to write =  488, Writing 64 samples
Samples to write =  424, Writing 64 samples
Samples to write =  360, Writing 64 samples
Samples to write =  296, Writing 64 samples
Samples to write =  232, Writing 64 samples
Samples to write =  168, Writing 64 samples
Samples to write =  104, Writing 64 samples
Samples to write =   40, Writing 40 samples
SamplesGenerated: 825
SamplesGenerated: 825
SamplesGenerated: 825
End of program, press Enter key to quit
Sherryl Radbil
Data Acquisition Engineer
The MathWorks
0 Kudos
Message 1 of 5
(3,546 Views)
Hi Sradbil!

I recreated your c example to LabVIEW and gave it a shot (It is saved for LabVIEW 8.5, if anyone would like it in a previous version, let me know!) with a 6259 (which should be pretty much the same as your 6251).

I am seeing the same issues, however, I am also getting an error when polling "DAQmxIsTaskDone" in a loop.  Error -200290, "The generation has stopped to prevent the regeneration of old samples.  Your application was unable to write samples to the background buffer fast enough to prevent old samples from being regenerated."  This actually makes a bunch of sense.  What is happening is follows:

First off, your task is continuous so your task will never be done.  That polling loop should run all 10 times or until we get an error.  Now lets take a look at what is happening in the buffer.  You have set up a 512 sample buffer.  That data is being pulled from the PC and pushed into the device's FIFO.  As that FIFO empties we pull more data from the PC and put it in the FIFO.  At some point we have transferred enough data to the FIFO such that there is enough room in the FIFO that would require us pushing more than the 1000 samples you wrote.  At that point, the buffering code realizes that to fill more of the FIFO it would need to repeat some of the samples since you stopped writing to the buffer, but you specifically told it not to regenerate data.  At this point we get error -200290 that I described above.  However, the device actually hasn't finished writing the data we DID put into the FIFO, but since we got a fatal error we kill the task anyways.  Therefore, the amount of samples generated will be some number less than 1000 and greater than or equal to what we actually ended up putting into the FIFO before recognizing the error.

How do we fix it?  The simplest solution is making your task Finite.  It appears you only wanted to generate 1000 samples anyways, so that seems like a perfect case for a Finite Task.  I know you said this was a simplified solution, so it may not be possible to make the task Finite in your real application.  If you can describe what you're trying to do perhaps somebody can help you fix it in your actual application.

Thanks!
Zach




Message Edited by Zach Hindes on 06-04-2008 10:24 AM
------
Zach Hindes
NI R&D
Message 2 of 5
(3,524 Views)

Hello sradbil,

I ran your code and was able to confirm that the behavior you described is what actually takes place. After doing some

experimenting and tweeking of your code, I think that I have found the problem.  I discovered that if you configure the

sample clock for finite samples, the analog output channel retains the correct voltage level if you only write the desired

level to the last or 1000th sample.  Below, you'll find how I modified your code.

 

// Configure the generation and commit the task.

DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,

"", rate, DAQmx_Val_RisingSlope, DAQmx_Val_FiniteSamps, 1000));

DAQmxErrChk (DAQmxTaskControl(taskHandle, DAQmx_Val_Task_Commit));

 

Best wishes,

Wallace F.

National Instruments
Applications Engineer
0 Kudos
Message 3 of 5
(3,490 Views)
Zach and Wallace - many, many thanks for taking the time to help me. I've learned a lot from your posts.

As Zach surmised, the way our app is set up we must do a continuous generation (we allow the user to keep queuing new data to generate even after we've started) so that when we call DAQmxCfgSampClkTiming() we don't know how many samples we'll really put out.

Your answers got me thinking and I found that since our app was first written with NI-DAQmx 8.0 a new call was added:

int32 __CFUNC DAQmxSetWriteNextWriteIsLast(TaskHandle taskHandle, bool32 data);

Description from NI-DAQmx C Reference:
Specifies that the next samples written are the last samples you want to generate. Use this property when performing continuous generation to prevent underflow errors after writing the last sample. Regeneration Mode must be DAQmx_Val_DoNotAllowRegen to use  this property.

I thought I'd found my solution since this is a continuous generation and regeneration mode is set to DAQmx_Val_DoNotAllowRegen.
But when I add these lines:

        // If this will be our last buffer call DAQmxSetWriteNextWriteIsLast
        if ( (countOfSampsWritten+samplesToWrite) == numSamplesWanted)
        {
            error = DAQmxSetWriteNextWriteIsLast(taskHandle, 1);    // Receive -200452 DAQmxErrorAttributeNotSupportedInTaskContext
            printf("DAQmxSetWriteNextWriteIsLast returned %d\n", error);
        }

right before my call to DAQmxWriteAnalogF64() in the original program I posted I get the error:

-200452 DAQmxErrorAttributeNotSupportedInTaskContext

The help states that we need a continuous generation and No Regeneration.
I have both.
So why is this not supported in the task context.

I'm attaching the modified program with those few lines added.

Any additional insight is appreciated.


Sherryl Radbil
Data Acquisition Engineer
The MathWorks
0 Kudos
Message 4 of 5
(3,471 Views)
Hi,
 
As the error message alluded to, DAQmxSetWriteNextWriteIsLast() is not supported for M-Series. If you want the user to be able to que up an undetermined amount of data with nonregeneration, then the easiest way is to perform a normal nonregeneration task and ignore the specific buffer underflow error when the user stops writing.
 
Cheers,
Andrew S 
0 Kudos
Message 5 of 5
(3,464 Views)