Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Analog Ouput Update

Is it possible to write to the Analog Output buffer while a continuous generation is being performed?
 
I need to be able to adjust a DC output signal on the PXI-6723, based upon a feedback measurement ( so there is no predefined update pattern ).
 
Currently I have to stop the AO task, write the new data, and restart the task. 
If I do not stop the task I receive the following error:

Error 0xfffcf19c - Some or all of the samples to write could not be written to the buffer yet. More space will free up as samples currently in the buffer are generated.

This process is taking too long, so I am  looking into ways to speed it up.
 
Any ideas?
 
Thanks,
Anson 
0 Kudos
Message 1 of 18
(7,105 Views)
Hello Anson,

I have written an example which I think demonstrates the operation you discussed. I am assuming you are developing in LabVIEW, but if you are using another development environment the same ideas will hold true. I modified one of our example programs to use regeneration to update the data that is generated by writing new data to the memory buffer that is being generated. For a more detailed description of regeneration, you can see the NI-DAQmx Help which you can find by going to your Start menu and selecting All Programs>>National Instruments>>NI-DAQ. Specifically, the help file has a section called Regeneration which states the following:

"Regeneration

Generating the same data more than once is called regeneration. You can configure NI-DAQmx to allow or disallow regeneration by setting the Regeneration Mode attribute/property. By default, NI-DAQmx allows regeneration for sample clock timing and disallows it for handshaking or burst handshaking timing. When regeneration is disallowed, new data must be continuously written to the device.

Allowing Regeneration and Using Onboard Memory

When the Use Only Onboard Memory attribute/property is true, NI-DAQmx transfers data only once to the device and that data is continually regenerated from there. Attempting to write new data to the device after starting the task returns an error. In addition, the amount of data written to the device before staring the task must fit in the onboard memory of the device.

When the Use Only Onboard Memory attribute/property is false, NI-DAQmx continuously transfers data from the host memory buffer to the device even though this data is not changing. Thus, if you write new data to the device after starting the task, that new data is generated and regenerated until you write more new data. This type of regeneration is sometimes called PC memory or user buffer regeneration.

When this attribute/property is false, you can also set the Data Transfer Request Condition attribute/property to specify when to transfer data from the host buffer to the device."

My example is attached and is called Cont Gen Voltage Wfm-Int Clk-Regeneration_Modified.vi. There are more notes in the VI itself regarding each function used, but basically this example takes an update from the user through the Front Panel and writes the value on the analog output. You could easily modify this example to calculate the update based on a formula or equation that better suits your needs. I hope this helps, let us know if you have any other questions.


Matt Anderson

Hardware Services Marketing Manager
National Instruments
Message 2 of 18
(7,082 Views)

Matt,

Thanks for your reply.

I am not using Labview ( I'm using C++ in Visual Studio 6.0 ), so unfortunately I am not able to view your sample.

If I understand the regeneration documentation properly, I should be able to:

  1. Set "Regeneration" =  true
  2. Set "Use Only Onboard Memory" = false

This will result in the device getting constantly updated with the contents of my data buffer, which I can update while the Task is running using the standard write() functions.

Is this correct?

I have some questions about the "UseOnlyOnBrdMem" configuration function ( see declaration below )

DAQmxSetAOUseOnlyOnBrdMem(TaskHandle taskHandle, const char channel[], bool32 data)

The channel[] parameter surprises me!

  1. Do I need to supply the name of the output channel in the task that will be using "user buffered" generation?
  2. What if the task contains multiple channels, do I need to call this function for each channel in the task?
  3. Is it possible to have one channel in the task using "User Buffered" data while the other use "Device Buffered" data?

Thanks,

Anson

 

 

0 Kudos
Message 3 of 18
(7,076 Views)
Hello Anson,

First, let me address your questions:

A) Yes, by enabling regeneration and disabling onboard memory only, you are creating a data buffer in memory which you can update with new data to generate with your device.

B) Regarding the channel parameter questions:
    1. No, you do not need to supply a channel name in the task to be used with this function. I passed NULL as a parameter and my program ran without error.
    2. The AOUseOnlyOnBrdMem property is set for all channels within a task. All the channels in the TaskHandle you pass will be set to the value you select.
    3. No, it is not possible to set one channel in a task to use only onboard memory and then set another channel to another setting.


Though you are not using LabVIEW, the fundamental steps to perform the operation in the above VI will remain the same (this is the beauty of the architecture of the NI-DAQmx driver). Here are the notes from the attached VI with the corresponding C function calls:

