USB104 A7: Artix-7 FPGA Development Board - Review

Table of contents

RoadTest: USB104 A7: Artix-7 FPGA Development Board

Author: yesha98

Creation date:

Evaluation Type: Development Boards & Tools

Did you receive all parts the manufacturer stated would be included in the package?: True

What other parts do you consider comparable to this product?: The package does not contain the Zmod ADC / DAC, which could've been really useful for people looking to experiment with Analog signals too. One more point to be noted is, the board lacks Ethernet connectivity, which becomes crucial in some cases, thus adding a NIC Pmod to the package would be appreciable.

What were the biggest problems encountered?: The MIG 7 series - Memory Interface Generator IP has a problem in routing as the sys_clk is in a different bank (Vivado 2017.3). Was unable to fix the problem even after many tries.

Detailed Review:

1. Introduction:

The USB 104 A7, as the name suggests, comes in the PC104 form factor, mainly aimed at use in the Stackable computers. The main advantage of using a stackable computer is its scalability. The boards can be added (scaled) to the requirement of the application such that the memory, programmable fabric, LEs, and other things match the requirement. The board features the famous Artix-7 100T FPGA which is widely used in development boards such as the Arty A7 and Basys boards. This brings us to the question of why USB 104 A7? Well, the answer is, this is an industry-grade board that can withstand drastic changes in temperatures.

 

Update: Course Featuring this board - Summer of FPGAs - Building an Embedded System on FPGA

 

 

Needless to mention the board comes with very good packaging and all basic parts to get the board working such as the Power Adapter and the USB cable.

imageimage

1.1 Key Features:

  • Power Management: The power input source is automatically determined by the supply circuitry. The barrel jack supply is preferred. If a supply is connected when the board is already powered through USB, then the board will seamlessly switch over to the external supply without brownout or reset. If the external supply is disconnected, the board will switch back to USB power, but the onboard supplies will temporarily shut down and then sequence back on.
  • Platform MCU:

The board featured the famous ATmega328PB, which is also used in Arduino boards, to implement the SmartVIO requirements of the SYZYGY standard, set the DDR voltage, configure the USB Hub, and provide information about the power supply settings and SYZYGY ports to the FPGA.

  • DPTI:

The DPTI interface is an 8-bit wide parallel FIFO-style data interface supporting both asynchronous and synchronous modes.

  • FTDI FT2232HQ USB-UART bridge:

One can use PC applications to communicate with the board using the standard Windows COM port command.

Refer to manual for detailed info: https://reference.digilentinc.com/reference/programmable-logic/usb104a7/reference-manual

 

2. RoadTest:

2.1 Detecting the USB-Serial Communication when connecting the board to PC for the first time and running the out-of-box demo.

2.2 Testing onboard USB-JTAG Programmer

2.3 Compatibility with Xilinx ISE (Older versions)

2.4 Testing a design with Pmod VGA

2.5 Testing a design with Pmod SD

2.6 Design to boot Linux

2.7 Testing the GPIO with custom Pmod Starter

       (Includes an interesting section that explains the purpose of this board)

 

Note: Watch the videos at a higher resolution for better clarity.

 

2.1 Detecting the USB-Serial Communication when connecting the board to PC for the first time and running the out-of-box demo:

 

For the development of block designs and ease, the board files are provided on the Digilent website which can be downloaded and added to the design. Vivado detects the board as soon as it is added to the respective directory - C:\Xilinx\Vivado\<version>\data\boards\board_files

image

image

The above images show how Vivado immediately detects the board files for their use in IP and block-based designs.

The board files can be found here: https://github.com/Digilent/vivado-boards/tree/master/new/board_files/usb104-a7/B

 

2.2 Testing onboard USB-JTAG Programmer:

In this test, a simple HDL code for a half adder will be executed on the FPGA to test the on-board buttons, LEDs and finally program the FPGA using the bitstream generated and programmed into the FPGA

 

{tabbedtable}

Getting Started

Tab Content
Create Project image
Give the project a name without spaces

image

Select the Design Entry type

image

Select the board image
Click Finish image

image

A Master XDC file is used as a constraints file for easy coding which can be found in this link: https://github.com/Digilent/digilent-xdc/blob/master/USB104-A7-100T-Master.xdc

 

Output:

 

 

 

 

2.3 Compatibility with Xilinx ISE (Older versions):

