NI DAQ with both digital and analog input and output modules. Errors: underflow, trigger timestamp not received, DAC conversion could not complete, buffer

36 views (last 30 days)
My primary goal is to use the recommended approach for using a daq object to read/write in the background so as to not affect the timing of the control loop happening in the foreground.
What I’ve tried:
  • I created a control matrix, u, in my main function, and then started a while loop for the duration of the controlled operation, and then have two separate if statements (one for writing to the daq and one for reading) within that while loop whose conditions are time dependent to manage the timing of read/write operations. I would then overwrite certain rows of the control matrix to affect control commands. Here I used start(daq_obj, “repeatoutput”)
  • Result: The timing of the loops have to be strictly controlled and are very dependent on anything else happening in the while loop, e.g. updating the commanded outputs from the controller, how much I’m plotting each time through the loop, and whether the main loop needs to call additional code, if any abnormal conditions are found in any of the 44 parameters collected in the “read” portion of the loop. Ultimately, I could not reliably run the system using this method, e.g. I would make repeated runs without changing anything and sometimes it worked fine and othertimes, in a seemingly quite random way, I would get errors like, “Output underflow event: last valid scan was number x”, or “Trigger timestamp not received.”
  • In this method, when I created the daq object, I gave function handles to the ScansAvailableFcn (read_stuff.m) and ScansRequiredFcn (load_more_data.m). I created 2 sec of control parameters (a 2x11 matrix of doubles) (1Hz) and used preload(daq_obj, u); start(daq_obj, ‘Continuous’). With this method, as I understand it, the daq creates a listener for the daq object’s input buffer event ‘ElementsAvailable’. It then runs my read_stuff.m, which uses read(daq_obj, ‘all’, ‘outputformat’, ‘matrix’) to read data. This is the data I was saying I could see within the function’s workspace using a breakpoint or printing to the cmd window. To get the data, I’ve tried saving it to the preexisting daq object’s UserData field. I’ve tried saving it to a .mat file and writing it to a .txt file and each method failed.
  • Result: The 1x44 vector of data from read would show up empty in the UserData field, and the .mat and .txt files would be empty. [Actually, the .mat was prepopulated with [7;7] (random), and after a run it would be empty.]
  • I then tried creating a structure in daq_obj.UserData field with 46 fields and populating 44 of them with the elements of the 1x44 vector, and one Boolean “status” (when I changed from false to true if the object was written to) and one double “reads” (to count how many times data was read and the object was written to).
  • Result: The “status” and “reads” fields where written to and would show as much back in my main function. Excellent, but writing the actual data fails. “Warning: Error occurred while executing the listener callback for event ElementsAvailable defined for class daq.Buffer: Index exceeds the number of array elements (44).”
  • I tried using assignin/evalin as described below, but
  • Result: this provided an empty matrix in the mat file.
Let’s see…
  1. Using readwrite errors out telling me to use write then read, separately.
  2. Using read and write separately errors out telling me to use readwrite.
  3. My belief is this error occurs when the timing of the reads and writes is incorrect. Thus I looked into the daq's callbacks, because the reads and writes occur on demand.
  • Using read in the daq’s ScansAvailable callback and write in the daq’s ScansRequired callback, doesn’t work because it has no outputs, global variables don’t work, storing the data in the daq’s UserData field don’t work (shows up empty), and fprintf’ing to a .txt works only the first 1 or 2 cycles and then fscanf just pulls empty each iteration (though I can see the data in callback’s workspace and in the .txt file.
  • I tried using only the ScansRequired callback to write and kept read in my main function. This errors out saying I need to read before I can write. I altered the code so it only writes immediately after a successful read, but this errors out as well, with an underflow event (which I believe is due to not writing fast enough).
I appreciate your help!!

Accepted Answer

David Meissner
David Meissner on 29 Apr 2022
Setup we used:
  • Using NI DAQ object callback ScansAvailableFcn with a call to read(d, ‘all’) within the callback
  • Using NI DAQ object callback ScansRequiredFcn with a call to write(d, d.UserData.u) within the callback where matrix u has a fixed number of rows, n
  • Before starting the DAQ we preloaded a fixed number of rows, p, to the DAQ
  • We used start(d, ‘Continuous’)
  • In our control loop, no faster than f Hz, we would update d.UserData.u (I do not think “no faster than f” is a hard requirement)
Parameters of concern:
  • a = NI DAQ object ScansAvailableFcnCount
  • r = NI DAQ object ScansRequiredFcnCount
  • n = size(d.UserData.u, 1)
  • p = size(preload_matrix, 1)
  • f = DAQ frequency
Restrictions (that have worked for us)
  • a == r && r == n (4 has worked for us. Other values may also work)
  • n > f (f = 1; n = 4*f has worked for us)
  • p > a
  • p ~= r && ((p + r) cannot be a multiple of a)
Our theory is that these restrictions prevent the initiation of a write and the completion of a read in which either the read or the write can be disregarded by the DAQ leaving in a few possible situations.
  • The DAQ misses a write cycle (to pull an additional r scans from d.UserData.u and write them to the DAQ) and before getting to the next write cycle, DAQ’s buffer runs out of scans to write and errors with “underflow” and “trigger timestamp was not received”, or
  • The DAQ misses a read cycle resulting in an error “DAC (digital to analog conversion)… DAQ did not have enough time to convert all the…”
  2 Comments
Shawn Albertson
Shawn Albertson on 1 Jun 2022
Did you consider using multiple daq objects/ tasks? If so, why did you choose not to?
I am working on a continuous background read&write program and found this thread. Your solution helped did work, but I am thinking of using one task for reading, one for writing, and a global data buffer which builds as it reads and a function which generates an output based on the buffer. This would allow me flexibility in my sampling frequency for each which is desirable.
David Meissner
David Meissner on 6 Jun 2022
Good question Shawn A.. I didn't think I could create multiple daq objects and I was under the impression that when the daq triggers a read operation it is allowed 1 callback function and when the daq triggers a write operation it is allowed 1 callback function. For me, if I tried to fill the daq's buffer as I went, it would quickly report 'out of memory', so I used matlab's global variable datatype (perhaps this is what you are referring to). This data is then captured by my main function and also the raw data is written via fprintf to a text file. The data written to the daq is written to it's own .txt as well. Does this help answer your question?

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!