Wiki

This version is outdated by a newer approved version.DiffThis version (18 Aug 2016 22:26) is a draft.
Approvals: 0/1
The Previously approved version (05 Aug 2016 20:50) is available.Diff

This is an old revision of the document!


A simple BBP for RF Transceivers

This wiki page is a follow up documentation for the ADI article titled “A Simple Baseband Processor for RF Transceivers”. The article covers the theory and implementation details of a simple BBP using the ZC706 + AD-FMCOMMS3 rapid prototyping platform. This page details the demonstration and build process of the BBP design on the ZC706 + AD-FMCOMMS3 hardware.

Please note that Analog Devices does NOT support this design. It is unlikely that we maintain this core or design as we would the reference design. The recommended procedure for a BBP design is to model it in Simulink and subsequently implement the design using HDL coder. The core of the axi_xcomm2ip is intentionally obfuscated to discourage any use or modification of the IP. However, the radio communication demonstration detailed here may be used as a frame work and implementation flow for such designs. It is also meant to illustrate a work flow using the ADI github repositories, especially the HDL. The build process serves as a use case example for a set of frequently asked questions about the use of the HDL repository and the project frame work.

This document and the design, at present, is applicable and built only for Xilinx tools and devices. An Altera equivalent is in the plans and may be added sometime in the near future. It is assumed that the reader is familiar with the ADI reference designs, Vivado, TCL scripts and Linux. Also note that the instructions exclusively use a Linux command line environment. Please do not seek support or ask questions outside the scope of this document.

This guide has two sections, the first section covers the hardware demonstration, what it is and how to run it. The second section covers the build process of the demo from the source files.

Setup and Running the demo

The demo is a simple chat (as in transmitting and receiving text messages) program between two ZC706 + AD-FMCOMMS3-EBZ platforms. You may place the two boards adjacent to each other within your lab desk space. Please do NOT try to use it with your significant other(s) across the seven seas. The best learning or experimentation setup requires two hardware platforms. This allows one to understand the importance and need for carrier tracking. It is possible for you to run the demo on a single platform in loopback mode. The default setup assumes two independent hardware platforms. So the single platform loopback mode requires some additional LO changes.

Download run-time files

Setup (host Linux desktop)

The setup assumes that you are familiar with the AD-FMCOMMS3-EBZ user guide and used it to capture some signals or at least done a sanity level testing. You also have the image with the boot and file system partitions in the SD card.

To begin with, download the RFBBP demo run-time files and extract the contents.

[~]> mkdir rfbbp
[~]> cd rfbbp

[~/rfbbp]> gunzip runfiles.tar.gz
[~/rfbbp]> tar -xvf runfiles.tar

Now mount your SD card. You should see two mount points; BOOT and rootfs. The software routines run in user space and we need a directory to keep them. This way, you can blow it away if you need it to be. You may have to be a little mindful of the file permissions as the board user is “analog”. A simple solution is to grant the permissions to everyone.

[~/rfbbp]> cp uImage /media/rkutty/BOOT/
[~/rfbbp]> cp BOOT.BIN /media/rkutty/BOOT/
[~/rfbbp]> cp devicetree.dtb /media/rkutty/BOOT/

The following are the Linux user space files and are copied to the “xcomm2ip” folder in the home directory.

