Skip to content

FPGA Development

ifrasch edited this page Mar 7, 2017 · 23 revisions

This page contains information pertaining to digital logic development for the bladeRF's Altera Cyclone IV FPGA. See http://www.nuand.com/fpga.php for available FPGA bitstreams. "Hosted" is the default bitstream for the bladeRF.

Table of Contents

Overview

The Altera Cyclone IV FPGA interfaces with the Cypress FX3 USB3.0 controller (CYUSB3014-BZXC), the Lime Micro LMS6002D RF transceiver, the Si5338 clock generator chip, the VCTCXO DAC. The primary purpose of the default "hosted" image is to shuffle I/Q samples between the FX3 and the LMS6002D, and configure the LMS6002D via SPI based on commands received from the FX3 via UART. Other purposes include controlling to the Si5338 clock generator chip and VCTCXO DAC, controlling the SPDT RF switches lying in between the LMS6002D and the SMA RX/TX ports, and interfacing with expansion boards.

The VHDL source code is separated into platform-specific code and IP cores. IP is separated into nuand IP, OpenCores IP, and IP created from Altera tools.

The top level bladerf entity (bladerf.vhd) defines the ports which are connected to external pins. Architectures for the bladerf entity are kept in different files for different designs. The hosted_bladerf architecture (bladerf-hosted.vhd) corresponds to the default bladeRF image. Other existing architectures include the ADSB decoder which performs signal processing to decode ADSB signals instead of shuffling IQ samples (more info here).

Architecture

This section will describe the structure of the default FPGA architecture bladerf-hosted.vhd.

The FPGA consists of an Altera NIOS II soft processor for command+control and custom logic for sample shuffling+everything else. The NIOS II is clocked at 80 MHz. The C code for the NIOS II is found in bladeRF/hdl/fpga/ip/altera/nios_system/software. The "nios_system" component inside bladerf-hosted.vhd contains everything needed for command+control, including the NIOS II processor. IQ sample shuffling is kept separate from command+control. Samples are transferred between the FX3 and the FPGA via the FX3's GPIF II interface.

Samples Architecture

The following diagram illustrates the modules that IQ samples flow through in the FPGA. Modules outside of the sample path have been omitted. Signals that do not carry IQ samples have also been omitted for simplicity.

Note: to reduce confusion, signals/ports will be italicized and modules/processes will be monospace code formatted.

At the LMS6002D chip interface, each "IQ sample" consists of one 12-bit signed I sample and one 12-bit signed Q sample. Inside the FPGA, I and Q samples are either sign extended or sign contracted so that the FX3 sees a 16-bit I sample and a 16-bit Q sample. This was done for ease of integration with FX3 firmware.

Transmit side

Samples are sent from the FX3 to the FPGA over the bidirectional fx3_gpif bus to the fx3_gpif module. The register_gpif process inside the hosted_bladerf architecture handles the driving/releasing of the fx3_gpif bus and interfaces with the fx3_gpif module via fx3_gpif_in, fx3_gpif_out, and fx3_gpif_oe. Samples then go to tx_sample_fifo via tx_sample_fifo.wdata. Sample metadata passes through tx_meta_fifo via tx_meta_fifo.wdata when metadata is enabled. A clock domain crossing happens inside these FIFOs. Samples then pass to fifo_reader through tx_sample_fifo.rdata which separates them into the I sample (tx_sample_raw_i) and the Q sample (tx_sample_raw_q). Corrections for DC offset and other imperfections are done in tx_iq_correction. The sign contraction from 16 bits to 12 bits happens just before tx_sample_i and tx_sample_q go into the lms6002d module. This module creates the time-multiplexed lms_tx_data output signal which goes directly to the LMS6002D chip. The I sample is driven during one clock cycle and the Q sample on the next clock cycle.

Receive side

Samples are received from the LMS6002D chip via lms_rx_data. The lms6002d module extracts the time-multiplexed I and Q samples and outputs them to the rx_mux process. Sign extension happens just before the signals pass into the mux. In RX_MUX_NORMAL mode, the mux passes the raw I and Q samples to the output. The RX_MUX_12BIT_COUNTER and RX_MUX_32BIT_COUNTER modes pass either 12-bit or 32-bit counter signals rx_gen_i and rx_gen_q to the output. These modes are useful for debugging, to find out if samples are being lost in the bladeRF's USB connection (especially USB 2.0). If the host PC side receives a stream of sample values that have discontinuities (e.g. 1 2 3 15 16 17), then samples were lost. RX_MUX_DIGITAL_LOOPBACK mode performs loopback by outputting rx_loopback_i and rx_loopback_q, which originate from the rx_loopback_fifo module (not shown). After the RX mux the rest of receive path is essentially the reverse of the transmit path.

Where to place custom code

Typical FPGA applications involve placing some signal processing in the RX and/or TX path. The code can be modified so that all IQ sample processing happens inside the FPGA (e.g. modulation/demodulation, filtering, etc) and the FX3 transmits/receives some sort of data instead of IQ samples. These types of modifications/additions should go in between the iq_correction blocks and the sample/meta fifos. fifo_reader and fifo_writer can be rewritten or removed. See the Examples section for some examples of this.