Steps:
1. Create an Analog Output Voltage channel.
    - int32 DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);
    - int32 DAQmxCreateAOVoltageChan (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], float64 minVal, float64
     maxVal, int32 units, const char customScaleName[]);

2. Configure the task to automatically regenerate data.
    - int32 __CFUNC DAQmxSetWriteRegenMode(TaskHandle taskHandle, int32 data);

3. Call the DAQmx (Sample Clock) VI Use C function call to set the sample clock rate. Additionally, set the sample mode to Continuous and set the size of the sample buffer. The buffer must contain at least 2 samples to perform continuous generation; however, a larger buffer will prevent data being overwritten when updating the buffer with new samples.
    - int32 DAQmxCfgSampClkTiming (TaskHandle taskHandle, const char source[], float64 rate, int32 activeEdge, int32 sampleMode, uInt64
     sampsPerChanToAcquire);

4. Read the actual sample clock rate (eventually coerced depending on the hardware used).
    - int32 __CFUNC DAQmxGetSampClkRate(TaskHandle taskHandle, float64 *data);

5. Compute the desired waveform, using the buffer size and DC value.
    - not a DAQmx function, any sort of array instantiation should work

6. Write the waveform to the output buffer.
    - int32 DAQmxWriteAnalogF64 (TaskHandle taskHandle, int32 numSampsPerChan, bool32 autoStart, float64 timeout, bool32 dataLayout, float64
     writeArray[], int32 *sampsPerChanWritten, bool32 *reserved);
   
    or

    - int32 DAQmxWriteBinaryI16 (TaskHandle taskHandle, int32 numSampsPerChan, bool32 autoStart, float64 timeout, bool32 dataLayout, int16 writeArray[],
     int32 *sampsPerChanWritten, bool32 *reserved);

    or

    - int32 DAQmxWriteBinaryU16 (TaskHandle taskHandle, int32 numSampsPerChan, bool32 autoStart, float64 timeout, bool32 dataLayout, uInt16 writeArray[],
     int32 *sampsPerChanWritten, bool32 *reserved);

    - depends on whether you are writing scaled or unscaled data and what format you are using for your array

7a. Call the Start VI. This is only needed when the loop is executed for the first time.
    - int32 DAQmxStartTask (TaskHandle taskHandle);

7b. Do nothing.
    - unnecessary in this case

8. Loop continuously until user presses the Stop button. Every iteration computes and writes a new waveform to the buffer.
    - see note on 6 above about which version of the write function to use.

9. Call the Clear Task VI to clear the Task.
    - int32 DAQmxClearTask (TaskHandle taskHandle);

10. Use the popup dialog box to display an error or warning if any.
    - done by using the DAQmxErrChk() with the above function calls

I hope this information is helpful, let me know if you need anything else.

Matt Anderson

Hardware Services Marketing Manager
National Instruments
Message 4 of 18
(7,062 Views)

Matt,

I seem to be unable to configure regeneration and onboard memory usage for my PXI-6723.

Here is the configuration seqence I am performing

  1. DAQmxCreateTask()
  2. DAQmxCreateAOVoltageChan()
  3. DAQmxSetWriteRegenMode()
  4. DAQmxSetDOUseOnlyOnBrdMem()

Steps 3 and 4 are generating the following errors:

3) DAQmxSetWriteRegenMode( DAQmxTaskHandle, 1 );

Error 0xfffcf273 - Requested value is not a supported value for this property.

4) DAQmxSetDOUseOnlyOnBrdMem(DAQmxTaskHandle,  NULL,   0);

Error 0xfffcf0fc - Specified property is not supported by the device or is not applicable to the task.

Any ideas why I am receiving these errors?

Thanks,

Anson

 

0 Kudos
Message 5 of 18
(7,036 Views)
Hello Anson,

1. As noted above, the definition for the function to set regeneration mode is as follows:

    int32 __CFUNC DAQmxSetWriteRegenMode(TaskHandle taskHandle, int32 data);

However, when you examine the documentation, you will find that the data values are not simple booleans, but numerical values which represent different options. The NI-DAQmx C Reference Help contains a section called "Regeneration Mode" which describes these values. I have copied this description below for your reference:



So, if you would like to enable this mode you would actually pass the DAQmx_Val_AllowRegen value (10097) to the function rather than a 1 for true. For your information, you can find the NI-DAQmx C Reference Help by navigating to Start>>All Programs>>National Instruments>>NI-DAQ.


