主要内容

Getting Started with NI USRP Targeting

Since R2024a

This example shows how to deploy a custom algorithm on the FPGA of an NI™ USRP™ radio. The example begins with a model of an algorithm that applies a gain to incoming samples and takes you through steps to generate HDL code and deploy the design on your radio.

Workflow

In this example, you follow a step-by-step guide to generate a custom FPGA image from a Simulink® model and deploy it on an NI USRP radio by using a generated MATLAB® host interface script.

For more information about how to prototype and deploy software-defined radio (SDR) algorithms on the FPGA of an NI USRP radio, see Target NI USRP Radios Workflow.

Design Overview

The example uses a simple gain algorithm that receives IQ samples from the radio, applies a numeric gain to the received signal, and sends the output samples to the host through the onboard PL DDR buffer. On the host, you use a live script to transmit a test waveform and receive the output samples from the DUT.

Requirements

To target NI USRP radio devices with Wireless Testbench™, you must install and configure third-party tools and additional support packages.

For details about which NI USRP radios you can target, see Supported Radio Devices.

Note

Generating a bitstream with this workflow is supported only on a Linux® operating system (OS). For details about host system requirements, see System Requirements.

For details about how to install and configure additional support packages and third-party tools, see Installation for Targeting NI USRP Radios.

Set Up Environment and Radio

Set up a working directory for running the example by using the openExample function in MATLAB. This function downloads the example files into a subfolder of the Examples folder in the currently running release and then opens the example. If a copy of the example exists, openExample opens the existing version of the example.

openExample('wt/GettingStartedWithNIUSRPTargetingWorkflowExample')

The working directory contains all the files you need to use this example, including helper functions and files. The files you interact with are:

  • wtGettingStartedUSRPTargetingGainSL.slx — The Simulink hardware generation model. This model includes the DUT subsystem, which implements a simple gain algorithm, and additional subsystems than enable you to simulate the DUT behavior.

  • GettingStartedWithNIUSRPTargetingWorkflowExample.m — The MATLAB script that you can use to simulate the behavior of the Simulink model before you generate HDL code.

  • VerifyGainAlgorithmUsingMATLABExample.m — The live script that you use in MATLAB to verify the algorithm running on your radio.

To program the FPGA on your radio with the bitstream that you generate in this example, and to verify the algorithm running on your radio, use the Radio Setup wizard to connect and set up your radio.

Supported Radios

For details about the USRP radio hardware you can use with this example, see Supported Radio Devices.

Note

If you use this example with a USRP X310 radio with TwinRX daughterboards, you cannot use your radio to transmit a test tone. To verify the design running on your radio by using a transmitted tone, use an external transmitter.

Simulink Hardware Generation Model

The Simulink model in this example is a hardware generation model of an SDR algorithm. Using the HDL Code tab in the Simulink Toolstrip or the HDL Workflow Advisor, you can generate a custom HDL IP core from the model, then generate a bitstream and load it onto the FPGA on your radio. You can then generate a host interface script that provides the MATLAB code you need to interact with the hardware.

Open Model

Open the Simulink model.

The top-level structure of the model includes three subsystems:

  • The Inputs subsystem generates input samples. It uses a Signal Generator block to generate a complex sine wave, which it inputs to the DUT.

  • The Gain subsystem, which is the DUT, applies gain to the incoming samples and outputs the resulting data. The gain applied is determined by the value written to the Write_Gain port.

  • The Outputs subsystem processes the output data for visualization. It converts the data into real and imaginary parts, which it sends to the Scope block to be plotted.

Open the Gain subsystem.

Simulate Model

To confirm the behavior of the model, simulate the model. The scope shows the input sine wave with a magnitude of 0.5 and the output sine wave with a magnitude 2, which confirms that the DUT applies a gain of 4.

Configure IP Core