NIOS II Software

Software running on the NIOS II soft processor handles all command/control. The software receives packetized requests (originating from host software) from the FX3 chip via UART. It then performs the appropriate configuration/control action. For example, writing registers on the LMS6002D via SPI to set the frequency/gains, setting IQ imbalance correction, setting the sample rate, writing/reading expansion or configuration GPIO, etc. The NIOS system communicates with the rest of the FPGA logic via the input/output ports of the nios_system component (instantiated in bladerf-hosted.vhd). For more information, view the readme for the NIOS software here.

Development

Getting Started

Building FPGA image from source

Once you have cloned the bladeRF repository to your local machine, instructions for installing the required Quartus II free software and building the FPGA image and Quartus project file can be found in the README of bladeRF/hdl.

Tutorial: Blinking some LEDs

This can be thought of as a "hello world" for the FPGA. We will simply modify the FPGA code to blink some LEDs. Quartus GUI does not need to be open for this tutorial.

The bladeRF board has 3 LEDs accessible from the FPGA: D11, D12, and D13 controlled by bladerf entity output pins led(1), led(2), and led(3) respectively. The default FPGA image uses these LEDs for status indicators. We are going to use them for an LED blinking pattern instead.

Open bladerf-hosted.vhd. CTRL-F for "led(" and you should find these lines that control the LEDs:

led(1) <= led1_blink        when nios_gpio(15) = '0' else not nios_gpio(12);
led(2) <= tx_underflow_led  when nios_gpio(15) = '0' else not nios_gpio(13);
led(3) <= rx_overflow_led   when nios_gpio(15) = '0' else not nios_gpio(14);

Comment out these lines. We are going to instead insert a blink_leds process to control the LEDs. This process will make the LEDs blink one at a time for 0.5 seconds each, in order. Paste this code into the file above the commented-out code:

blink_leds : process (c4_clock)
    variable counter : natural range 0 to 57_600_000 := 57_600_000;
begin
    if (rising_edge(c4_clock)) then
        counter := counter - 1;
        if (counter = 0) then
            counter := 57_600_000;
        elsif (counter < 19_200_000) then
            led(2) <= '0';
            led(1) <= '1';
            led(3) <= '1';
        elsif (counter < 38_400_000) then
            led(2) <= '1';
            led(1) <= '0';
            led(3) <= '1';
        else
            led(2) <= '1';
            led(1) <= '1';
            led(3) <= '0';
        end if;
    end if;
end process;

This process involves a counter which counts clock cycles of the 38.4MHz c4_clock. The LED pattern outputted is based on the value of the counter. The LEDs are active low, as seen in the bladeRF schematic. Also note that the LEDs are placed in the order D12 D11 D13 on the board.

Now lets build the FPGA bitstream. Instructions are the same as in the "Building FPGA image from source" section. Run
[quartus install directory]/nios2eds/nios2_command_shell.sh to get into the appropriate Quartus II environment. From the same terminal, go to the bladeRF/hdl/quartus directory and run build_bladerf.sh like so:

./build_bladerf.sh -r hosted -s <size>, where <size> is replaced with your bladeRF FPGA size (40 or 115).

This will take ~10 minutes to build. Once finished, cd into the newly created build folder which contains the hostedx<size>.rbf FPGA bitstream. From there you can plug in your bladeRF and use bladeRF-cli to load the FPGA with your bitstream:

bladeRF-cli -l hostedx<size>.rbf

Once loaded, you should see the LEDs blinking on your board.

Adding custom VHDL modules or Altera IP

If you want to instantiate a custom VHDL/IP module in bladerf-hosted.vhd, you will need to also reference the source of that module in bladerf-hosted.qip so that the build script will find it. Follow the steps below:

  1. Write/obtain a VHDL file for your custom module, or generate Altera IP using Quartus.
  2. Instantiate the module in bladerf-hosted.vhd using the same syntax of other instantiated modules
    <instance name>: entity work.<entity name of module>
  3. Open bladerf-hosted.qip and add the relative path to your module.
    For a custom VHDL module, add
    set_global_assignment -name VHDL_FILE [file normalize [file join $here <relative_path_to_your_VHDL_file>.vhd]]
    For Altera-generated IP, add
    set_global_assignment -name QIP_FILE [file normalize [file join $here <relative_path_to_your_IP_file>.qip]]
  4. Run the build script to build the FPGA bitstream.
Note: If you are generating Altera IP cores using a free version of Quartus (i.e. Quartus II Web Edition) without an IP license, you may not be able to generate a .rbf bitstream file to load the bladeRF FPGA with. Instead you will be required to use Altera's OpenCore Plus evaluation feature to load the FPGA. This means that a time-limited .sof file will be generated (placed in hdl/quartus/work/output_files) and must be loaded on to the FPGA using the USB Blaster cable (available here) connected to the FPGA's JTAG header (J38). This can be done in Quartus. You can either keep the cable attached after you program the FPGA, and the IP core will work without a time limit, or you can detach the cable and the IP core will work for a limited time (ex: For the FFT core, the time limit is 1 hour).

Examples

Related Resources

Clone this wiki locally