2. The reason you are receiving this error is because you are attempting to set a digital task property for an analog task. You posted that you are using the DAQmxSetDOUseOnlyOnBrdMem(), which is the property to set for a digital operation. You would actually use the DAQmxSetAOUseOnlyOnBrdMem() function to set the property for an analog output operation. Should be a quick change and you should be good to go.


Message Edited by Matt A on 04-07-2008 08:43 AM

Matt Anderson

Hardware Services Marketing Manager
National Instruments
Message 6 of 18
(7,004 Views)

Matt,

Thanks for your patience.  I should have caught those last errors, just overlooked them in my haste to get this resolved.

I have fixed the driver errors I was receiving ( per you directions ), however I am still unable to get this approach to work.

Below is the current Sequence of commands I am executing:

  1. DAQmxCreateTask()
  2. DAQmxCreateAOVoltageChan()
  3. DAQmxSetWriteRegenMode( DAQmxTaskHandle, 10097 );
  4. DAQmxSetAOUseOnlyOnBrdMem(DAQmxTaskHandle,  NULL,   0);
  5. DAQmxCfgSampClkTiming()
  6. DAQmxCfgOutputBuffer() -- I may not need this one anymore
  7. DAQmxWriteAnalogF64()
  8. DAQmxStartTask()

This sequence is working fine, and the first value I write to the task is being generated at the expected output.

After the task is started I am unable to update the output.

  • I've tried updating the data buffer I passed to the task in step 7
    • But the output is not updated.
  • I've tried resending the DAQmxWriteAnalogF64() command
    • I receive the same errors described above when performing the write command on a running task.

Am I missing something?

I thought that configuring the card in this manner would allow me to update the output task ( without stopping the task ) by changing the contents of the buffer supplied in step 7.  Is this not correct?

Thanks for all your help,

Anson

 

0 Kudos
Message 7 of 18
(6,968 Views)

- UPDATE -

Matt,

I increased my buffer size which resolved the failure I was receiving when executing the Write() function.  So now there are no driver failures, but there is still a problem.

When I execute the Write() command, I receive no errors and the function indicates that the correct number of samples where written.  I do not however see any change at the output pin.  Also, after a few minutes the output drops to zero.

Here is the sequence:

  1. Create and configure the Task as we have discussed above
  2. Write a single sample of 2 (2 VDC)
  3. Start the task
  4. Attempt to write a new sample to the buffer (3 VDC)
    1. No failures generated but the output stays at 2 VDC.
  5. The output eventually drops to 0 VDC ( with no input from me)

Any ideas why I would see this?

Thanks again,

Anson

0 Kudos
Message 8 of 18
(6,947 Views)
Hello Anson,

That behavior does seem strange. My LabVIEW code worked well and did not report any errors. I passed the following values to my sample clock function::

rate (Sample Clock Rate): 20000
sampsPerChanToAcquire (Buffer Size): 250

I specifically chose this combination of sample rate and buffer size so that I would eliminate errors with old data being mixed with new, but also so that updates to my voltage would take no longer than one cycle through the buffer (1/20000 sec/Sample * 250 Samples= 0.0125 sec) to update the output. What values are you using in your task? What happens if you try this combination of sample rate and buffer size? Rather than writing a single sample of 2 and then 3 to the buffer, you could try writing an array of 250 elements (all 2s) to the buffer and then another 250 element array of all 3s to the buffer. I'm not sure that that would address your question specifically, but that is the method I am using and it seems to work for me. Let me know how things go.

Matt Anderson

Hardware Services Marketing Manager
National Instruments
0 Kudos
Message 9 of 18
(6,908 Views)
Hello Matt,

I downloaded your vi and an memory underflow error occured. I am using NI DAQPad-6015 with DAQmx on Windows Xp.

I have been searching everywhere for a solution to my current problem with continuous AO update, and this thread is the closest thing I can find. Allow me to explain what I am trying to achieve.

I have a 21 kHz digital signal.
I want to use that as a trigger for an anolog output of an step function.
The tricky thing (and the dilemma I am having) is on each tick, the output should step up once, and then after a couple ticks, the output returns to 0. So the pattern is like 0, 3, 6, 9, 0, 3, 6, 9 and so on. I have attached my vi here. The problem, as you will see, is that the "write" is inside a while loop and therefore not sync up with the clock. Furthremore, the outputing frequency is much slower than 21kHz and is unpredictable. Could you take a look and provide me with some pointers?

Thanks,
Vectrix
0 Kudos
Message 10 of 18
(6,663 Views)