When you are satisfied with the simulated behavior of the model, you can proceed to integrate your design into a custom IP core by generating HDL code and mapping the model inputs and outputs to the hardware interfaces.

First, use the hdlsetuptoolpath (HDL Coder) function to set up the tool chain. Specify the path to your Vivado® bin directory. For more information, see Set Up Third-Party Tools.

hdlsetuptoolpath('ToolName','Xilinx Vivado', ...
    'ToolPath','/opt/Xilinx/Vivado/2021.1/bin');

From the Apps tab in the Simulink Toolstrip, select HDL Coder. Then open the HDL Code tab.

Configure Output Options

In the HDL Code tab, configure the output options:

  • Ensure the Gain subsystem is pinned in the Code for option. To pin this selection, select the Gain subsystem in the Simulink model and click the pin icon.

  • Select IP Core as the Output > IP Core option.

HDL Code tab in the Simulink Toolstrip

Configure HDL Code Generation Settings

Open the Configuration Parameters dialog box by clicking Settings in the HDL Code tab.

In the HDL Code Generation pane, ensure that Language is set to Verilog. By default, HDL Coder generates the Verilog® files in the hdlsrc folder. You can select an alternative location. If you make any changes, click Apply.

HDL Code Generation panel in the Configuration Parameters window

In the Target pane, configure these settings:

  • Under Workflow Settings, select the IP Core Generation workflow. To set Project Folder, click Browse and select a target location for saving the generated project files. If you do not specify a project folder, the software saves the generated project files in the working directory.

  • Under Tool and Device Settings, select your radio from the Target Platform list. This example uses a USRP N310 radio. If you are using a different radio, adjust the reference design parameters accordingly.

  • Under Reference Design Settings, set Reference Design to the desired reference FPGA image for your design, based on how you set up your hardware. For a USRP N310 radio, you have one option: HG: 1GigE, 10GigE.

    Set the reference design parameters to these values:

    • Number of Input Streams — Set to 1 because the DUT is connected to one data input stream.

    • Number of Output Streams — Set to 1 because the DUT is connected to one data output stream.

    • Sample Rate (S/s) — Set to the maximum supported master clock rate for the target device. This value is set by default. For an N310 radio, this value is 153.6e6.

    • Reference Design Optimization — Set to None. This example uses a simple design that does not require optimizations to meet timing constraints.

    • DUT Clock Source — Set to Radio. When you select this setting, the DUT is clocked at the MCR used by the radio to achieve the specified sample rate. Alternatively, you can set this setting to Custom to set the DUT clock frequency to a user-defined value in the Target Frequency parameter under Objectives Settings.

    • Stream Port FIFO Length (Samples) — Set to Auto. This setting automatically calculates the buffer length for each DUT input and output data streaming port.

    • Register Port FIFO Length (Samples) — Set to Auto. This setting automatically calculates the buffer length for each DUT register port.

    Under Objectives Settings, since the DUT Clock Source is set to Radio, the Target Frequency is fixed at the highest supported MCR of the radio.

Click Apply.

HDL Code Generation > Target panel in the Configuration Parameters window

To apply these settings and close the Configuration Parameters window, click OK.

For more information, see Configure HDL Code Generation Settings.

Map Target Interfaces

In the HDL Code tab, click Target Interface to open the Interface Mapping table in the IP Core editor. To populate the table with your user logic, click the Reload IP core settings button: Reload IP core settings and interface mapping table from model icon.

IP Core Interface Mapping table

The Source, Port Type, and Data Type columns are populated based on the Simulink model. The Interface column automatically populates based on the port names in your model:

  • The Write_Gain port maps to a Write Register interface.

  • The Read_Gain port maps to a Read Register interface.

  • The Data_In, Valid_In, Last_In, and Ready_Out ports map to a Simplified AXI4-stream Input0 interface.

  • The Data_Out, Valid_Out, Last_Out, and Ready_In ports map to a Simplified AXI4-stream Output0 interface.

