Programming with the FPGA Interface C API

Publish Date: May 15, 2017 | 1 Ratings | 4.00 out of 5 | Print

Overview

This white paper and attached five tutorials with code walk you through building an application in C/C++ for NI Linux Real-Time that will communicate with an FPGA programmed using LabVIEW. The essential components of the LabVIEW RIO architecture are a real-time processor, one or multiple FPGAs, and I/O processing elements. In the Eclipse-based design flow, C/C++ is used to program the processor, and LabVIEW FPGA is used to program the FPGA and access the I/O. A set of APIs collectively known as the FPGA Interface C API is used to interface between the C/C++ program (on the processor) and LabVIEW FPGA program (on the FPGA).

Table of Contents

  1. Hardware Architecture
  2. Programming LabVIEW FPGA to Access I/O
  3. Generating the C API
  4. Utilizing the Generated C API from Eclipse to Program the RT Processor
  5. Programming the FPGA as a Co-processor
  6. Next Steps

1. Hardware Architecture

The C/C++ Embedded System Design Tools whitepaper provides a high-level discussion of the design flow and the tools. The following discussion and attached tutorials are based on the CompactRIO Single-Board controller (model sbRIO-9637). The board is based on the RIO hardware architecture (below) that includes a Xilinx Zynq-7000 XC7Z020 All Programmable System on Chip, with an Artix-7 FPGA and a 667 MHz dual-core ARM Cortex-A9 processor running the NI Linux Real-Time (32 bit) distribution. Even though the design flow discussed here is targeted for sbRIO-9637, the concept is general enough to be used for any other RIO boards, e.g., NI CompactRIO, NI myRIO, NI FlexRIO, and NI R Series boards.

Image 

 

Back to Top

2. Programming LabVIEW FPGA to Access I/O

The image below shows the project view of a LabVIEW program. The project view encompasses hardware, I/O, and the software program. An embedded target, model sbRIO-9637, has been added to the project. If the RT Single-Board RIO Target is expanded, the FPGA target and the associated I/O are visible. For the sbRIO-9637 board, there are 16 analog inputs, 4 analog outputs, 28 digital I/O, and three board level pre-defined I/O channels.  

A program in LabVIEW is called a virtual instrument (VI). A VI interacts through controls and indicators (similar to variables in programs). Depending on the execution host for LabVIEW, a VI can be written for the desktop, the real-time processor or the FPGA. Getting Started with LabVIEW FPGA is a collection of introductory videos walking through common LabVIEW FPGA programming tasks.

We will illustrate the design flow through a program which controls the behavior of two LEDs (LED1 and LED2 on sbRIO-9637) via a push button (PB1 on sbRIO-9637). In the default state (PB1 is not pressed), LED1 is on and LED2 is off. When PB1 is pressed, LED1 is off and LED2 is on. When PB1 is released, the LEDs return to default state. The first image below shows an FPGA VI that accesses three I/O – one digital input (a push button PB1), and two digital outputs (LEDs LED1 and LED2). The corresponding names on the FPGA I/O interfaces are DIO12 (PB1), DIO4 (LED1) and DIO5(LED2). All I/O are accessed within a while loop to continuously monitor their state. To read and control the state of any I/O, one needs to create a control or indicator reference for the respective I/O. A control or indicator in LabVIEW is similar to a register; indicator implies writing action, and control implies reading action. The second image below shows control and indicators for I/O being accessed by the program.

 

When the design is complete, LabVIEW hands off the design to the Xilinx Vivado compilation toolchain to compile. After successful compilation, a valid bitfile (file extension .lvbitx) is generated. An FPGA bitfile is similar to an executable on a processor, and is the configuration of the digital circuit on the FPGA.

 

Back to Top

3. Generating the C API

After successful compilation of the LabVIEW FPGA VI, the C interface should be generated. If FPGA Interface C API has been installed, then open the FPGA Interface C API Generator from the LabVIEW Project to generate the necessary files to be used from a C/C++ project in Eclipse.

The following four files are generated:

-NiFpga.c (C Source): C API loader

-NiFpga.h (C/C++ Header File): C API loader

-NiFpga_<fpga_VI_name>.h (C/C++ Header File): Register references for the defined VI

-NiFpga_<fpga_VI_name>.lvbitx (Bitfile)

 

