Main Content

Use MATLAB FPGA I/O Host Interface to Communicate with FPGA on Zynq-Based Radio

This example shows how to prototype an FPGA design on a Xilinx Zynq-based radio and communicate with hardware by using MATLAB as the host computer. In this example, you can deploy a waveform transmitter and receiver algorithm on hardware, and then transmit and receive the stream signals through the MATLAB host.

In this example, you to interact with an FPGA design that is running on the hardware. Working with hardware helps you to rapidly prototype designs, verify functionality, tune key parameters, connect to real-world signals, collect data for analysis, and more.

This example highlights how to:

  • Generate simple algorithm that runs on hardware.

  • Generate HDL IP core and host interface script for your design

  • Use host interface script to establish connection with the hardware

  • Deploy bitstream and integrate HDL IP core on hardware

  • Write input stream signal to your FPGA design

  • Read output stream signal from your FPGA design for analysis

Prerequisites

Install and configure these support packages and third-party tools.

After installing HDL Coder Support Package for Xilinx FPGA and SoC Devices, obtain the Linux image from the install directory. To get required path, enter the command:

>> fullfile(matlabshared.supportpkg.getSupportPackageRoot,'3P.instrset','xilinxlinuxbinaries.instrset','zc706')

System Architecture

This figure shows the high-level architecture of the system in this example.The host computer communicates to the FPGA through the processing system on the System on Chip (SoC) board. The host computer can also tune parameters by writing to AXI4-Lite registers in the algorithm IP core.

The HDL IP core on the Zynq® programmable logic (PL) combines:

  • Waveform transmission from the FPGA RAM to the radio front end

  • Power signal computation of both the transmitted and received waveforms

  • Triggering logic

The Zynq® processing system (PS) performs these tasks:

  • Loading the waveform from the ARM processor to the FPGA RAM for transmission onto SDR

  • Receiving the computed power signals from the PL

Unlike the code generation and deployment on the PS, which happens while using software interface model, when you use the fpga() function in the MATLAB host, the IIO drivers in the PS transmit and receive the signals.

The waveform transmission and reception is trigger-based and the algorithm computes the power signals of the transmitted and received waveforms. Because the algorithm is trigger-based and deals with packetized data, the example uses AXI4-Stream interface instead of the I/Q stream to manage the data transmission between the ARM processor and the FPGA.

The HDL IP core has these port interfaces:

  • AXI4-Stream input ports for writing the waveform into FPGA RAM

  • AXI4-Stream output ports for reading the computed power of transmitted and received signals into the PS

  • AXI4-Lite input ports for real-time control and adjustment of the design

  • AXI DMA ports for data movement of the I/Q samples between the HDL IP core and the PS

  • The transmitter and receiver base-band ports for data movement of the I/Q samples between the HDL IP core and the AD936x IP

Open the Model

The hdlcoder_radio_loopback model is compatible with hardware generation. You can use this model to generate HDL code for the PL and generate a host interface script by using the HDL Workflow Advisor. Using the host interface script, you can connect to the design running on the hardware.

The HDL_DUT subsystem models the functionality to be implemented on the PL. The highlighted blocks outside the subsystem represent the control functionality to be implemented on the PS.

modelname = 'hdlcoder_radio_loopback';
load_system(modelname);
open_system(modelname);

The Tx and Rx subsystems model the transmitter and receiver logic of the PL algorithm, respectively.

currentSubSys = 'HDL_DUT';
open_system([modelname '/' currentSubSys]);

In the Tx subsystem, a valid input frame of AXI4-S data writes to the dual-port block RAM. The maxTxCount and txSel input ports control the transmission of the data in the Tx subsystem, and the txStart input port triggers the transmission of data.

currentSubSys = 'HDL_DUT/Tx';
open_system([modelname '/' currentSubSys]);

The Rx subsystem computes the power for both the transmitted and received signals as I/Q squared magnitude. To provide padding, the Valid Out Output port outputs a valid period that corresponds to 1.5 times the frame size of the transmitted signal. This padding accounts for the time taken for the transmitted waveform to appear at the receiver.

currentSubSys = 'HDL_DUT/Tx';
open_system([modelname '/' currentSubSys]);

The HDL_DUT subsystem has designated ports that model AXI4 data paths between the PS and PL.

The AXI4-Lite registers are:

  • maxTxCount, which defines the maximum number of transmit signal samples (up to 2047)

  • txStart, which triggers a single transmission of maxTxCount samples when set to true

  • txSel, which switches between transmitting data stored in the FPGA RAM to the PS or to the ramp signal

The AXI4-Stream interfaces are:

  • AXI4S_Data_In, which loads transmission data from the PS to the FPGA RAM

  • AXI4S_Data_Out, which retrieves computed power of Tx and Rx signals to the PS

Simulate the Model