The Interface Mapping column is populated automatically based on the port names in the model.

To set the interface options for the streaming interfaces, open the Set Interface Options window by clicking Options in the far right of the table.

For the Data_In options, select a receive antenna as the source connection. The DUT receives input samples from this antenna on the radio. Set the stream buffer size to 32768, which is the default setting. The buffer size must be a power of two to ensure optimal use of the FPGA RAM resources. The buffer size is specified in terms of the number of samples, with each sample having a size of 8 bytes.

Data_In interface options

For the Data_Out options, select the PL DDR buffer as the sink connection. The DUT streams samples first to the onboard radio memory buffer, then to MATLAB for post-processing.

Data_Out interface options

When you have populated the table, validate the interface mapping by clicking the Validate IP core settings button: Validate IP core settings and interface mapping icon.

For more information, see Map Target Interfaces.

Generate and Load Bitstream

To generate a bitstream from the configured IP core, first open the deployment settings from the Build Bitstream button.

Deployment Settings button in Build Bitstream drop-down menu

  • Ensure that the Run build process externally option is selected. This setting is the default and it ensures that the bitstream build executes in an external shell, which allows you to continue using MATLAB while building the FPGA image.

  • In the Program Target Device settings, set the IP address. The default is 192.168.10.2. If your radio has a different IP address, update this field with the correct value.

Deployment Settings window

Click Build Bitstream to create a Vivado IP core project and build the bitstream. After the basic project checks complete, the Diagnostic Viewer displays a Build Bitstream Successful message along with warning messages. However, you must wait until the external shell displays a successful bitstream build before moving to the next step. Closing the external shell before this time terminates the build.

The bitstream for this project generates with the name n3xx.bit and is located in the build_N310_HG/build_N310_HG folder of the working directory after a successful bitstream build. If you are using a different radio, the name and location reflects your radio.

To load the bitstream onto the device now, click Program Target Device from the Build Bitstream button. Alternatively, you can load the bitstream later by using the programFPGA function in the generated host interface script.

For more information, see Generate Bitstream and Program FPGA.

Generate Host Interface Scripts

To generate MATLAB scripts that enable you to connect to and run your deployed design on your radio, in the HDL Code tab, click Host Interface Script. This step generates two scripts in your working directory based on the target interface mapping that you configured for your IP core.

  • gs_wtGettingStartedUSRPTargetingGainSL_interface.mHost interface script that creates an fpga object for interfacing with your DUT running on the FPGA from MATLAB. The script contains code that connects to your hardware and programs the FPGA and code samples to get you started with running the algorithm on your radio. For more information, see Interface Script File.

  • gs_wtGettingStartedUSRPTargetingGainSL_setup.mSetup function that configures the fpga object with the hardware interfaces and ports from your DUT algorithm. The function contains DUT port objects that have the port name, direction, data type, and interface mapping information, which it maps to the corresponding interfaces. For more information, see Setup Function File.

    Note

    The number of samples, specified in the FrameSize property, is set by default to 1e5. To change this value or the value of the Timeout property, manually edit the setup function.

Verify Gain Algorithm Using MATLAB

To verify the algorithm running on your radio, use this modified version of the host interface script to transmit test data from MATLAB, loop back the data to the DUT on the FPGA, then plot the output.

Open Live Script

You can open this live script in MATLAB from the example working directory and use it interactively. In the Files panel, navigate to your example working directory and open VerifyGainAlgorithmUsingMATLABExample.m.

Select Radio

Call the radioConfigurations function. The function returns all available radio setup configurations that you saved using the Radio Setup wizard.

savedRadioConfigurations = radioConfigurations;

To update the menu with your saved radio setup configuration names, click Update. Then select the radio to use with this example.

savedRadioConfigurationNames = [string({savedRadioConfigurations.Name})];
radio = savedRadioConfigurationNames(1) ;

Evaluate the transmit antennas available on your radio device. You select an available antenna to transmit test data later in the script.