There are many developers and engineers still working with older versions of design software due to compatibility issues and because their previous designs might now work with newer versions of the software

due to software and IP upgrades or major upgrades. Thus it is essential to test if the board works with older versions and other software.

The below video illustrates the compatibility with the Xilinx ISE - Boundary-scan in iMPACT(I hope people still remember that)

 

 

The board is very well compatible with the Xilinx ISE and one can use it for simple designs with HDL code as the board files are not compatible with the ISE format.

 

 

2.4 Testing a design with Pmod VGA:

 

A sample code to test Pmod VGA in VHDL. Resolution: 1920 * 1080 @ 60Hz

top.vhd:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;


entity top is
    Port ( CLK_I : in  STD_LOGIC;
           VGA_HS_O : out  STD_LOGIC;
           VGA_VS_O : out  STD_LOGIC;
           VGA_R : out  STD_LOGIC_VECTOR (3 downto 0);
           VGA_B : out  STD_LOGIC_VECTOR (3 downto 0);
           VGA_G : out  STD_LOGIC_VECTOR (3 downto 0));
end top;


architecture Behavioral of top is


component clk_wiz_0
port
 (-- Clock in ports
  CLK_IN1           : in     std_logic;
  -- Clock out ports
  CLK_OUT1          : out    std_logic
 );
end component;


--Sync Generation constants


----***640x480@60Hz***--  Requires 25 MHz clock
--constant FRAME_WIDTH : natural := 640;
--constant FRAME_HEIGHT : natural := 480;


--constant H_FP : natural := 16; --H front porch width (pixels)
--constant H_PW : natural := 96; --H sync pulse width (pixels)
--constant H_MAX : natural := 800; --H total period (pixels)


--constant V_FP : natural := 10; --V front porch width (lines)
--constant V_PW : natural := 2; --V sync pulse width (lines)
--constant V_MAX : natural := 525; --V total period (lines)


--constant H_POL : std_logic := '0';
--constant V_POL : std_logic := '0';


----***800x600@60Hz***--  Requires 40 MHz clock
--constant FRAME_WIDTH : natural := 800;
--constant FRAME_HEIGHT : natural := 600;
--
--constant H_FP : natural := 40; --H front porch width (pixels)
--constant H_PW : natural := 128; --H sync pulse width (pixels)
--constant H_MAX : natural := 1056; --H total period (pixels)
--
--constant V_FP : natural := 1; --V front porch width (lines)
--constant V_PW : natural := 4; --V sync pulse width (lines)
--constant V_MAX : natural := 628; --V total period (lines)
--
--constant H_POL : std_logic := '1';
--constant V_POL : std_logic := '1';




----***1280x720@60Hz***-- Requires 74.25 MHz clock
--constant FRAME_WIDTH : natural := 1280;
--constant FRAME_HEIGHT : natural := 720;
--
--constant H_FP : natural := 110; --H front porch width (pixels)
--constant H_PW : natural := 40; --H sync pulse width (pixels)
--constant H_MAX : natural := 1650; --H total period (pixels)
--
--constant V_FP : natural := 5; --V front porch width (lines)
--constant V_PW : natural := 5; --V sync pulse width (lines)
--constant V_MAX : natural := 750; --V total period (lines)
--
--constant H_POL : std_logic := '1';
--constant V_POL : std_logic := '1';


----***1280x1024@60Hz***-- Requires 108 MHz clock
--constant FRAME_WIDTH : natural := 1280;
--constant FRAME_HEIGHT : natural := 1024;


--constant H_FP : natural := 48; --H front porch width (pixels)
--constant H_PW : natural := 112; --H sync pulse width (pixels)
--constant H_MAX : natural := 1688; --H total period (pixels)


--constant V_FP : natural := 1; --V front porch width (lines)
--constant V_PW : natural := 3; --V sync pulse width (lines)
--constant V_MAX : natural := 1066; --V total period (lines)


--constant H_POL : std_logic := '1';
--constant V_POL : std_logic := '1';


--***1920x1080@60Hz***-- Requires 148.5 MHz pxl_clk
constant FRAME_WIDTH : natural := 1920;
constant FRAME_HEIGHT : natural := 1080;


constant H_FP : natural := 88; --H front porch width (pixels)
constant H_PW : natural := 44; --H sync pulse width (pixels)
constant H_MAX : natural := 2200; --H total period (pixels)


