To download NI software, including the products shown below, visit ni.com/downloads.
This document is part of the Introduction to NI R Series. This example personality for R Series devices first explains the overall architecture of FPGA code and then details how to use each of the included example host VIs.
Download the Balanced I/O Example DAQ Personality
All of the core functionality of this example personality is contained within the FPGA code. This FPGA code implements analog input, analog output, counters, and digital I/O tasks on a low level. Each of these components is contained within its own separate loop in the NI LabVIEW FPGA code. In the following sections, learn how the FPGA code works. Although each of the components of the code is addressed separately, it's important to keep in mind that they are all within one FPGA VI.
Figure 1. Analog Input Loop
The outer While Loop simply polls the AI Enable Boolean. Once this Boolean goes true, the analog acquisition begins. The inner While Loop is what actually controls the data acquisition. This inner While Loop consists of a flat sequence structure with two frames. In the first frame, we are simply setting the loop rate such that the loop runs at the specified sampling rate. There is some additional logic in this frame as well to let the user know how fast the loop is actually running.
The second frame of the sequence structure simultaneously acquires a single sample from each channel (channels 0–7) and builds these eight samples into a 1D array. This array is then fed into a single-cycle Timed Loop. This loop executes once for each channel that the user requests data from. For example, if the user requests data from channels 0, 1, and 7, this single-cycle Timed Loop runs three times. Each time the loop runs, it writes a single sample into the analog input DMA FIFO. The next iteration waits at the Loop Timer until it is time to acquire the next data point.
Once the AI Enable Boolean goes false, the data acquisition stops and control is transferred to the outer loop, which waits until AI Enable goes high again and the acquisition starts over. If at any point the AI FIFO is full when we try to write to it, we terminate the data acquisition and set the AI Buffer Overflow? indicator to true. Also, each time we write data to the AI FIFO, we increment a counter by one. We do this so we know exactly how much data has been put in the buffer and the host VI can adequately flush the buffer between finite acquisitions.
Figure 2. Analog Output Loop
Just like the Analog Input Loop, the outer While Loop simply polls the AO Enable Boolean. Once this Boolean goes high, the analog output operation starts. The inner While Loop is what actually controls the analog output operation. This loop consists of a flat sequence structure with two frames. The first frame of the sequence structure simply sets the loop rate such that the loop executes at the appropriate output frequency that the user selects.
The second frame of the sequence structure reads one entry out of the DMA FIFO for each channel that the user selects as a buffered output channel. For example, if the user selects that they are using analog output channels 0, 1, and 7, this While Loop runs three times and puts each value into the appropriate slot in an eight element array.
The next segment of logic after this loop may look complicated, but is really quite simple. We start off by converting the AO Buffer Enable input into an array of eight Booleans. Each Boolean in this array corresponds to one of the eight analog output channels. For example, a TRUE in element zero of this array indicates that AO channel 0 is configured as a buffered channel and we should output the data from the AO FIFO for that channel. If a FALSE is in element zero of this array, this means that AO channel 0 is configured as a software-timed (nonbuffered) channel. If a channel is configured as nonbuffered (FALSE), then we should simply output the value in the corresponding control for that channel (AO 0 in this example). The logic in this section of code simply looks at the AO Buffer Enable Boolean for the given channel and if TRUE, it routes the value from the FIFO read to the channel (through the Select function). If FALSE, it routes the value of the corresponding channel control to the output.
The analog output operation stops if the user sets the AO Enable Boolean to FALSE or if a buffer underflow condition occurs. After this loop exits, the code waits for AO Enable to go false (in the case that it was a buffer underflow) and then clears out the AO FIFO by reading from the FIFO until it is empty. For this logic to work, the host VI must guarantee that after AO Enable is set to false, it will no longer put new data points into the AO DMA FIFO until after the next analog output operation.
Once the analog output operation is over, the outer loop takes control again and polls the AO Enable Boolean until it goes high again and the next analog output operation starts.
Figure 3. Counter Loop
In this example personality, there are four independent counters. Each of these counters is implemented in LabVIEW FPGA with identical loops.
Like all of the loops we have looked at so far, the Counter Loop starts with an outer loop that polls the Counter 0:Enable Boolean. Once this Boolean goes true, the counter operation starts. The counter consists of a single-cycle Timed Loop, which executes once for each tick of the 40 MHz internal clock. Inside this single-cycle Timed Loop, most of the work of this counter is done in the Advanced Counter Sub subVI. The host program has to supply some inputs to the counter, which determines how the counter operates. These parameters are as follows:
The outputs of the Advanced Counter Sub are the current counter value and the Counter Reset signal. Counter Reset is high if the counter was reset by the Advanced Counter Sub VI. If this is the case, we manually set the Counter 0:Reset Counter input to false. This is to prevent the counter from being reset continuously until the user manually unsets the Counter 0:Reset Counter input.
Once the Counter 0:Enable signal goes false, we exit the single-cycle Timed Loop and the outer loop starts polling the Counter 0:Enable input again waiting for it to go high. When Counter 0:Enable goes high again, the counter is first reset and then it starts counting again.
Figure 4. Digital I/O Loop
The Digital I/O Loop is by far the simplest loop in the entire FPGA code. This loop reads the five, 8-bit ports of digital inputs and writes them to five separate indicators. It also takes the values of five 8-bit controls and writes these to five outputs. The loop itself runs continuously as fast as it can without stopping.
To use the FPGA personality, we need a host that knows how to communicate to the FPGA VI. As a part of this personality, we have included several host VIs that each illustrate a different functionality of this personality. In this section, learn about all of the example hosts, how they are used, and what is going on in the block diagram.
Figure 5. Cont Acq&Graph Voltage-Int Clk.vi Front Panel
Figure 6. Cont Acq&Graph Voltage-Int Clk.vi Block Diagram
This example illustrates how to do a simple continuous analog acquisition. The front panel of this VI is similar to an analogous DAQmx VI. You have to select the device you want to communicate with, the channels you want to read from, the sampling rate, and the number of samples to read from the buffer at once.
If you look at the block diagram, the first thing that we do is open a reference to the FPGA VI. This downloads the FPGA code to your R Series device and starts running. After this, we set the depth of the host side DMA FIFO. In this example, we are setting the depth to 32,767 elements. This means that the buffer that resides on our host PC will be large enough to store 32,767 samples (all channels are counted in this total).
Next, we start the DMA process by calling AI FIFO: Start. This ensures that as soon as the FPGA starts acquiring samples, they will be transferred from the FPGA memory to the host memory in the background. After this, we set the AI loop timer to specify how fast we want to acquire data and we set the AI Channel Enable to tell the FPGA which of the eight AI channels we want to read from. Finally, we set AI Enable to true to start our acquisition.
Inside the loop, we read the specified number of samples from the FIFO and feed these samples into the AI Data to Array subVI. This subVI decimates the 1D array that comes out of the FIFO and builds an appropriate 2D array to be fed into the waveform graph. Also in this loop, we are checking to see if there has been a buffer overflow and also retrieving the actual loop rate that the FPGA is running at. The application stops if one of three conditions occurs: the user clicks the stop button, there is a buffer overflow, or some other error occurs.
Once the main loop stops, we close the reference to the FPGA and reset the FPGA (stopping the FPGA VI). Finally, we display any errors that may have occurred to the user.
Figure 7. Acq&Graph Voltage-Int Clk-Retrigger Front Panel
Figure 8. Acq&Graph Voltage-Int Clk-Retrigger Block Diagram
The Acq&Graph Voltage-Int Clk-Retrigger example is much like the previous example except instead of acquiring voltage samples continuously, we acquire a finite amount of samples each time the Trigger button is clicked.
Once the reference to the FPGA VI is opened and the FPGA VI is running, we go into our main loop. This main loop consists of one event structure that waits for the Trigger button to be clicked. Once this button is clicked, we set up the parameters for the acquisition and then read in the specified number of points from the AI FIFO.
The interesting part of this code is what happens after we read in all of the data points and set AI Enable to false to stop the data acquisition. After this we go into the Flush FIFO loop. This loop goes through and reads any extra data that may have been written to the FIFO that we want to clear out of the FIFO before the next iteration occurs. After we flush out the FIFO, we return to the main loop and wait for the trigger button to be clicked again. Once the user clicks the stop button, we exit the loop and close out the reference to the FPGA (which stops execution of the FPGA code).
Figure 9. Gen Mult Voltage Update.vi Front Panel
Figure 10. Gen Mult Voltage Update.vi Block Diagram
The Gen Mult Voltage Updates host example shows the simplest possible use case for analog output with this FPGA personality. After opening up the reference to the FPGA VI and running it, we simply set AO Enable to true and specify a loop speed for the Analog Output Loop on the FPGA. Once we enter the main loop, we calibrate the data in the AO Channels array and then write the data to the AO controls on the FPGA.
Figure 11. Cont Gen Voltage Wfm-Int Clk-Non Regeneration Front Panel
Figure 12. Cont Gen Voltage Wfm-Int Clk-Non Regeneration Block Diagram
The Cont Gen Voltage Wfm-Int Clk-Non Regeneration example is a more complex example that demonstrates the hardware timed analog output capabilities of the FPGA personality. In this example, we first open a reference to the FPGA VI without running it. We then set the Analog Output Loop timer and the AO Buffer Enable. If you remember from the previous sections, the AO Buffer Enable input is what tells the FPGA code which channels to treat as buffered (hardware-timed) outputs and which outputs to treat as static (software-timed) outputs. We then set AO Enable to TRUE. Normally, this would start our analog output on the FPGA, but because our FPGA code isn't actually running yet, the analog output operation does not start.
The next thing that we do is generate some samples of a given waveform type and write it to the AO FIFO. We do this so that there is already some data in the FIFO when the FPGA starts running. If we waited to write data to the FIFO until after we started the FPGA VI, we would most likely run into buffer under run issues with the FPGA trying to read from the FIFO before we put data in it.
Once we have some initial data in the FIFO, we call the Run method on the FPGA to start the FPGA code running. Since we have already set the AO Enable to TRUE, the analog output will start as soon as we call this method. Inside the While Loop, we monitor the actual loop rate and feed more data into the analog output FIFO. In this particular example, the same waveform is fed into all eight channels. Once the user clicks the stop button, the loop exits and the FPGA reference is closed out.
Figure 13. Count Digital Events.vi Front Panel
Figure 14. Count Digital Events.vi Front Panel
The Count Digital Events host is designed to show how to use the counters on this FPGA personality. We first start by opening a reference to the FPGA code and running it. After this we set the parameters of the counter (initial count, ticks to filter, and so on). Finally we set Counter 0:Enable to TRUE and the counter operation starts.
We then go into the main While Loop. This loop simply reads the value of the counter and allows the user to reset the counter value. After the user clicks stop, the FPGA reference is closed and the application finishes.
Figure 15. Write Dig Chan.vi Front Panel
Figure 16. Write Dig Chan.vi Block Diagram
The Write Dig Chan host VI illustrates how to do some simple digital output using this FPGA personality. On the block diagram, we are simply opening the FPGA reference and running the FPGA VI. We then go into the main loop and write the values of the Data to Write control into Connector 2:DIO Port 0. These writes happen 10 times per second. After clicking the stop button, the FPGA reference is closed and the FPGA VI stops.
Figure 18. Read Dig Chan.vi Block Diagram
The Read Dig Chan example shows how to use the digital input capabilities of this FPGA personality. We open a reference to the FPGA VI and start the FPGA code running. After this we go into our main loop and read from the digital ports 10 times per second. After the user clicks the stop button, we exit the loop and close out the reference to the FPGA.
This Balanced I/O example DAQ personality is intended to show what is possible with R Series devices and LabVIEW FPGA. No other device offers eight analog inputs, eight analog outputs, four simple event counters (with debounce filters), 40 digital input lines, and 40 digital output lines, all on a single piece of hardware. You do not need the LabVIEW FPGA Module to use this precompiled personality. However, you do need the module to make any modifications to the FPGA code. The NI-RIO driver is the only driver necessary.
Balanced I/O Example DAQ Personality
Advanced Data Acquisition Techniques with R Series
Description-Separate-2Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.