antennaSelection = hTransmitAntennas(radio);

Create usrp System Object

Create a usrp System object™ with the specified radio. This System object controls the radio hardware.

device = usrp(radio);

Program FPGA

If you have not yet programmed your device with the bitstream, select the load bitstream option to use the programFPGA function. Update the code with your bitstream and device tree file. You can find these files in the programFPGA call in the generated host interface script, gs_wtGettingStartedUSRPTargetingGainSL_interface. If your radio is a USRP X310, you need only a bitstream file to program the FPGA.

loadBitstream = false;
if(loadBitstream)
     programFPGA(device, ...
        "build_N310_HG/build-N310_HG/n3xx.bit", ...     % replace with your .bit file
        "build_N310_HG/build/usrp_n310_fpga_HG.dts");   % replace with your .dts file
end

To configure the DUT interfaces according to the hand-off information file, use the describeFPGA function. Calling this function additionally sets the default values for the SampleRate, DUTInputAntennas, and DUTOutputAntennas properties based on the selections you made in Simulink.

% Replace with your hand-off information file
describeFPGA(device,"wtGettingStartedUSRPTargetingGainSL_wthandoffinfo.mat");

Configure Device

Configure the usrp System object to loop back a test waveform to the input of the DUT. You can loop back the waveform over the air or directly on the FPGA.

To specify a sample rate different from the value selected in Simulink when generating the bitstream, uncomment this line and specify a value for the SampleRate property.

% device.SampleRate = 61.44e6;

By default, the DUT streaming input is connected to the receive antenna you selected in the Simulink workflow. To use a different antenna, uncomment this line and specify a value for the DUTInputAntennas property.

% device.DUTInputAntennas = "RF1:RX2";

Specify a transmit antenna for your test waveform. If your radio has no transmit antennas, for example a USRP X310 radio with TwinRX daughterboards, remove this line. You can use another radio to transmit a signal to capture over the air, or use ambient noise.

device.TransmitAntennas = antennaSelection(1);

Set the LoopbackMode property to FPGA to loop back each transmit antenna to an associated receive antenna on the FPGA. Alternatively, you can select Disabled to transmit and receive data over the air. FPGA loopback is not available on radios that have no transmit antennas.

device.LoopbackMode = "FPGA";

Specify the center frequency and gain for the selected transmit and receive antennas. To loop back over the air, ensure the transmit and receive center frequencies are equal. If FPGA loopback mode is selected, these properties have no effect.

device.ReceiveCenterFrequency = 2400000000;
device.TransmitCenterFrequency = 2400000000;
device.ReceiveRadioGain = 10;
device.TransmitRadioGain = 10;

Create and Set Up FPGA Object

To connect to the DUT on the FPGA of your radio, create an fpga object with the your usrp System object device.

dut = fpga(device);

Set up the fpga object using the generated setup function. This example uses the default frame size of 1e5. If you change the frame size, open the setup function file and manually update RX_STREAM0_FrameSize before you call the setup function.

gs_wtGettingStartedUSRPTargetingGainSL_setup(dut);

Set Up Device Object

To establish a connection with the radio hardware, call the setup function on the usrp System object.

setup(device);

Configure DUT

After connecting to the radio, configure the register ports on the DUT using the writePort and readPort functions.

Write 1 to the Write_Gain register to get a baseline result. Then, read from the Read_Gain register to verify that the value is set.

writePort(dut,"Write_Gain",1);
data_Read_Gain = readPort(dut,"Read_Gain");

% Test read value is the same as the written value
if data_Read_Gain ~= 1
    error("Value read from port 'Read_Port': "+string(data_Read_Gain)+" doesn't match the expected value: 1")
end

Repeatedly Transmit Test Waveform

Transmit a test waveform for exercising the DUT running on your radio. If your radio has no transmit antennas, for example a USRP X310 radio with TwinRX daughterboards, skip this section. You can use an external transmitter or ambient noise as a signal source.