constant V_FP : natural := 4; --V front porch width (lines)
constant V_PW : natural := 5; --V sync pulse width (lines)
constant V_MAX : natural := 1125; --V total period (lines)


constant H_POL : std_logic := '1';
constant V_POL : std_logic := '1';


--Moving Box constants
constant BOX_WIDTH : natural := 8;
constant BOX_CLK_DIV : natural := 1000000; --MAX=(2^25 - 1)


constant BOX_X_MAX : natural := (512 - BOX_WIDTH);
constant BOX_Y_MAX : natural := (FRAME_HEIGHT - BOX_WIDTH);


constant BOX_X_MIN : natural := 0;
constant BOX_Y_MIN : natural := 256;


constant BOX_X_INIT : std_logic_vector(11 downto 0) := x"000";
constant BOX_Y_INIT : std_logic_vector(11 downto 0) := x"190"; --400


signal pxl_clk : std_logic;
signal active : std_logic;


signal h_cntr_reg : std_logic_vector(11 downto 0) := (others =>'0');
signal v_cntr_reg : std_logic_vector(11 downto 0) := (others =>'0');


signal h_sync_reg : std_logic := not(H_POL);
signal v_sync_reg : std_logic := not(V_POL);


signal h_sync_dly_reg : std_logic := not(H_POL);
signal v_sync_dly_reg : std_logic :=  not(V_POL);


signal vga_red_reg : std_logic_vector(3 downto 0) := (others =>'0');
signal vga_green_reg : std_logic_vector(3 downto 0) := (others =>'0');
signal vga_blue_reg : std_logic_vector(3 downto 0) := (others =>'0');


signal vga_red : std_logic_vector(3 downto 0);
signal vga_green : std_logic_vector(3 downto 0);
signal vga_blue : std_logic_vector(3 downto 0);


signal box_x_reg : std_logic_vector(11 downto 0) := BOX_X_INIT;
signal box_x_dir : std_logic := '1';
signal box_y_reg : std_logic_vector(11 downto 0) := BOX_Y_INIT;
signal box_y_dir : std_logic := '1';
signal box_cntr_reg : std_logic_vector(24 downto 0) := (others =>'0');


signal update_box : std_logic;
signal pixel_in_box : std_logic;




