Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

how to gracefully stop a continuous analog output using DAQmx C calls

Hello, I have been using a USB 6216 (and also have a PCIe-6259).  I am generating continuous analog outputs.  I would like to be able to gracefully stop the generation and have the analog output return to a default value.   I can almost do what I would like by stopping the original task, clearing it, and then creating and executing a second task to set the scalar value using DAQmxWriteAnalogF64().

 

However, there is about a 25ms delay between the end of the continuous periodic output and the new scalar value.  During this delay, the output of the daq is latched at the last generated value.

 

I would like the switch to be without this delay.

 

Is there a typical pattern or best practice for making this sort of switch using DAQmx C calls?

 

Many thanks

 

-Chris

0 Kudos
Message 1 of 7
(7,303 Views)

I would be happy to post my code if that is helpful.  I would also note that the delay in switching to the steady-state value is much shorter on the PCIe-6259. It's only about 2-3 ms with the same code.  This acceptible for most of our applications.

 

Here's an outline of what I'm doing. I'll edit out most of the parameters because the C looks messy

 

int32 taskHandle=0; int32 stopTask=0;

 

/* to start the task, I call: */

DAQmxCreateTask()

DAQmxCreateAOVoltageChan()

DAQmxCfgSampClkTiming ()

 

DAQmxWriteAnalogF64() //send the periodic waveform over to the DAQ

DAQmxStartTask(taskHandle)

// the DAQ nicely outputs a waveform until I press a button which in my gui triggers a call to a function which runs:

// stop the running task

DAQmxStopTask(taskHandle);

DAQmxClearTask(taskHandle)

// create the default output task for steady state values

DAQmxCreateTask(stopTask);

 DAQmxCreateAOVoltageChan();

DAQmxWriteAnalogF64() // write new "default" values

// eventually stop and clear the "default" task

 

I found that if I didn't clear the original task, but instead stopped it and simply wrote the new default values using the original task, the delay/latency dropped dramatically. (<1ms)

 

I realize that I am missing knowledge about how the DAQ handles tasks.  Can continuous output tasks be written to while still runnning?

 

0 Kudos
Message 2 of 7
(7,299 Views)

Continuous tasks can be written to while running.  The best method would be to not stop the task, but rather call DAQmxWriteAnalogF64 again with data that will start from the current point in your previous waveform and ramp down to your predetermined value, then call stop and clear.

 

Regards,

Seth B.
Principal Test Engineer | National Instruments
Certified LabVIEW Architect
Certified TestStand Architect
0 Kudos
Message 3 of 7
(7,286 Views)

Thank you Seth for your help,

I have greatly shortened the time it takes to transition by using the same task to do the writing.  However, I have been unable to actually implement the method you suggested of writing  to the still-running task and to bring down the value.  I begin by writing to two channels, 500 samples per channel in continuous sampling mode at 1000Hz using the internal clock.   The task runs and issues a periodic waveform as expected.  If in my task stopping code I write another 500 samples per channel (1000 total) of my DC value that I would like to hold at, it will often appear to work.   That is the output will switch to the new DC value and I can stop the task.

 