Simulate this model to confirm its operation. A chirp signal is defined in workspace variable inpSig. The Tx Data block reads the signal into the model and scales it for representation by the int16 fixed-point data type. The Write Tx Data block generates AXI4-Stream Data and Valid signals, which writes the signal samples to RAM in the HDL_DUT subsystem. The Max Tx Count, Tx Start and Tx Select blocks model the AXI4-Lite control registers.. The values of these blocks trigger a single transmission of the chirp signal, followed by a single transmission of the ramp signal for 2047 samples which loop back over the I/Q interfaces. This transmission triggers a receive at the same time which captures both the transmitted and received signal for a certain length and calculates the power of both signals before transferring them over the AXI4-Stream Data and Valid signals.

The image shows the power output of the Tx and Rx data frames in the Scope block.

After the simulation completes, you can start the process of generating the HDL IP Core, integrating the core with the SDR reference design, and generating the host interface script.

Generate the IP Core

First set up the Xilinx tool chain by invoking the hdlsetuptoolpath function. For example:

>> hdlsetuptoolpath('ToolName','Xilinx Vivado','ToolPath','C:\Xilinx\Vivado\2023.1\bin\vivado.bat');

Register the custom boards and compile ADI IP path to MATLAB path for creating a Vivado project by entering these commands:

hdlcoder_amd_examples_root
addpath(fullfile(hdlcoder_amd_examples_root,'ZC706'))
addpath(fullfile(hdlcoder_amd_examples_root,'ipcore'))
hdlcxilinx.internal.hwsetup.compileADIIP

Running the compilation for first time in MATLAB takes several minutes to complete.

Right-click the HDL_DUT subsystem and select HDL Code > HDL Workflow Advisor.

1. In step 1.1, set Target workflow to IP Core Generation and Target platform to Xilinx Zynq ZC706 evaluation kit.

2. In step 1.2, set Reference design to Radio loopback with AXI4-Stream Interface. For this example, you can use the default reference design parameters.

3. In step 1.3, review the data in the Target platform interface table section. The Workflow Advisor automatically maps the DUT signals to the interface signals in the reference design.

4. In step 1.4, set the Target Frequency (MHz) parameter to the DUT synthesis frequency.. The DUT synthesis frequency depends on the baseband sampling rate of the system. In this example, the sample rate is 3.84 MHz, so a synthesis frequency of at least 4 MHz is sufficient.

5. Right-click step 2 and click Run to Selected Task to perform the design checks.

6. Right-click step 3 and click Run to Selected Task to generate the HDL code for the IP core.

Generate Host Interface Script

Next, you use the generated host interface script and modify it to:

  • Create a hardware object to establish a connection to your FPGA.

  • Deploy the bitstream on hardware.

  • Write input control signals and stream signals to the PS.

  • Read the output stream signals from the PS.

After you use the fpga function to read the stream signal from the PS to the MATLAB host, you unpack the data to visualize the behaviour of the design.

To generate a host computer interface to the IP core and deploy the design to the target hardware board:

1. In step 4.1, click Run This Task.. This task inserts the generated IP core for the FPGA algorithm into the reference design and creates the system shown in the system architecture diagram.

2. In step 4.2, select Generate host interface script and clear the Generate Simulink software interface model. Then, click Run this task.

HDLWFA_Step_4.2.png

The HDL Workflow Advisor generates two MATLAB files in your current folder. You can use these files to prototype your generated IP core directly from MATLAB.

generated_scripts_image.png

Generate Bitstream

Step 4.3 generates a bitstream for the PL. You can execute this step in an external shell by selecting Run build process externally. This selection allows you to continue using MATLAB while building the FPGA image. Next, click Run This Task. After the HDL Workflow Advisor completes the product checks, it marks step 4.3 with a green check mark. You must wait until the external shell displays a successful bitstream build before continuing on to the next step.

When the bistream is ready, you can load it on the hardware board by using the host interface script.

Interact with the FPGA Design from the Host Computer

Interact with the FPGA design by reading and writing data through MATLAB on the host computer.

Open the generated script file by entering:

open gs_hdlcoder_radio_loopback_interface.m

Using host interface script, you can:

  • Program the FPGA hardware with the generated bitstream and configure the processor with the device tree, which requires board IP address as well.

  • Create an fpga hardware object, which represents a connection to the FPGA on your hardware board.

  • Configure the fpga object with the desired hardware interfaces and ports from your DUT algorithm.

  • Read and write data to the DUT to exercise your algorithm on the hardware.

  • Release the hardware board from the current MATLAB session.

You can modify the interface script depending on the algorithm implemented in your Simulink model.

Open the generated setup function by entering:

open gs_hdlcoder_radio_loopback_setup.m

This function configures the fpga hardware object with the same ports and interfaces specified in task 1.3. Set Target Interface.

  • Under AXI4-Lite section, DUT input ports such as maxTCount,txStart, and txSel are mapped to AXI registers because the table in step 1.3 declared these ports as AXI4-Lite.

  • Similarly, the DUT input port AXI4S_Data_In and DUT output port AXI4S_Data_Out are mapped to AXI4-Stream Read and AXI4-Stream Write, respectively.

l

You can also modify the setup script depending on the algorithm you implement in your Simulink model. You can alter parameters, such as WriteFrameLength and ReadFrameLength, as shown in this example. In this setup script, the values for WriteFrameLength and ReadFrameLength have been adjusted from 1024 to 2048. However, you cannot change parameters like IOInterface because they have been defined to work as intended.

