Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

DAQmxWriteBinaryI16 only changes on half-buffer cycles

I need to dynamically change a portion of a continuously generated waveform while it is being generated. I can do this by making a call to DAQmxWriteBinaryI16 for example. I notice a half-buffer type of behavior though. If I'm changing a part of the first half of the waveform and the waveform is currently generating the first part, then I do not observe that update until the next cycle of the waveform, even if I write the new part before the waveform gets to it.

For example, the total waveform has 1000 points. I want to change points 300 to 350. The waveform is currently at point 50. I make the software call to change points 400-450 when the waveform is at point 50. I do not see the changed points when it pa
ses through 300-350. The waveform goes through 300 to 350 and generates the old existing points, continues on to 1000, then regenerates again around to points 300-350. Then I see the new points. I am observing this on an oscilloscope generating a ramp at slow rates.

If I make the change when the waveform is at point 400 or beyond, I see the change take place on the next iteration around to 300-350.

Same thing happens trying to change a part of the second half-cycle.

The M Series Help > Analog Output > Analog Output Data Generation Methods > Buffered > states : "Regeneration is the repetition of the data that is already in the buffer. Standard regeneration is when data from the PC buffer is continually downloaded to the FIFO to be written out. New data can be written to the PC buffer at any time without disrupting the output."

From what I observe, while it can be written to the buffer at any time, it does not actually change until the next half-buffer. I recall the old N
IDAQ had half-buffer parameters. Is there any way around this issue with DAQmx ?
This is observed using a PCI-MIO-16E-4 board with programmed with Delphi if that matters.
0 Kudos
Message 1 of 5
(3,899 Views)
Hello,
This sounds like expected behavior. The buffers are working like a bucket with you filling from the top and the FIFO on the DAQ board draining through a hose from the bottom. Once a buffer has been sent to the FIFO from the bucket, it has to finish writing that buffer out before it can be updated with a new set of points from your bucket.
In essence, you are writing data to one buffer, and then it is sent to the FIFO as a complete set of points to output. Again, that means there are 2 buffers. When you use the "DAQmxWriteBinaryl16" function, you are writing to the first of 2 buffers.

I referenced the E-series help manual since the PCI-MIO-16E-4 is an E-series device. However, the M-series help says the same thing.
The help says:
"In a bu
ffered generation, data is moved from a PC buffer to the DAQ device's onboard FIFO using DMA or interrupts before it is written to the DACs one sample at a time. Buffered generations typically allow for much faster transfer rates than non-buffered generations because data is moved in large blocks, rather than one point at a time."

This would further explain this situation because the data is transferred to the FIFO buffer on the board in large chunks.

Nicholas C
National Instruments
Applications Engineering
0 Kudos
Message 2 of 5
(3,899 Views)
I'm using a waveform with 1,000,000 points, much larger than the board's on-board FIFO. So the entire half-buffer is not being sent at one time.

Upon further investigation into this behavior, it appears that if the waveform is currently generating any part of the portion you wish to change, it does not make that change until the next iteration, irrespective of any half-buffer issues. For example, assume the portion between points 200,000 and 800,000 of a 1,000,000 point waveform are to be changed. Note this crosses the half-buffer boundry. If the call to DAQmxWriteRaw is made when the waveform is at point 150,000, the entire changed portion is observed in the current iteration. It takes approximately 20 msec to complete the DAQmxWriteRaw call. If th
e call to DAQmxWriteRaw is made when the waveform is at point 300,000, none of the changed portion is observed until the next iteration, not even the portion after the half-buffer (points 500,000 to 800,000). It takes hundreds of msec to complete the DAQmxWriteRaw call. The waveform clock rate was 500kHz or 2 sec total duration. If the call to DAQmxWriteRaw is made when the waveform is at point 600,000, none of the changed portion is observed until the next iteration. It takes less time to complete the DAQmxWriteRaw call than making the call when at point 300,000. So it appears DAQmx analyzes where it currently is in the waveform cycle and waits until it is not generating any of the range to be changed and only then changes its internal memory buffer over the desired portion of the waveform data.

So it is possible to change part of the half-buffer currently being generated, as long as no part of the portion to be changed is currently being generated.
0 Kudos
Message 3 of 5
(3,899 Views)
Your observations on the behavior of the driver are correct. If you are trying to update data in the buffer that is in the process of being transferred down to the device, the driver will hold off updating the data until after it has been sent to the device. This is intentional and meant to prevent glitches in the data stream where the write operation blasts over data that is currently being transferred to the device. For more information on this, see the Key NI-DAQmx Concepts->Buffering->Glitching section in the NI-DAQmx Help. The net result is you end up waiting one more buffer generation before your new data gets output. While it is possible to do what you're asking, there are a couple of things to keep in mind.

First, there are generally two models for performing buffered generations. In the first model, regeneration of data from the buffer is disallowed and you must always write new data before it is transferred to the device. If you fail to write new data before the device requests more data, an error is thrown and the generation stops. In the second model, regeneration of data from the buffer is allowed and you can update data in the buffer at any time without receiving an error. This is the default behavior and is controlled through the Regeneration Mode attribute in the DAQmx Write Property Node. From your description, it sounds like this is the model you are trying to use.

Second, with every buffered generation there is a read and write pointer that is maintained within the buffer by the driver. The write pointer is where the next write to the buffer will occur, and the read pointer is where data is being read from the buffer and transferred to the device. The read pointer is automatically incremented by the driver as data is transferred to the device. The write pointer is incremented each time you write new data to the buffer. The position of each pointer is a virtual position that increases towards infinity throughout time, and the read pointer will always lag the write pointer by at most one buffer. This means for generations where data regeneration from the buffer is allowed, the driver will automatically increment the write pointer by one buffer if no new data is written and the read pointer catches the write pointer. To determine the current location of the pointers in the buffer, you can query the Current Write Position, Space Available In Buffer, and Total Samples Per Channel Generated attributes in the DAQmx Write property node. The Current Write Position tells you the position of the write pointer, and the Space Available In Buffer attribute indicates how much data can be written to the buffer without the write call having to block and wait for more room to become available in the buffer. The Total Samples Per Channel Generated attribute tells you how much data has actually been generated from the device on the I/O connector. To calculate the read position you can then use the following formula: Read Position = Current Write Position - (Buffer Size - Space Available In Buffer). With these pieces of information, you can then use the Relative To and Offset attributes in the DAQmx Write property node to move the write pointer within the buffer and update any piece of the buffer required by your application.

Since I don't know the requirements of how you need to update your buffer, I'm trying to answer your question by giving a broad low level summary of how buffered generations work. If this still doesn't help, let me know what your requirements are and I might be able to provide a more targeted solution.
Message 4 of 5
(3,899 Views)

I am struggling with the same problem...

 

I use NI-DAQmx analog output with Buffer Regeneration and I would like to avoid the automatic waiting that the the DAQmxWrite performs when the write pointer is less than one buffer size ahead of the read pointer (which it does to avoid glitching). Is there any way to switch that waiting off? I would like to update all the sample values in the buffer as fast as possible and I don't care whether glitching does occur or not. My program has a multi-loop framework with message queues and if there is waiting during the DAQmx write operation the corresponding messages accumulate in the message queue, thereby blocking smooth user interaction.

 

Thanks a lot in advance for any hints!

0 Kudos
Message 5 of 5
(3,377 Views)