Intermittently, it will not switch over.  I suspect it has something to do with where in the buffer the values are being written and that what I'm getting is some sort of glitching.  The NIDAQmx help gives some mention of these issues and I have looked at the reference for the relativeTo property and the buffer offset.   It's still unclear to me how the buffer is setup and used and what relation there is to values being output versus the values being written (or DMA'd) to the on-board buffer. 

 

I don't see any more examples or more detailed discussion.  Can you, or anyone else point me to a reference?

0 Kudos
Message 4 of 7
(7,230 Views)

Hi Chris,

 

I think you are correct that the issue is with the exact point that the buffer is being written to.  In an anlog output task there are two things that one might consider a "buffer":

1.  There is a buffer in your computer's RAM that serves as the "Output Buffer".  The default size of this should be the 500 samples that you are first writing in your task, but it can also be much larger if so desired. When you are calling DAQmx Write this is the buffer that you are writing to. 

 

2.  There is an on-board FIFO that holds the data on the board before it is generated.  This buffer has a fixed size depending on the hardware used--on the boards you mentioned this FIFO is 8191 samples shared between all AO channels.  DAQmx will calculate how much of the buffer to fill based off of the clock rate and the hardware you are using (USB vs. PCI etc.).

 

During the generation process, the data is transferred periodically from the output buffer in RAM to the on-board FIFO--the mechanism for doing so is quite different between USB and PCI/PCIe to compensate for the higher latency (observed in your first post) of USB Bulk transfers.

 

What I would guess is happening is that you are stopping your task in software immediately after writing the 0s.  Depending on how much data is left to generate from the on-board FIFO, the 0s may or may not reach the actual output before the task is killed in software.

 

You might try inserting a pause into your code between when you write the 0s and when you stop the DAQmx task to make sure the new data has propagated all the way to the output.  From what I can tell this would explain the behavior you are seeing.

 

 

The "glitching" you mentioned occurs when you are writing to and reading from the buffer at the same time.  During glitching, your output may be a mix of old and new data (some samples may be updated before they are transferred to the on-board FIFO and some may not be).  The recommended way to avoid this is to disable regeneration, but you will have to continuously write new data to the buffer as it is being generated.  This example shows how one might do this in the DAQmx C API.

 

 

P.S. sorry if the bold text seems rude, I wanted to make sure my actual suggestion stood out from all of the other background information.

Message Edited by John P on 12-01-2009 06:54 PM
John Passiak
0 Kudos
Message 5 of 7
(7,209 Views)

Hi Seth,

With your help, I'm now getting perfect graceful stops.  I had previously tried adding delays after WriteAnalogF64, but it looks like they weren't long enough to get the desired effect.  When I was clocking the output at 1kHz, delays up to 5 seconds weren't preventing incidents of leaving the output in the undesired high state.  Given the info that the onboard buffer is around 8192 samples long, I now time the delay so that there is time for the whole buffer to cycle through, e.g. delay  = round(8192.0/samplerate+0.5) + 0.010 sec .  For testing purposes, I increased the sample rate to 8kHz so the there was less time spent sleeping during the delay.

 

Is there a way to query the hardware to get the size of the onboard buffer.  I would assume that in regeneration mode, the write ends up taking the contents of the host outputbuffer and creates one or more duplicates of it in the onboard buffer.  

 

I have read through the nonregenerative approach code that you sent. Thanks for that as well. I will try that approach later.

 

I would still like to have book or manual to go from that discusses these issues on the NI boards. I am somewhat used to programming microcontrollers where I can  set up   the DMA from host to device and I feel like I actually know what's going on in terms of which sample pointer is getting updated etc.

 

I do appreciate all the documentation that is available, but these sort of details seem hard for me to find. 

0 Kudos
Message 6 of 7
(7,186 Views)

Hi Chris,

 

The function to query the size of the on-board FIFO (for output) is:

DAQmxGetBufOutputOnbrdBufSize(TaskHandle taskHandle, uInt32 *data);

 

 

You are correct that in regeneration mode the Output Buffer (in PC Memory) is going to create duplicates in the on-board memory.  This is all done behind the scenes by DAQmx.

 

 

The DAQmx Help that is installed with the driver is going to be your best resource for consolidated information on how DAQmx operates.  In particular, the section on Buffering addresses some of these issues:

DAQmx_Help.png

 

 

The DAQmx help isn't going to be as low-level as you are probably used to when performing register-level programming on a microcontroller (we do have a driver development kit available for many of our multifunction DAQ products for those interested in low-level control but I would recommend sticking with DAQmx for 99.9% of applications).  DAQmx handles the low-level details for you so you don't typically have to worry about things like data transfers which can be rather complicated.

 

 

In any regard, if the 8 second delay is too much there are some tweaks we can make to reduce this (setting Write Position, Data Transfer Request Condition, etc.).  However, the easiest way to flush out the on-board buffer faster is to simply increase the sample rate.

 

Also, a Device Reset will set the output back to 0V, so if you aren't running any other tasks this might be an option as well (DAQmxResetDevice).

 

 

Best Regards,

John

John Passiak
0 Kudos
Message 7 of 7
(7,170 Views)