The first two files are always generated for any program, and refer to the complete API. The last file is the bitfile generated by compiling the FPGA VI. The third file is unique for each VI – this is the most interesting file for the C API, and should be reviewed after each generation. There are three key pieces of information in the file: (1) filename of FPGA bitfile which can be concatenated, (2) unique signature of the bitfile which would be later used to open sessions for the FPGA, and (3) register references for the control/indicators from FPGA VI. Below is snapshot of the code.

Not all data types in LabVIEW FPGA are supported by the C API generator. Currently the C API supports Boolean, Integer, and Floating Point data types used in LabVIEW FPGA controls/indicators, DMA FIFOs, and interrupts. Other types like Fixed Point (native data type for FPGAs to optimize resources) and LabVIEW clusters are currently not supported.

 

Back to Top

4. Utilizing the Generated C API from Eclipse to Program the RT Processor

Once the C API files have been generated, you can write your main C/C++ application. Getting Started with C/C++ Development Tools for NI Linux Real-Time, Eclipse Edition discusses installing the Eclipse plugin, setting up the project, and accessing the remote target to transfer files. The remaining steps of this tutorial assume that a C/C++ project has been setup and the C API files have been transferred to the remote target. Assuming a C++ file is being generated, these are the steps to create the main program (screenshots for the push button/led program are shown as an example):

1. Include the header file (specific to the FPGA VI) generated by the C API and any other header file as needed by the program.

2. Create a session, initialize FPGA interface library, and load the NiFpga Library.

3. Open an FPGA session by referring to the corresponding bitfile, its unique signature, and resource name.

4. Initialize the variables representing the control/ indicators; for the current example, three Boolean variables are created with desired initial values.

5. Initializing the indicators are done by updating the corresponding C API variables; for our example, once the program starts executing, LED1 will be off and LED2 will be on.

6. This is the main logic of the application. In this program, the push button is continuously monitored, and status of the LEDs are modified based on the status of push button. There is a while loop which stops if an error is reported by the FPGA. If no error is reported, status of the push button is checked. If the button is pushed, LED1 is turned on and LED2 is turned off. The LEDs return to the initial state when the button is released. usleep is used to provide time interval between status check on the push button.

 

7. Close the session, and unload the C API library.

Back to Top

5. Programming the FPGA as a Co-processor

The previous steps focused on accessing I/O on the processor via the FPGA, considering it like a driver. An FPGA is much more powerful than an I/O accessor. FPGAs like Xilinx Zynq-7000 series SoC used in sbRIO-9637 have logic cells and dedicated DSP slices that can be used for I/O co-processing, computational co-processing, and real-time processing. LabVIEW FPGA offers IP to assist in writing an FPGA VI serving one or all of the above features.

FPGA for I/O co-processing. FPGA can be used for I/O processing like PWM (pulse width modulation). Figure 14 shows a LabVIEW FPGA VI which receives an LED intensity value from the real-time processor, and then sets that intensity for the two LEDs after PWM is performed on each signal. Performing tasks like this on the FPGA saves precious computation cycles on the real-time processor and can be executed at a faster loop rate.

FPGA for computational co-processing. LabVIEW FPGA provides a range of functions out-of-the-box, like filtering, signal processing, and control that are executed extremely fast on the FPGA, and help in sharing the computational load of the real-time processor.

FPGA for real-time processing. While all real-time computations can be performed on a processor; doing some of those on deterministic hardware like an FPGA can help lower both latency and jitter. Compare a scenario where the processing is done on the real-time processor;  the operating systems and the driver API of the processor may introduce additional delay and jitter. On the other hand, if the processing is done on hardware (FPGA), then the response time can be small (orders of magnitude reduction) with very little or no jitter.

In summary, use the LabVIEW FPGA module for critical pieces of your application that can be offloaded from the processor; examples of such co-processing include the above as well as specific tasks like high-speed control, custom protocols, inline signal processing, and custom timing, triggering and synchronization.

Back to Top

6. Next Steps

Visit our active developer forums for answers on advanced questions regarding C/C++ and Linux programming: NI Linux Real-Time Community

For additional FPGA Interface C API exercises specific to the hardware you're developing on, please check out the following links:

Back to Top

Bookmark & Share


Downloads


Ratings

Rate this document

Answered Your Question?
Yes No

Submit