begin
  
   
clk_div_inst : clk_wiz_0
  port map
   (-- Clock in ports
    CLK_IN1 => CLK_I,
    -- Clock out ports
    CLK_OUT1 => pxl_clk);


  
  ----------------------------------------------------
  -------         TEST PATTERN LOGIC           -------
  ----------------------------------------------------
  vga_red <= h_cntr_reg(5 downto 2) when (active = '1' and ((h_cntr_reg < 512 and v_cntr_reg < 256) and h_cntr_reg(8) = '1')) else
              (others=>'1')         when (active = '1' and ((h_cntr_reg < 512 and not(v_cntr_reg < 256)) and not(pixel_in_box = '1'))) else
              (others=>'1')         when (active = '1' and ((not(h_cntr_reg < 512) and (v_cntr_reg(8) = '1' and h_cntr_reg(3) = '1')) or
                                          (not(h_cntr_reg < 512) and (v_cntr_reg(8) = '0' and v_cntr_reg(3) = '1')))) else
              (others=>'0');
                
  vga_blue <= h_cntr_reg(5 downto 2) when (active = '1' and ((h_cntr_reg < 512 and v_cntr_reg < 256) and  h_cntr_reg(6) = '1')) else
              (others=>'1')          when (active = '1' and ((h_cntr_reg < 512 and not(v_cntr_reg < 256)) and not(pixel_in_box = '1'))) else 
              (others=>'1')          when (active = '1' and ((not(h_cntr_reg < 512) and (v_cntr_reg(8) = '1' and h_cntr_reg(3) = '1')) or
                                           (not(h_cntr_reg < 512) and (v_cntr_reg(8) = '0' and v_cntr_reg(3) = '1')))) else
              (others=>'0');  
              
  vga_green <= h_cntr_reg(5 downto 2) when (active = '1' and ((h_cntr_reg < 512 and v_cntr_reg < 256) and h_cntr_reg(7) = '1')) else
              (others=>'1')           when (active = '1' and ((h_cntr_reg < 512 and not(v_cntr_reg < 256)) and not(pixel_in_box = '1'))) else 
              (others=>'1')           when (active = '1' and ((not(h_cntr_reg < 512) and (v_cntr_reg(8) = '1' and h_cntr_reg(3) = '1')) or
                                            (not(h_cntr_reg < 512) and (v_cntr_reg(8) = '0' and v_cntr_reg(3) = '1')))) else
              (others=>'0');
              

 ------------------------------------------------------
 -------         MOVING BOX LOGIC                ------
 ------------------------------------------------------
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (update_box = '1') then
        if (box_x_dir = '1') then
          box_x_reg <= box_x_reg + 1;
        else
          box_x_reg <= box_x_reg - 1;
        end if;
        if (box_y_dir = '1') then
          box_y_reg <= box_y_reg + 1;
        else
          box_y_reg <= box_y_reg - 1;
        end if;
      end if;
    end if;
  end process;
      
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (update_box = '1') then
        if ((box_x_dir = '1' and (box_x_reg = BOX_X_MAX - 1)) or (box_x_dir = '0' and (box_x_reg = BOX_X_MIN + 1))) then
          box_x_dir <= not(box_x_dir);
        end if;
        if ((box_y_dir = '1' and (box_y_reg = BOX_Y_MAX - 1)) or (box_y_dir = '0' and (box_y_reg = BOX_Y_MIN + 1))) then
          box_y_dir <= not(box_y_dir);
        end if;
      end if;
    end if;
  end process;
  
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (box_cntr_reg = (BOX_CLK_DIV - 1)) then
        box_cntr_reg <= (others=>'0');
      else
        box_cntr_reg <= box_cntr_reg + 1;     
      end if;
    end if;
  end process;
  
  update_box <= '1' when box_cntr_reg = (BOX_CLK_DIV - 1) else
                '0';
                
  pixel_in_box <= '1' when (((h_cntr_reg >= box_x_reg) and (h_cntr_reg < (box_x_reg + BOX_WIDTH))) and
                            ((v_cntr_reg >= box_y_reg) and (v_cntr_reg < (box_y_reg + BOX_WIDTH)))) else
                  '0';
                
  
 ------------------------------------------------------
 -------         SYNC GENERATION                 ------
 ------------------------------------------------------

  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (h_cntr_reg = (H_MAX - 1)) then
        h_cntr_reg <= (others =>'0');
      else
        h_cntr_reg <= h_cntr_reg + 1;
      end if;
    end if;
  end process;
  
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if ((h_cntr_reg = (H_MAX - 1)) and (v_cntr_reg = (V_MAX - 1))) then
        v_cntr_reg <= (others =>'0');
      elsif (h_cntr_reg = (H_MAX - 1)) then
        v_cntr_reg <= v_cntr_reg + 1;
      end if;
    end if;
  end process;
  
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (h_cntr_reg >= (H_FP + FRAME_WIDTH - 1)) and (h_cntr_reg < (H_FP + FRAME_WIDTH + H_PW - 1)) then
        h_sync_reg <= H_POL;
      else
        h_sync_reg <= not(H_POL);
      end if;
    end if;
  end process;
  
  
  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      if (v_cntr_reg >= (V_FP + FRAME_HEIGHT - 1)) and (v_cntr_reg < (V_FP + FRAME_HEIGHT + V_PW - 1)) then
        v_sync_reg <= V_POL;
      else
        v_sync_reg <= not(V_POL);
      end if;
    end if;
  end process;
  
  
  active <= '1' when ((h_cntr_reg < FRAME_WIDTH) and (v_cntr_reg < FRAME_HEIGHT))else
            '0';


  process (pxl_clk)
  begin
    if (rising_edge(pxl_clk)) then
      v_sync_dly_reg <= v_sync_reg;
      h_sync_dly_reg <= h_sync_reg;
      vga_red_reg <= vga_red;
      vga_green_reg <= vga_green;
      vga_blue_reg <= vga_blue;
    end if;
  end process;


  VGA_HS_O <= h_sync_dly_reg;
  VGA_VS_O <= v_sync_dly_reg;
  VGA_R <= vga_red_reg;
  VGA_G <= vga_green_reg;
  VGA_B <= vga_blue_reg;


end Behavioral;

 

Constraints file:

## 100MHz Clock
set_property -dict { PACKAGE_PIN E3    IOSTANDARD LVCMOS33 } [get_ports { CLK_I }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { CLK_I }];
### Pmod Header JB
set_property -dict { PACKAGE_PIN C4    IOSTANDARD LVCMOS33 } [get_ports { VGA_G[0] }]; #IO_L7P_T1_AD6P_35     Sch=jb[1]
set_property -dict { PACKAGE_PIN B2    IOSTANDARD LVCMOS33 } [get_ports { VGA_G[1] }]; #IO_L10N_T1_AD15N_35   Sch=jb[2]
set_property -dict { PACKAGE_PIN B3    IOSTANDARD LVCMOS33 } [get_ports { VGA_G[2] }]; #IO_L10P_T1_AD15P_35   Sch=jb[3]
set_property -dict { PACKAGE_PIN B4    IOSTANDARD LVCMOS33 } [get_ports { VGA_G[3] }]; #IO_L7N_T1_AD6N_35     Sch=jb[4]
set_property -dict { PACKAGE_PIN B1    IOSTANDARD LVCMOS33 } [get_ports { VGA_R[0] }]; #IO_L9P_T1_DQS_AD7P_35 Sch=jb[7]
set_property -dict { PACKAGE_PIN A1    IOSTANDARD LVCMOS33 } [get_ports { VGA_R[1] }]; #IO_L9N_T1_DQS_AD7N_35 Sch=jb[8]
set_property -dict { PACKAGE_PIN A3    IOSTANDARD LVCMOS33 } [get_ports { VGA_R[2] }]; #IO_L8N_T1_AD14N_35    Sch=jb[9]
set_property -dict { PACKAGE_PIN A4    IOSTANDARD LVCMOS33 } [get_ports { VGA_R[3] }]; #IO_L8P_T1_AD14P_35    Sch=jb[10]


### Pmod Header JC
set_property -dict { PACKAGE_PIN C5    IOSTANDARD LVCMOS33 } [get_ports { VGA_B[0] }]; #IO_L1N_T0_AD4N_35     Sch=jc[1]
set_property -dict { PACKAGE_PIN C6    IOSTANDARD LVCMOS33 } [get_ports { VGA_B[1] }]; #IO_L1P_T0_AD4P_35     Sch=jc[2]
set_property -dict { PACKAGE_PIN B6    IOSTANDARD LVCMOS33 } [get_ports { VGA_B[2] }]; #IO_L2N_T0_AD12N_35    Sch=jc[3]
set_property -dict { PACKAGE_PIN C7    IOSTANDARD LVCMOS33 } [get_ports { VGA_B[3] }]; #IO_L4N_T0_35          Sch=jc[4]
set_property -dict { PACKAGE_PIN A5    IOSTANDARD LVCMOS33 } [get_ports { VGA_HS_O }]; #IO_L3N_T0_DQS_AD5N_35 Sch=jc[7]
set_property -dict { PACKAGE_PIN A6    IOSTANDARD LVCMOS33 } [get_ports { VGA_VS_O }]; #IO_L3P_T0_DQS_AD5P_35 Sch=jc[8]

## Bitstream Settings
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]

 

This project additionally needs a clock gen IP, xci file can download from this link: https://github.com/Digilent/Arty-Pmod-VGA/tree/master/src/ip/clk_wiz_0

The VGA Pmod is connected to JB and JC as shown below:

image

 

Working video:

 

 

2.5 Testing a design with Pmod SD:

This phase of the test consists of creating a block design with MicroBlaze and the Pmod SD IP and using the Xilinx SDK to check the read-write capabilities of the SD card.

 

The SD card will be connected to the JA Pmod connector on the board.

image

 

One more thing that should've been included with this board is the system-reset button which should've been an active low button. Almost all IPs such as the MicroBlaze processor system reset and the MIG series comes with default active low reset mode. While this option of having a system reset button is available in the Arty based boards, this board lacks the dedicated system reset button.

The below image shows how I had to use a resistor connected to one of the GPIOs to use it as an external system reset.

image

 

After creating the block design, run the synthesis, implementation and finally generate the bitstream.

Launch the Xilinx SDK after exporting the hardware with bitstream included.

The C++  code used to test the SD card is given below: (A demo program)

main.cc File:

