09-26-2006 10:55 AM
Thank you.
In fact my real code is pretty much the same as the sample codes I posted. In my real code, I have a similar "Ok" callback to do a while(1) loop DAQ unless some of the DAQ data exceed some limits. Therefore, you can say while DAQ is working, the main thread is locked in the while(1) loop just like the sample "OkCallback". In my secondary thread, i.e. the async timer callback, DAQ data is simply displayed in numeric boxes and plotted in the graph which was created in main thread. Since async timer is totally an independent thread on the main thread, I cannot understand why firing timing will be an issue for display. So far, I am pretty sure there is nothing wrong with my traditional DAQ MIO boards, because I put the while (1); command in the beginning of the DAQ callback code and the timer callback is just trying to randomly display some data in the graph and numeric boxes, the data can not be displayed or plotted at all except one numeric box. As you suggested, ProcessSystemEvents () should not be appear in my main thread since it will lower my DAQ rate. I really don't know how to make it work correctly. Can I talk to you directly over phone? Thanks.
09-26-2006 11:03 AM
09-26-2006 11:08 AM
09-26-2006 11:26 AM
I cannot move my DAQ into the timer callback, because my DAQ rate is over 100 Hz.
Why in my sample code, the graph can be updated correctly even though the "while" loop kept "blocking" events?
09-26-2006 12:50 PM - edited 09-26-2006 12:50 PM
What kind of DAQ card are you using? Having the DAQ card read at a rate greater than 100Hz, moving the data to a buffer in the PC, then moving the data from that buffer for display are all different things. The DAQ card reads data based on it's own internal hardware timing (which you setup with the acquisition rate), the data is moved to the PC, usually through a DMA channel by NIDAQ, and you then read the data from a buffer queue maintained by NIDAQ. You can read this queue and display the data at a much slower rate than the clock frequency of the incoming data, you are just reading bigger chunks of data at one time. In other words, read it in segments instead of one point at a time. The speed you can acquire is dictated by the size of the onboard buffer of the DAQ card and how fast the data can be offloaded to the PC (fortunately something that is handled for you by NIDAQ), and the size of the NIDAQ buffer.
All you have to do is move the total block of data read from the NIDAQ buffer at a rate that is faster than the data is comming in from the card. The execution of the read data buffer command and display of the data must simply take less time than your timer event callback. This should be pretty easy even if you drop your timer rate to 50mS.
Take a look at the CVI example for a continuous analog acquire:
Under Help -> Find Examples
Look for Hardware Input and Output/DAQmx/Analog Measurements/Voltage for ContAcq-Intclk-Anlgstart.prj
There is a lot of additional information in these forums on how to do continuous data acquisitions that are almost seamless where you ping-pong between a pair of buffers so that the read process is essentially continuous.
Message Edited by mvr on 09-26-2006 12:52 PM
09-26-2006 01:10 PM
Here is another piece of the puzzle, you want to use your daq card in continous, non-blocking mode. See this link.
http://forums.ni.com/ni/board/message?board.id=180&message.id=20013&requireLogin=False
What I called the ping-pong buffer arrangement was called double buffered in conventional NIDAQ, but handled for you by NIDAQmx. You should be able to set up for continuous acquisition without any problem.
09-26-2006 02:36 PM
Based on your thoughts, let me make a tentative conclusion on our discussion:
1. while (1) loop in my main thread blocks CVI from updating user interface so that both graph and numeric can not be displayed or updated correctly.
2. ProcessSystemEvents() in my DAQ routine lowered the DAQ rate due to the responses to other events such as update user interface.
3. Instead of putting DAQ routine in main thread, I should put DAQ routine in the second thread (async timer callback) to let main thread freely responded other events simultaneously.
4. DAQ rate can be set as high as possible, while retriving DAQ data segments from buffer can be as slow as we want.
I have following questions about the async timer callback:
1. When will the timer callback return? It denpends on time interval or code completion?
2. What if I need to process DAQ data one by one in real-time? I am using PCI-MIO-16XE-10 DAQ board.
Thanks again for your help.
09-26-2006 03:31 PM
09-26-2006 04:47 PM
Thanks Luis and mvr. You make me deeply understand the problem. From my research, I realized that probably I should use threadpool instead of async timer to do the DAQ and real-time display simultaneously, since unlike a timer, threadpool does not have a time interval (like interruption) issue related to the DAQ. Hence, I can just simply changed my original DAQ callback into a thread function, while displaying DAQ data from thread-safe queue in the graph. Can I create a new thread in a "callback" function instead of "main"?
Here is the structure I want to change into:
1. StartDAQCallback function:
In this callback fuction, I want to create a new thread for DAQ. Meanwhile, I want to build a safe thread queue for DAQ data. After they are created, I will read the queue every 50 ms and display the data in the graph. ProcessSystemEvents() will also be included in this callback for responding when user clicks "stop" or "pause" button in UI.
2. ThreadFunction:
Basically this a real-time control function. It acquires DAQ data from sensor and send commands to actuators in real-time. It will quit the thread either when some DAQ data exceed the range or user click "stop" button in UI.
What do you guys think about the mechanism I proposed above? Will it work well for my application? My objective is fairly straight forward: 1. Displaying DAQ data in the graph timely while not lowering DAQ rate. 2. Respond user input while displaying and acquiring. Thank you for your input.
09-27-2006 11:21 AM - edited 09-27-2006 11:21 AM
From your post it sounds like you have a pretty good handle on how to implement your application. I think what you have described will work for you.
Moving the DAQ acquisition process into a loop in a separate thread pool is fine. Doing it in the way you feel most comfortable with is generally the best way to go. The suggestion to use the async timer was made because it is less complicated to implement than setting up a thread pool etc, and it could probably be made to work. But setting up your own thread process is a better way to go if you want to use a loop based design.
There are CVI examples that you can probably modify pretty easily to get to where you want go by setting up a thread and executing your data acquisition loop in it. Once the DAQ process is executing in its own thread and is not blocking or being blocked by the main thread, the majority of your timing issues should be solved. There is a CVI function PostDeferredCallToThread() that can be used for communication of commands/events/actions between threads. This can be used by your main thread to suspend/resume and terminate the DAQ data routine in the secondary thread. More information is available in CVI help under Posting Events and Multithreading and by searching the CVI examples on this web site. In the CVI examples for running a process in another thread, they cover things like how to signal the thread to shut itself shutdown.
Updating the display with the latest DAQ Data can be handled by setting the displays controls directly in the same method as you were using in the timer thread example, or by passing the data through a thread safe queue and letting another thread (async timer is fine), handle the updates. I think you have already solved the display problem, the issue has been getting the DAQ acquire routine to run correctly.
As far as ProcessSystemEvents(), you should not need to call it at all. The DAQ thread will not need it since it only handles getting data from NIDAQ. The display panel itself is in the main thread. As long as all the callbacks in your main thread do not enter long or endless loops, the main user display will redraw just fine. As for the process that writes data to the screen, both writing it directly from the DAQ thread, or using a timer or other thread to update the screen, again the screen should update without the need for ProcessSystemEvent() calls.
I see that you want to process the daq data in virtual realtime so that you can control an external process. You can probably do this from inside your DAQ reader thread. As long as the process you are trying to control does not require the response time to a data change event to be faster than about 10mS you should be fine. The 10mS limitation comes from some of the issues with a standard OS like windows, it is not a CVI issue. As I mentioned before, if better than 10mS response time is required consider using a realtime OS.
I know it can be frustrating trying to resolve these kind of issues in a forum, but I think you are well on the way to getting this working. Feel free to ask any kind question here. Good Luck.
Message Edited by mvr on 09-27-2006 11:27 AM