01-29-2011 08:29 AM
I ran into a small problem with transferring data from the FPGA to the RT controller on my cRIO-9073.
I would like to read 120 samples from 16 channels from an NI 9208 current input module into an array (size 16x120) with a sample rate of 500Hz - say every second. I tried to implement this using the Scan Engine (though with only a 250Hz sample rate). This was apparently too CPU intensive, as the load was continuously at 100%. I was advised to implement the DAQ on the FPGA and transfer the data from the FPGA to the RT controller using a DMA FIFO instead.
I tried to look for similar applications and I had a look at the following documents as well as some examples that came with the installation:
After reading (and copying) the examples I managed to transfer some data, but I still have some problems getting this to work the way I want. I have included the VIs and some screenshots of the block diagrams of my program.
I would expect that if I read e.g. 32 elements from the FIFO on the RT controller side every 2 seconds, I will get a 1-dimensional array, where the 16 first elemets are the first 16 samples from each channel on my NI 9208 and the next 16 samples the samples from the channels 1/500 second later. However, the positions of the samples change position in the 1-dimensional array for each time I read them, and if I try to read all the 1920 samples, I do not manage to read anything from the FIFO.
I am sure this is due to my lack of understanding of how the FIFOs work, and I would greatly appriciate any hints or suggestions about how I should fix this!
Best regards, Martin
PS. The FIFO I created has the following properties:
"General" -> "Type" -> "Target to Host - DMA"
"General" -> "Requested Number of Elements" -> "1920"
"Data Type" -> "Data Type" -> "FXP"
"Data Type" -> "Encoding" -> "Signed"
"Data Type" -> "Word Length" -> "24 bits"
"Data Type" -> "Integer word length" -> "-4 bits"
"Interfaces" -> "Arbitration for Write" -> "Arbitrate if Multiple Requestors Only"
01-29-2011 09:28 PM
First, a little bit about FIFOs. FIFOs are very similar to Queues, except they are built to be faster and more deterministic (hence they come as part of the RT module). Consequently, there are some features of Queues that are not available with FIFOs, such as "Preview Queue Element" or "Enqueue Element at Opposite End." I actually prefer using FIFOs even when I'm just programming in Windows.
With that said, the FIFOs behave basically the same independent of what target they are used on, with one big exception. On FPGA targets if the FIFO gets full the new data will not overwrite the old data and the new data will be lost. On other targets the FIFO write function includes a boolean that allows the new data to overwrite old data if the FIFO is full.
Taking a look at your code, what you have is a FIFO that is filling up way faster than data is being taken out of the FIFO. And with a FIFO writer that is being told to wait until space is available to write data, the FIFO is filling up fast and then the FPGA code gets bogged down waiting for FIFO space. Another item that I noticed is that you are configuring the FIFO depth (i.e. length) to be the same as the size of block of data that you want to read. With no extra "wiggle" space that could cause problems too. I'd recommend that if you have the memory capability to configure the FIFO depth to hold 2 full blocks of data.
If I understand your problem statement, you actually only want part of the data being acquired. If that's the case there are several ways you can go about that:
1. Pull all of the data out of the FIFO on the host side and then throw away what data you don't want
2. Write some code on the FPGA side that only puts the data that you want into the FIFO, i.e. you don't have to write data to the FIFO during every loop.
3. Write some code on the FPGA side to change the loop rate from loop to loop to get the desired data.
I would recommend #2 above. That is a technique that I use all of the time. Typically, I just turn on the acquisition at a fixed speed and then use what ever logic is needed to pass only the data that I want up to the host.
Hope this helps,
01-30-2011 09:37 AM
Thanks for taking the trouble to help me along the way! I did not know that the FIFO on the FPGA cannot be configured to overwrite data, so that was indeed some valuable information. I think I might have been a bit unprecise in my problem statement, though, so I'll try to see if I manage better: :-)
I want to measure the cylinder pressures in a reciprocating engine from 16 pressure transmitters. The engine runs at about 12.5 Hz, and since I would like to have about 40 samples per revolution, I need a sample rate of 500 Hz. I would like to analyse 2-3 revolutions each time, so I need 120 samples per channel. I don't really care if I have lost some data between the times I read the data - so filling up the FIFO is of no big concern. "Fresh" data would be a bonus, but it's not really critical. But I do need the data I use to be continuous, and I need to know which sample comes from which channel.
I have tried to improve my code by expanding the size of the FIFO (Num elements 5760), and first write the data to an array (1920 elements) before I write to the FIFO on the FPGA-side. This will probably fill the FIFO at the same rate as the previous code, but I could then add some timing too if necessary (e.g. only write to the FIFO if a certain amount of msec has passed and there are 1920 new elements in the array). I will increase the depth to 2x1920 on the RT-side and see if this works (or at least closer to what I expect and want). I have to admit that I still don't understand why the data I read in the earlier code did not come with the data from the channels in the same posision each time.
I have to wait to see if the new code works though, since LabVIEW is still on the "Synthesizing"-step after more than one and a half hour. I have never the less included a screenshot of the new code for the Target.
01-30-2011 09:48 AM
Oops. I just realized that there is a small bug in my new code: In order to get the correct array index, I need to multiply the value of the counter with the number of channels, before tunneling it into the for-loop and adding it to the loop counter.
01-31-2011 08:52 AM
Thanks for the clarification on your problem, although I think that perhaps I wasn't clear on my answer.
You are correct in that the new code that you've posted will fill up the FIFO just as fast as the old code. What I suggest is that you allow the analysis on the RT side of the cRIO to control when new data gets written to the FIFO, that way you don't have a FIFO filling up with data that isn't going to be used. Take a look at the FPGA code that I've attached and see if that is what you're after. Note that I didn't test the code, consequently there may be a hack or two in the code.
If I'm reading your post correctly, you are also wondering how to know which sample came from which channel once you get the data out of the FIFO on the RT side. I've attached another piece of code that shows how to do that, a wonderful little function on the arrays pallet called "Decimate 1D Array."
I hope this helps,
01-31-2011 02:39 PM
Hello again, Dave,
Many thanks for your code example! I've tried to implement it, and I think I am one step closer to a solution. It seems that eventhough my lack of understanding of the inner workings of the DMA FIFO on the FPGA did not help, the source of my problems lies elsewhere. Your code helped locate the problem.
As I never seem to manage to get the FIFO to work, and I couldn't find a reason why not. I am now seeing some (to me) strange behaviour on the RT side, as the array never seems to update - indicating that the FIFO was never read. The elements remaining seemed to grow with time and hardly ever go to zero. The CPU usage went straight to 100%. When I replaced the data from my NI 9208 (analog current module) with just an array of constants on the FPGA part, the array on the RT side seemed to update and the remaining elements went to zero, but the 100% CPU-usage remains. When I tried to read some data from a different module (NI 9213), I had the same problems as with the NI 9208.
I am now reading up on high CPU-usage and DMA FIFO to see if I can manage to fix my code. I was pointed in the direction of the two links below, and I'll give it a try again tomorrow.
02-02-2011 12:35 PM
suggest you download thefollowing:
I have used the base code to impliment diesel engine cylinder pressure monitoring on 2hz 10 cylinder 70000shp motor
Use version 3.05 for 2010 else 2.71 for 2009.