/******************************************************************************/
/*                                                                            */
/* main.cc -- Demo program for the PmodSD IP                                  */
/*                                                                            */
/******************************************************************************/
/* Author: Thomas Kappenman                                                   */
/* Copyright 2016, Digilent Inc.                                              */
/******************************************************************************/
/*
*
* Copyright (c) 2013-2016, Digilent <www.digilentinc.com>
* Contact Digilent for the latest version.
*
* This program is free software; distributed under the terms of
* BSD 3-clause license ("Revised BSD License", "New BSD License", or "Modified BSD License")
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1.    Redistributions of source code must retain the above copyright notice, this
*        list of conditions and the following disclaimer.
* 2.    Redistributions in binary form must reproduce the above copyright notice,
*        this list of conditions and the following disclaimer in the documentation
*        and/or other materials provided with the distribution.
* 3.    Neither the name(s) of the above-listed copyright holder(s) nor the names
*        of its contributors may be used to endorse or promote products derived
*        from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/******************************************************************************/
/* File Description:                                                          */
/*                                                                            */
/* This demo creates a file in your SD card and writes to it                  */
/*                                                                            */
/******************************************************************************/
/* Revision History:                                                          */
/*                                                                            */
/*    08/10/2016(TommyK):   Created                                           */
/*    01/20/2018(atangzwj): Validated for Vivado 2017.4                       */
/*                                                                            */
/******************************************************************************/


#include "PmodSD.h"
#include "xil_cache.h"
#include "xil_printf.h"




void DemoInitialize();
void DemoRun();




int main(void) {
   Xil_ICacheEnable();
   Xil_DCacheEnable();


   DemoInitialize();
   DemoRun();
   return 0;
}


void DemoInitialize() {


}


void DemoRun() {
   DXSPISDVOL disk(XPAR_PMODSD_0_AXI_LITE_SPI_BASEADDR,
         XPAR_PMODSD_0_AXI_LITE_SDCS_BASEADDR);
   DFILE file;


   // The drive to mount the SD volume to.
   // Options are: "0:", "1:", "2:", "3:", "4:"
   static const char szDriveNbr[] = "0:";


   FRESULT fr;
   u32 bytesWritten = 0;
   u32 bytesRead, totalBytesRead;
   u8 buff[12], *buffptr;


   xil_printf("PmodSD Demo Launched\r\n");
   // Mount the disk
   DFATFS::fsmount(disk, szDriveNbr, 1);


   xil_printf("Disk mounted\r\n");


   fr = file.fsopen("newfile.txt", FA_WRITE | FA_CREATE_ALWAYS);
   if (fr == FR_OK) {
      xil_printf("Opened newfile.txt\r\n");
      fr = file.fswrite("It works!!!", 12, &bytesWritten);
      if (fr == FR_OK)
         xil_printf("Write successful\r\n");
      else
         xil_printf("Write failed\r\n");
      fr = file.fsclose();
      if (fr == FR_OK)
         xil_printf("File close successful\r\n");
      else
         xil_printf("File close failed\r\n");
   } else {
      xil_printf("Failed to open file to write to\r\n");
   }


   fr = file.fsopen("newfile.txt", FA_READ);
   if (fr == FR_OK) {
      buffptr = buff;
      totalBytesRead = 0;
      do {
         fr = file.fsread(buffptr, 1, &bytesRead);
         buffptr++;
         totalBytesRead += bytesRead;
      } while (totalBytesRead < 12 && fr == FR_OK);


      if (fr == FR_OK) {
         xil_printf("Read successful:");
         buff[totalBytesRead] = 0;
         xil_printf("'%s'\r\n", buff);
      } else {
         xil_printf("Read failed\r\n");
      }
   } else {
      xil_printf("Failed to open file to read from\r\n");
   }


   while (1);
}

 

This demo code along with all header files are available in the Pmod library. Link: https://github.com/Digilent/vivado-library/releases/tag/v2019.1-1

 

Output video after running the program:

 

2.6 Design to boot Linux:

 

image

A block design was created with various IP blocks available with the board, such as Clock, Microblaze softcore IP, Quad SPI, UART lite, and the MIG 7 series for the DDR3 interface.

An attempt to boot PetaLinux was made with the above block design but was not successful because of an error in the bitstream generation.

image

Here's a possible solution, but still unable to fix this error due to the clock pin allocation, upgrading to a newer version of Vivado might solve this issue.

A possible solution Link: https://www.xilinx.com/support/answers/60480.html

 

2.7 Why use this board?

As many might be thinking, why this board? this part of the test shall address it.

             imageimageimage

Given above are 3 development boards, all of them feature the Artix-7 FPGA. But comparatively cheaper than the USB104-A7 board.