Generate a test waveform as a 16 bit integer scaled in the range intmin("int16") to intmax("int16").

sineAmplitude = intmax('int16')/2;
sineFrequency = device.SampleRate/8;
sineGen = dsp.SineWave(sineAmplitude,sineFrequency,0, ...
    ComplexOutput=true, ...
    SamplesPerFrame=1e5, ...
    SampleRate=device.SampleRate);
testWaveform = int16(floor(sineGen()));

Repeatedly transmit the waveform from the selected transmit antennas by calling the transmit function in continuous mode.

transmit(device,testWaveform,"continuous");

Since the DUT applies an integer gain, you may need to reduce the amplitude of the transmit waveform to prevent clipping. Or, if looping back through the radio antennas, adjust the ReceiveRadioGain and TransmitRadioGain properties of the usrp System object device.

Stream Data from Radio into DUT

To start streaming RF data from the radio front end into the DUT, call the usrp System object as a function. Since the DUT passes out the RF data modified with a gain to the PL DDR Buffer, request a specific number of samples from the radio front end. Otherwise, if the buffer overflows, it will apply back pressure on the data stream and subsequent reads may have stale or no data.

Request a number of samples equal to the DDR buffer allocation in the setup function, which is 1e5.

samplesToRequest = 1e5;
device(samplesToRequest);

Read Buffered Data from DUT Output and Plot

Use the readPort function to read buffered data from the output of the streaming port on the DUT, Data_Out.

[data_Data_Out,numberOfSamples_Data_Out,overflow_Data_Out] = readPort(dut,"Data_Out");

Verify that there is no overflow and the number of valid samples is equal to the number of samples requested from the radio.

if overflow_Data_Out
    error("Overflow output should not be true when reading from a PL DDR Buffer")
end
if numberOfSamples_Data_Out ~= samplesToRequest
    warning("Read: "+string(numberOfSamples_Data_Out)+" number of samples from the buffer, but expected: "+string(samplesToRequest))
end

The length of data from a streaming data port is equal to the frame size specified in the setup function. If insufficient samples are in the buffer when readPort is called, then the data is padded with zeros up to the frame size. Remove any padded data using the number of samples output.

data_Data_Out = data_Data_Out(1:numberOfSamples_Data_Out);

Plot the real part of the first one hundred samples.

plot(real(data_Data_Out(1:100)));
legend("Gain=1")
hold on

Repeat with Different Gain value

Set the Write_Gain register to a different value. Then, request samples from the radio front end, read from the output buffer, and plot.

writePort(dut,"Write_Gain",4);
device(samplesToRequest);
[repeat_data_Data_Out,repeat_numberOfSamples_Data_Out] = readPort(dut,"Data_Out");
repeat_data_Data_Out = repeat_data_Data_Out(1:repeat_numberOfSamples_Data_Out);
plot(real(repeat_data_Data_Out(1:100)));
legend("Gain=1","Gain="+num2str(readPort(dut,"Read_Gain")))

Compare Data using Median

Calculate the median value for the absolute real part of the data from each gain value. Divide this median value by the median value when the gain was set to 1. Compare this value to the gain you set. If you are using a sample rate that requires decimation or interpolation, the beginning of the burst of data may show the effects of the up or down sampling.

controlMedian = median(abs(real(data_Data_Out)));
experimentMedian = median(abs(real(repeat_data_Data_Out)));
gainCalculated = experimentMedian/controlMedian;
gainSet = readPort(dut, "Read_Gain");
disp("Written Gain to DUT: "+string(gainSet)+", Calculated Gain from Data: "+num2str(gainCalculated))
Written Gain to DUT: 4, Calculated Gain from Data: 4

Release Hardware Resources

Release the device System object and the fpga object to disconnect from the hardware.

release(dut);
release(device);

See Also

Topics