Configure the Software Defined Radio (SDR)

This example uses the System Object hdlcoder.sdr to configure the AD9361/AD9364 transmitter and receiver, respectively. The transmitter and receiver do not send data from the PS to the PL but configuring them initializes RF parameters and enables transmit and receive data paths.

Before performing any write or read operations using host interface script, the configure the SDR. If not, the SDR can take erroneous values and exhibit unexpected behaviour.

Run Host Interface Script on the Target

Modify the generated host script as shown in this code. First, initialize all the variables in the script and then load the generated bitstream on the hardware board. The sel variable selects between the internally generated ramp signal and externally passing signal. After the bitstream loads, you can verify the SDR connection to hardware.

%% Variables Initialization

IPAddress = '192.168.3.2'; %Hardware board IP address
Fc = 2.4e9;    %Center Frequency
Fs = 3840000;  % Sampling Frequency
nsamp = 2048;  %Number of time samples
ntxSampleS = 2048;     %Number of transmit signal samples
txGain = -10;  %SDR transmitter gain
rxGain = 1;    %SDR receiver gain
FrameSize = 2048;
t = (0:nsamp)/Fs;
sel = input('Enter 0 to see the internal ramp and 1 for externally passing signal:  ') %#ok<NOPTS>
sel = 1
hProcessor = xilinxsoc(IPAddress,'root','root');
programFPGA(hProcessor, "hdl_prj\vivado_ip_prj\vivado_prj.runs\impl_1\system_top.bit", "devicetree_fmcomms2_axis.dtb");
### Programming FPGA device on Xilinx Zynq ZC706 hardware board at 192.168.3.2...
### Copying FPGA programming files to SD card...
### Setting FPGA bitstream and devicetree for boot...
# Copying Bitstream system_top.bit to /mnt/hdlcoder_rd
# Set Bitstream to hdlcoder_rd/system_top.bit
# Copying Devicetree devicetree_fmcomms2_axis.dtb to /mnt/hdlcoder_rd
# Set Devicetree to hdlcoder_rd/devicetree_fmcomms2_axis.dtb
# Set up boot for Reference Design: ''
### Rebooting Xilinx Zynq ZC706 at 192.168.3.2...
### Reboot may take several seconds...
### Attempting to connect to the hardware board at 192.168.3.2...
### Connection successful
%% Create fpga object

hFPGA = fpga(hProcessor);
%% Configure SDR

SDRTxRx = hdlcoder.sdr('AD936x', ...
    IPAddress = IPAddress,...
    CenterFrequency = Fc,...
    ChannelMapping = [1 2],...
    BasebandSampleRate = Fs,...
    TxGain = txGain,...
    RxGain = rxGain,...
    SamplesPerFrame = FrameSize);
setup(SDRTxRx);
## Establishing connection to hardware. This process can take several seconds.
## Establishing connection to hardware. This process can take several seconds.
%% Setup fpga object
% This function configures the "fpga" object with the same interfaces as the generated IP core

gs_hdlcoder_radio_loopback_setup(hFPGA);
%% AXI4-Stream Read

%writePort(hFPGA, "AXI4S_Data_In",int32(1000*sin(2*pi*20e3*(0:2047)/Fs)));
writePort(hFPGA, "AXI4S_Data_In",int32(1000*chirp(t(1:2048),0,t(2048),Fs/20,[],90)));
%writePort(hFPGA, "AXI4S_Data_In",int32(1000*sawtooth(2*pi*20e3*(0:2047)/Fs)));
%% AXI4 Lite

if(sel == 0)
 writePort(hFPGA, "txSel", zeros([1 1]));
else
 writePort(hFPGA, "txSel", ones([1 1]));
end
 writePort(hFPGA, "maxTxCount", int16(ntxSampleS-1));
 writePort(hFPGA, "txStart", ones([1 1]));
%% AXI4-Stream Write

data_AXI4S_Data_Out = readPort(hFPGA, "AXI4S_Data_Out");
%% Data Unpacking

dataReceived = typecast(data_AXI4S_Data_Out,'int16');
rxPower = dataReceived(1:2:4096);
txPower = dataReceived(2:2:4096);
subplot(2,1,1)
%figure
plot(t(1:end-1),txPower)
title('TxPower');
xlabel('-->time (sec)')
ylabel('-->Power (W)')
subplot(2,1,2)
%figure
plot(t(1:end-1),rxPower)
title('RxPower');
xlabel('-->time (sec)')
ylabel('-->Power (W)')

release(hFPGA);
delete(hFPGA);

After the SDR configuration completes, the writePort function passes input stream signal and control signals and the data coming from the DUT output port AXI4S_Data_Out is read into data_AXI4S_Data_Out through readPort.

The data type of the AXI4S_Data_Out is int32. The MSB 16 bits contains the information pertaining to TxPower. LSB 16 bits contains the information of RxPower. Hence data unpacking is required to separate TxPower and RxPower.

Finally, the release command releases the fpga handle from the MATLAB session and the delete command deletes the variable completely from the MATLAB workspace.

See Also

| |

Related Topics