As one might notice user GPIO and the onboard switches and other components such as 7-segment are absent in the USB104 board. This is because of the key features of the USB104-A7 board that the other two boards do not have. I have listed them below:

      1. USB Hub: This port is connected to a USB hub which breaks out the traffic into several different FPGA-connected interfaces, via an FTDI FT2232HQ USB-UART bridge and an FTDI FT232H hi-speed single-channel USB to UART/FIFO bridge. The USB hub and the two controllers are transparent to the user. A UART interface (referred to as the USB-UART Bridge), the USB-JTAG programming interface, and a parallel data interface (DPTI) are implemented. - Reference Manual.  The USB hub is absent in both the other boards.
      2. DPTI Parallel Data Transfer Interface: The DPTI interface is an 8-bit wide parallel FIFO-style data interface supporting both asynchronous and synchronous modes.
      3. DSPI Interface: Used to communicate with the PC104 stack
      4. Zmod Port: The USB104 A7 features one Zmod port, which uses a SYZYGY Standard interface to communicate with an installed SYZYGY pod. The port is compatible with version 1.1 of the SYZYGY specification from Opal Kelly. Can be used to attach an ADC / DAC for its use as a small oscilloscope or for waveform generation.
      5. Micron 512MB DDR3: High speed DDR3 volatile memory from Micron provides just the right amount of memory to assist your designs

 

The images given below explains how the USB hub is used in the USB104-A7 to route various signals.

 

{tabbedtable} Comparison Tab Content
In regular boards

Micro USB directly connected to the FT2232 Chip for both JTAG and USB-UART in Regular boards


image

USB104-A7

FT2232 Connected to the Hub rather than directly connecting to the USB

image

USB104-A7

JTAG connected to the USB Hub via the controller

 

image

USB104-A7

FT232 Connected to the USB Hub for DPTI

image

 

The above points explain why one can use this board rather than going for others.

 

Testing the GPIO with a custom Pmod:

I shall start by saying the quote: The expert at anything was once a beginner.” – Helen Hayes

People starting to learn hardware description languages might need the slide switches and the LEDs for sure.

As one would've realized by now that the board still lacks much user GPIO because it's all consumed by the DPTI and the Zmod, to address this issue, a custom Pmod is fabricated.

Let's take a look at the schematic for the fabrication.

image         image

Design made with NI Multisim:

From the schematics, it can be understood that using a 10k resistor would be used for pull-up and pull-down purposes.

As there is already a 200 Ohm resistor connected in series to the Pmod GPIO to prevent damage to the FPGA if one accidentally drives an input as an output,

only 100 Ohm resistor is used in series with the LEDs. All switches are active high. The circuit diagram is given below:

   imageimage

Started with the above components, some PCB mount slide switches, LEDs, and the Bent Male-Male Dual pin headers.

After soldering all the components and the connections:

                                                            Front - end                                                                                                                                   Back-end   imageimage

                                                                                        image

Here is the general constraints file for the above-fabricated Pmod:

## Pmod Header JA
#set_property -dict { PACKAGE_PIN F4    IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L13P_T2_MRCC_35 Sch=ja[1]
#set_property -dict { PACKAGE_PIN F3    IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L13N_T2_MRCC_35 Sch=ja[2]
#set_property -dict { PACKAGE_PIN E2    IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L14P_T2_SRCC_35 Sch=ja[3]
#set_property -dict { PACKAGE_PIN D2    IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L14N_T2_SRCC_35 Sch=ja[4]
#set_property -dict { PACKAGE_PIN H2    IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L15P_T2_DQS_35  Sch=ja[7]
#set_property -dict { PACKAGE_PIN G2    IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L15N_T2_DQS_35  Sch=ja[8]
#set_property -dict { PACKAGE_PIN C2    IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_L16P_T2_35      Sch=ja[9]
#set_property -dict { PACKAGE_PIN C1    IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L16N_T2_35      Sch=ja[10]