[~/rfbbp]> mkdir -p /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> cp xcomm2ip_m.c /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> cp xcomm2ip.c /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> cp xcomm2ip.sh /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> cp xcomm2ip_1.ini /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> cp xcomm2ip_2.ini /media/rkutty/rootfs/home/analog/xcomm2ip/
[~/rfbbp]> chmod go+rwx /media/rkutty/rootfs/home/analog/xcomm2ip/*.*

Now unmount the SD card 1, and mount SD card 2 and repeat the same process. After that, unmount SD card 2. If you haven't already done so, you need to prepare the two hardware platforms (let's designate them as SYSTEM-1 and SYSTEM-2 for easy reference) with the keyboard, mouse and display connections. Insert the SD cards into the SYSTEM-1 and SYSTEM-2 ZC706 boards and power them up. The rest of the setup is done in the hardware platforms. That is, the following instructions do NOT use your host machine.

Setup SYSTEM-1 (board Linux desktop)

In the desktop, open a terminal and login as root. If the OSC application is already open and running, close it. Then run the shell script with the “System ID” set to 1. The script compiles the two c files and then opens three terminals. In the first terminal it runs the osc application with a profile that sets the receive and transmit LO differenty. The second is a “view” terminal. This terminal echo the transmit text messages and display the received text messages. The third terminal is the “transmit-text-entry” terminal. You may enter the text messages in this terminal. A null entry (pressing enter without any text) exits the chat routines. This in any way meant to suggest or otherwise taken as a method of writing an application. This is discussed in detail later in the build process section.

[~/xcomm2ip]> ./xcomm2ip.sh
System ID [1|2]> 1

If you are running this demo in a single system with loopback, set the receive and transmit LO frequencies to be the same.

Setup SYSTEM-2 (board Linux desktop)

As you may have now guessed, the setup is same as SYSTEM-1 except that you set the ID to 2. This sets the receive LO frequency of SYSTEM-2 same as the transmit LO frequency of SYSTEM-1 and the transmit LO frequency of SYSTEM-2 same as the receive LO frequency of SYSTEM-1.

[~/xcomm2ip]> ./xcomm2ip.sh
System ID [1|2]> 2

Using the chat application

Now you may enter text messages in the “transmit-text-entry” terminals of either SYSTEM-1 or SYSTEM-2 and the “view” terminal of the “other” system should display them. This all seem a round about way of “talking to yourself”, but that is not really the idea here. As you may now be thinking you don't have much to communicate with your “other-self”, exit the applications and shutdown the system gracefully to return to read the rest of this document as it explains some behind-the-demo points which may be a bit more exciting than the demo itself.

Building the demo files from source

The main intent behind this design excercise is to illustrate as an example to some of the most frequently asked questions about the HDL repository and how to modify and use it. The following sections may be able to give you some ideas. These sections do a walk through of the build process to generate the demo files above from the source files. As we go through these sections, we cover the above mentioned frequently asked question and reveal (hopefully) our method to madness.

Download Source files

Setup a workspace

How to best use the HDL repository?

The ADI reference design repositories are hosted on GitHub. If you are familiar with git and the concepts and use of merging, branching and all that sort of thing you don't need to read this. If you are not or wish to be different, as many have pointed out, the simple best way would be to clone it and leave it as it is. Occassionally, perhaps, fetching and rebasing it. In this section, we show how to setup these repositories in your environment and use your own repository structure and version control along with it. Once again, the goal is to leave the ADI repository AS IT IS and do all the customizations outside of it.

[~]> mkdir rfbbp
[~]> cd rfbbp

[~/rfbbp]> git clone git@github.com:analogdevicesinc/hdl.git
[~/rfbbp]> cd hdl
[~/rfbbp/hdl]> git checkout hdl_2016_r1
[~/rfbbp/hdl]> git fetch
[~/rfbbp/hdl]> git rebase origin/hdl_2016_r1
[~/rfbbp/hdl]> cd ..

We also need linux, but it doesn't work the way of HDL. We handle this a little differently, but let's also clone this as it is needed for our build flow.

[~/rfbbp]> git clone git@github.com:analogdevicesinc/linux.git
[~/rfbbp]> cd linux
[~/rfbbp/linux]> git checkout 2016_R1
[~/rfbbp/linux]> git fetch
[~/rfbbp/linux]> git rebase origin/2016_R1
[~/rfbbp/linux]> cd ..

Creating the IP library

How do I create my own Vivado IP library and IP core?

The RFBBP is developed as an IP core that is part of a different library separate from the ADI library. A Vivado library is just a directory that needs to contain some specific files. In our case, we create a library (named “ip”) and the RFBBP core (named “axi_xcomm2ip”) inside our workspace. The generic set of files an IP needs are the Makefile, HDL files, constraints (if any) along with a TCL file to build the IP. The structure of our source files is presented below , that is - this is how you see the downloaded source files. You do NOT run these commands but simply extract the source files from the archive. The files falls into the directory structure referenced here.

[~/rfbbp]> mkdir -p ip/axi_xcomm2ip
[~/rfbbp]> touch ip/axi_xcomm2ip/Makefile
[~/rfbbp]> touch ip/axi_xcomm2ip/axi_xcomm2ip.v
[~/rfbbp]> touch ip/axi_xcomm2ip/axi_xcomm2ip_constr.xdc
[~/rfbbp]> touch ip/axi_xcomm2ip/axi_xcomm2ip_ip.tcl

This library can later be added to the Vivado library search paths to include all the IP cores within as follows. This is detailed in the project script flow further sections below.

set_property ip_repo_paths ip [current_fileset]

What to write in a TCL file to create a custom IP core?

The thing about the TCL flow is that it makes the tool conform to our needs. It is better we don't go into the tools (that will be too long), but consider this- so far we were unable to generate the Vivado library files across various versions using the same TCL script. However, if your plan is to stay with a single version of the tools you may not need to use the TCL flow. Simply create a new project with your files and package it to an IP core. Those who wish to use the TCL flow, it is just calling out a few TCL procedures. As Xilinx changes its commands and functionality over each version of the tool, we change them within these procedures so that bulk of our library remains unaltered. The only thing to note is the use of the environment variable “AD_HDL_DIR”. This variable is used to point to the ADI HDL repository and use the files and scripts inside of it. Here is the snippet of RFBBP's TCL file.

set ad_hdl_dir $::env(ADI_HDL_DIR)
set ad_phdl_dir $::env(ADI_HDL_DIR)

source $ad_hdl_dir/library/scripts/adi_ip.tcl

adi_ip_create axi_xcomm2ip
adi_ip_files axi_xcomm2ip [list \
  "$ad_hdl_dir/library/common/ad_rst.v" \
  "$ad_hdl_dir/library/common/ad_mem.v" \
  "$ad_hdl_dir/library/common/up_axi.v" \
  "axi_xcomm2ip_core.v" \
  "axi_xcomm2ip.v" ]

adi_ip_properties axi_xcomm2ip
adi_ip_constraints axi_xcomm2ip [list \
  "axi_xcomm2ip_constr.xdc" ]

ipx::save_core [ipx::current_core]

What to write in a Make file to create a custom IP core?

As with the TCL file, the Makefile is also a choice. If you choose to follow our frame work, simply list your dependencies and targets. Again note the export of the environment variable. This variable is set based on the workspace setup we discussed above, and the code snippet is below.

Show Makefile Contents:

How do I build the IP cores and library

In order for our directory “ip” to be a library, it must alteast have one core inside it. The “core” is nothing but the generated files from the tool. Also note that you don't need to generate this separately, the project make does check the existence of all the cores it needs and builds them accordingly.

[~/rfbbp]> cd ip/axi_xcomm2ip
[~/rfbbp/ip/axi_xcomm2ip]> make
[~/rfbbp/ip/axi_xcomm2ip]> cd ../..
[~/rfbbp]>

Creating the IP core

How do I create a custom AXI IP core using ADI frame work?

As mentioned in the article, the RFBBP IP is an AXI core, making it a peripheral that interfaces to the processor so that it can be accessed via software. In order to create an AXI IP core, one could make use of the ADI library common modules. All you need in such a case would be to instantiate the “up_axi” module. This module interfaces to the processor's AXI master bus (via an interconnect in most cases) and translates AXI bus transactions to simple memory like interface internally. The BBP IP core illustrates how to use this interface to implement the register and memory address space for the processor access. The “up_axi” module uses dword addressing, instead of the AXI byte addressing. The following code in the RFBBP core infers the “up_axi” module, there by in-effect creating it as an AXI IP core.

  wire            up_clk;
  wire            up_rstn;
  wire            up_wreq_s;
  wire    [13:0]  up_waddr_s;
  wire    [31:0]  up_wdata_s;
  wire            up_wack_s;
  wire            up_rreq_s;
  wire    [13:0]  up_raddr_s;
  wire    [31:0]  up_rdata_s;
  wire            up_rack_s;

  assign up_clk = s_axi_aclk;
  assign up_rstn = s_axi_aresetn;

  up_axi i_up_axi (
    .up_rstn (up_rstn),
    .up_clk (up_clk),
    .up_axi_awvalid (s_axi_awvalid),
    .up_axi_awaddr (s_axi_awaddr),
    .up_axi_awready (s_axi_awready),
    .up_axi_wvalid (s_axi_wvalid),
    .up_axi_wdata (s_axi_wdata),
    .up_axi_wstrb (s_axi_wstrb),
    .up_axi_wready (s_axi_wready),
    .up_axi_bvalid (s_axi_bvalid),
    .up_axi_bresp (s_axi_bresp),
    .up_axi_bready (s_axi_bready),
    .up_axi_arvalid (s_axi_arvalid),
    .up_axi_araddr (s_axi_araddr),
    .up_axi_arready (s_axi_arready),
    .up_axi_rvalid (s_axi_rvalid),
    .up_axi_rresp (s_axi_rresp),
    .up_axi_rdata (s_axi_rdata),
    .up_axi_rready (s_axi_rready),
    .up_wreq (up_wreq_s),
    .up_waddr (up_waddr_s),
    .up_wdata (up_wdata_s),
    .up_wack (up_wack_s),
    .up_rreq (up_rreq_s),
    .up_raddr (up_raddr_s),
    .up_rdata (up_rdata_s),
    .up_rack (up_rack_s));

How do I infer register and memory space using the "up_axi" module?

How do I create a custom AXI IP core to be able to use inside an ADI project?

The BBP is implemented as an “insert-able” core in the ADI design. If you are pondering to do something similar in other designs, you could follow the same procedure. However, in terms of placement, this requires a better understanding of the design and the various data path components. If your custom IP core can meet the throughput, placing it next to the interface core is a logical choice. If you need it to be an offline core, place it along with a DMA engine off the DDR memory. This allows you to collect data in the DDR and pass it to your custom core at its own pace.

Once the placement has been fixed, match the “inserting-point” interfaces of the data path. The custom IP core interfaces are simply mirrored from its adjoining cores. As you may have already guessed, the RFBBP is intended to interface with the “axi_ad9361” core. It is placed right in front of the “axi_ad9361” IP core. It is also intended to run at the AD9361 interface clock. So we use the same clock and reset signals as that of the AXI_AD9361 IP.

  input           clk,
  input           rst,

In the receive direction it needs to interface to the ADC data ports of the AXI_AD9361 core. This makes it essentially an offline data processing core. So we mirror the “axi_ad9361” core's adc data interface.

  input           adc_valid_i0,
  input   [15:0]  adc_data_i0,
  input           adc_valid_q0,
  input   [15:0]  adc_data_q0,
  input           adc_valid_i1,
  input   [15:0]  adc_data_i1,
  input           adc_valid_q1,
  input   [15:0]  adc_data_q1,

Similarly, in the transmit direction it needs to interface to the DAC data ports of the AXI_AD9361 core. However, this breaks the default data path of the ADI design in which the DAC data is sourced from the DMA core. So the BBP IP core needs the DMA signals in order to maintain the default data path unless programmed by the software otherwise.

  input           dac_valid_i0,
  input   [15:0]  dma_data_i0,
  output  [15:0]  dac_data_i0,
  input           dac_valid_q0,
  input   [15:0]  dma_data_q0,
  output  [15:0]  dac_data_q0,
  input           dac_valid_i1,
  input   [15:0]  dma_data_i1,
  output  [15:0]  dac_data_i1,
  input           dac_valid_q1,
  input   [15:0]  dma_data_q1,
  output  [15:0]  dac_data_q1,
  input           dma_dovf,
  input           dma_dunf,
  output          dac_dovf,
  output          dac_dunf,

Then infer a simple data interface multiplexer.

  assign dac_data_i0 = dac_data_i0_int;
  assign dac_data_q0 = dac_data_q0_int;
  assign dac_data_i1 = dac_data_i1_int;
  assign dac_data_q1 = dac_data_q1_int;
  assign dac_dovf = dac_dovf_int;
  assign dac_dunf = dac_dunf_int;

  always @(posedge rst or posedge clk) begin
    if (rst == 1'b1) begin
      dac_enable_m1 <= 1'd0;
      dac_enable <= 1'd0;
      dac_data_i0_int <= 'd0;
      dac_data_q0_int <= 'd0;
      dac_data_i1_int <= 'd0;
      dac_data_q1_int <= 'd0;
      dac_dovf_int <= 'd0;
      dac_dunf_int <= 'd0;
    end else begin
      dac_enable_m1 <= up_dac_enable;
      dac_enable <= dac_enable_m1;
      if (dac_enable == 1'b1) begin
        dac_data_i0_int <= dac_data_i;
        dac_data_q0_int <= dac_data_q;
        dac_data_i1_int <= 16'd0;
        dac_data_q1_int <= 16'd0;
        dac_dovf_int <= 1'd0;
        dac_dunf_int <= 1'd0;
      end else begin
        dac_data_i0_int <= dma_data_i0;
        dac_data_q0_int <= dma_data_q0;
        dac_data_i1_int <= dma_data_i1;
        dac_data_q1_int <= dma_data_q1;
        dac_dovf_int <= dma_dovf;
        dac_dunf_int <= dma_dunf;
      end
    end
  end

How do I send my own data to the ADI IP core?

This is NOT something we can answer. However, note that the most of the interface cores are meant to handle analog data. That is, though it is a digital interface, the data must be and considered to be analog. An often asked question is why the data one sent to the DAC does not match the data received at the ADC. This is a mis-conception, the digital data to the DAC is must be and in fact a “digitzed” analog signal.

As for our RFBBP core, it is suffice to say that the rest of the logic generate its own transmit data for the DAC and process the received data from the ADC as it seems fit. This part, though critical to understanding the workings of a radio design, is beyond the scope of this document and is intentionally left out of our discussion.

Modifying and customizing ADI projects

How do I insert a custom AXI IP core inside an ADI project?

Building Linux

Making the HDL IP core accessable to Linux

What do I need to do to access a HDL IP core from Linux?

Accessing the HDL IP core in Linux

How do I access a HDL IP core from Linux?

resources/fpga/docs/hdl/xcomm2ip.1471551993.txt.gz · Last modified: 18 Aug 2016 22:26 by rejeesh kutty