### Pmod Header JB
#set_property -dict { PACKAGE_PIN C4    IOSTANDARD LVCMOS33 } [get_ports { sw_b[0] }]; #IO_L7P_T1_AD6P_35     Sch=jb[1]
#set_property -dict { PACKAGE_PIN B2    IOSTANDARD LVCMOS33 } [get_ports { sw_b[1] }]; #IO_L10N_T1_AD15N_35   Sch=jb[2]
#set_property -dict { PACKAGE_PIN B3    IOSTANDARD LVCMOS33 } [get_ports { sw_b[2] }]; #IO_L10P_T1_AD15P_35   Sch=jb[3]
#set_property -dict { PACKAGE_PIN B4    IOSTANDARD LVCMOS33 } [get_ports { sw_b[3] }]; #IO_L7N_T1_AD6N_35     Sch=jb[4]
#set_property -dict { PACKAGE_PIN B1    IOSTANDARD LVCMOS33 } [get_ports { sw_b[4] }]; #IO_L9P_T1_DQS_AD7P_35 Sch=jb[7]
#set_property -dict { PACKAGE_PIN A1    IOSTANDARD LVCMOS33 } [get_ports { sw_b[5] }]; #IO_L9N_T1_DQS_AD7N_35 Sch=jb[8]
#set_property -dict { PACKAGE_PIN A3    IOSTANDARD LVCMOS33 } [get_ports { sw_b[6] }]; #IO_L8N_T1_AD14N_35    Sch=jb[9]
#set_property -dict { PACKAGE_PIN A4    IOSTANDARD LVCMOS33 } [get_ports { sw_b[7] }]; #IO_L8P_T1_AD14P_35    Sch=jb[10]


### Pmod Header JC
#set_property -dict { PACKAGE_PIN C5    IOSTANDARD LVCMOS33 } [get_ports { sw_a[0] }]; #IO_L1N_T0_AD4N_35     Sch=jc[1]
#set_property -dict { PACKAGE_PIN C6    IOSTANDARD LVCMOS33 } [get_ports { sw_a[1] }]; #IO_L1P_T0_AD4P_35     Sch=jc[2]
#set_property -dict { PACKAGE_PIN B6    IOSTANDARD LVCMOS33 } [get_ports { sw_a[2] }]; #IO_L2N_T0_AD12N_35    Sch=jc[3]
#set_property -dict { PACKAGE_PIN C7    IOSTANDARD LVCMOS33 } [get_ports { sw_a[3] }]; #IO_L4N_T0_35          Sch=jc[4]
#set_property -dict { PACKAGE_PIN A5    IOSTANDARD LVCMOS33 } [get_ports { sw_a[4] }]; #IO_L3N_T0_DQS_AD5N_35 Sch=jc[7]
#set_property -dict { PACKAGE_PIN A6    IOSTANDARD LVCMOS33 } [get_ports { sw_a[5] }]; #IO_L3P_T0_DQS_AD5P_35 Sch=jc[8]
#set_property -dict { PACKAGE_PIN B7    IOSTANDARD LVCMOS33 } [get_ports { sw_a[6] }]; #IO_L2P_T0_AD12P_35    Sch=jc[9]
#set_property -dict { PACKAGE_PIN D8    IOSTANDARD LVCMOS33 } [get_ports { sw_a[7] }]; #IO_L4P_T0_35          Sch=jc[10]

 

Running an example design (4-bit ALU):

 

 

3. Overall review:

My first impressions on the board were like, as soon as I unboxed it, found the board to be more compact than I expected. Almost all the components on the board are SMDs. The board seems so delicate yet robust.

One thing that I have to mention here is that even though it has a lot of useful features, it's not as popular as the other boards because beginners and developers prefer boards such as the Arty / Basys for getting started.

However, if you want to start with an industry-grade board, then this is the right one to start with, also if your design needs the use of high-resolution Analog to Digital Converters then you might want this board as it is one among the best to feature the dedicated Zmod port. The only place where I faced some problems was with the MIG IP as I am on a lower version of Vivado (2017.3). Upgrading to a higher version would probably solve the problem.

 

One thing I want to mention here is, the board does not have many tutorials/guides as compared to the famous boards such as the Arty, even the Pmod IPs which I used have been built around the Arty boards such that Vivado keeps warning about the board packaging. But then I hope the road tests would have covered maximum usage of these boards such that anyone who wants to build their design and get it running won't have much trouble searching for tutorials online. I have also solved the problem for beginners not wanting to start with this board by providing a guide to building a custom Pmod, I call it the Pmod Starter Pack.

 

4. Acknowledgments:

First of all, I thank Randall for giving me this opportunity. Secondly, I thank Daniel sir for arranging the shipment (I received the board just in time!)

Last but not the least, I thank Digilent, a National Instruments Company for sponsoring this road test.

Anonymous