USB104 A7: Artix-7 FPGA Development Board - Review

Table of contents

RoadTest: USB104 A7: Artix-7 FPGA Development Board

Author: 14rhb

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?: This is quite a niche product - aimed at developers who want the power of the Artix A7 along with the industry standard PC/104. Therefore there are no direct contenders although I do suggest some similar boards in the main roadtest report that may suit hobbyists or those on a lower budget.

What were the biggest problems encountered?: Realising that this board had a useful capability enabling bulk data transfer from host PC to the FPGA registers but without any clear introduction readily available....hopefully my roadtest addresses this somewhat for other developers who find it (when published). It is quite common that such documentation and support improves after the product has been on market for a few months.

Detailed Review:

 

This Roadtest review covers the Digilent USB104 A7 development board: a board by Digilent that uses the Xilinx Artix A7 Field Programmable Gate Array (FPGA) device in a PC/104 format board. This USB104 A7 board is manufactured by Digilent Inc, which is part of National Instruments. Digilent have designed and assembled this development board using a range of ICs from other manufacturers, the key IC being the Xilinx Artix 7 FPGA and Spansion's DDR3 memory IC.

 

My overall conclusion on this product is "If you want to learn about the Artix-7 are developing an industrial application and need something better than PMOD, then this is a very good contender."

1.     My Background

I undertake electronics at home as my hobby and have been doing so since the early 80's having been given one of those 'electronic starter kits' as a gift and then discovering electro-music and the famous Maplin catalogue...check out the artwork here.

 

I have had several full time jobs in various fields including Z80, 6805, analog design, coding, RF, mechanical, heavy electrical, optics, CPLD, Microcontrollers and now with FPGA. And I've found every single area really interesting and often dabble in projects spanning many of those fields. Most of the learning in those fields is gained from my hobby. Therefore I applied for this roadtest for a couple of reasons:

  • I like the Digilent product range so I was interested to know what this new board could offer
  • to add another FPGA board into my learning which should help me understand why I do certain steps in the design process and how I switch between the different boards (for example could I use TCL scripts and cross-build the same design?)

 

My skill level at Vivado, Verilog and SDK are improving constantly but I'm far below average in those fields. Whilst this roadtest will stick to the aims below, at times I use the opportunity to explore the unrelated software further to help develop my skills.

 

2.     Aims of this Roadtest

The top aims I wish to achieve from roadtesting this Digilent board are:

  • board specifics - determine what peripherals are provided on the board and understand/convey what each of those are
  • FPGA development - detailing the software choices for various aspects of FPGA design
  • gain knowledge of the Artix-7 FPGA family and gauge where this board's IC sits in that range
  • improve my understanding of Vivado/SDK through examples and application and to share that insight
  • gain knowledge of wider aspects of FPGA and DSP

 

I know as this roadtest writeup progresses I'll likely deviate off my real aim of testing this specific board and waffle about other aspects of FPGA and the development process, please excuse me when that happens. I'll try and pull my thought back quickly to telling you as readers what this board can and cannot offer rather than take you through a "Vivado Project build". That said, I will include screen shots as I often stumble across articles like this myself whilst trying to overcome some development issue; and perhaps this roadtest could also provide someone with the answers they need.

 

3.     Xilinx Artix 7 and other Families

Even concentrating on one manufacturer such as Xilinx I get confused over what the different FPGA devices can offer. Therefore I have pulled together some succinct points to hopefully make this a bit clearer for anyone like me.

 

The FPGA used on the USB104A7 is the Xilinx Artix-7 and it sits in a range of other FPGA families, the 7 appears to denote the fabric technology of 28nm. I pull these devices together very loosely in a diagram that also includes the Ultrascale and Ultrascale+ which are 20nm and 16nm technologies respectively. Apart from other FPGA by Xilinx. perhaps worth mentioning here is the Spartan-6 which was a 45nm technology device. The diagram below is my basic understanding of these families - I initially started to populate with key parameters but they overlapped so much in the end I decided that it was just confusing, instead opting for a simpler approach.

[Basic comparison of Xilinx 7-series families]

 

Delving further into just the Artix-7 range I have snipped a table from the online Xilinx data. It can be seen that the USB104-A7 uses the XC7A100T device (annotated with a red star below) which is at the higher end of the Artix-7 range in terms of resources available. When I compare this to the Spartan-7 I don't see a huge difference between this XC7A100T and the top Spartan-7 device....until I spot the Artix-7 has something called GTP transceivers. I'll investigate those as the roadtest progresses.

[Xilinx Artix-7 range of devices]

[device markings on Digilent USB104-A7 FPGA device]

 

4.     First Thoughts

Initial thoughts on unpacking and checking for damage, of which there was none, was that the Digilent box design was very appealing - a strange comment perhaps but arriving before Christmas made it a nice 'present' and, as a technical geek, I would have loved opening this as a gift from anyone....so thank you Digilent and Randall. For that reason I have decided to include a photo of that package along with my other prized Digilent development boards. For anyone looking to try out the PIC32 bit MCU I really recommend the BASYS MX3 and you can read my review of it Microchip PIC Overview: for BASYS MX3 Roadtest

[My collection of Digilent development boards....I think I need something red to complement the set ! ]

 

The Digilent USB104-A7 board is a pleasingly small and square format - indeed it's PC/104 compliant dimensions of 96mm x 90mm. On initial inspection the board has very few peripherals when compared to other FPGA development boards and I'll delve into the functionality next. I must admit I'd forgotten the basic spec and for a while I wondered where the usb-UART connector was. I thought the silver connector on the left hand side was an ethernet socket and then I realised I had read it was USB 2.0 type-B. This is nice to see as the type-B are more robust and definitely better mechanically than some SMT USB-B connectors. I remember too well the sinking feeling when I managed to pull the USB connector off my NXP I.MX RT1050 EV KIT and Display - Review roadtest board some years back (chapter 5 of that link contains the sorry tale).

 

I also could not hold back and soon connected the USB to my PC, which powered up the Digilent USB104-A7 into the pre-loaded demonstration code. Whilst the demonstration wasn't overly impressive (the four board LEDs cycled through continuously) it did show that the unit was functional. Also having a demo like this preloaded is a good way of being able to recognise when the board has reset during development or when the developers code is perhaps running. There were many times during this roadtest that I ran my debug code in SDK to no effect and then realised that the four LEDs were cycling, indicating I had not programmed the device (often because I had disconnected it from the PC).

 

5.     The Board Layout and Key Parts

5.1     Exploring the Board

I've highlighted the main peripherals and physical features of this board in the diagram below:

[The Digilent USB104-A7 basic components]

 

  • There is a barrel jack to supply +5v DC to the board. Small designs could be managed using just the USB connector power but as more of the fabric is utilised and PMOD/ZMOD devices attached then this would be required. The board has clear markings to ensure voltage and polarity are maintained - although I do use the same connector but at +12v for my oscilloscope!
  • There is a USB 2.0 Type B connector for attaching the board to a PC for programming, debugging and data transfer. The choice of USB type-B is interesting as it is the more robust IMO and therefore a good choice.
  • There is a small high speed connector in the middle area of the board known as ZMOD (more detail about this below) along with pillars for attaching ZMOD daughterboards
  • Centre of the PCB is the FPGA device itself and above that a 512MByte DDR3 memory unit

 

The big points about this Digilent board compared to others in the Artix-7 range are the SYZYGY connector and the PC/104 form factor of the PCB. The PC/104 is quite an old standard for electronics and PC based PCBs that allows them to be stacked in an industrial design, saving space. There were several standards to PC/104 and boards always seemed to attract a higher price due to this less common and esoteric format. Interconnects between boards were located in mandated positions to allow the stacking upwards and downwards between boards - this is not dissimilar to Arduino and Raspberry Pi shields. Whilst this Digilent USB104-A7 has the physical board size of PC/104 there are none of the expected interconnectors to allow it to plug into other commercial PC/104 boards - the ZYSYGY connector is non-standard as are the PMODs. Maybe this was a oversight on the designers part as being able to add the FPGA power of a Artix-7 to an existing industrial system could have been very useful indeed.

 

6.     Board Connectivity

Whilst at first it may appear this board lacks the SFP+, FMC or ethernet modules on other slightly higher priced designs (mainly Xilinx) the USB104A7 has a few hidden features. One of the interesting things about this board is that it includes multi-function capability in the USB connection. Like other FPGA development boards it includes the ability to program JTAG information into the device as well as including a USB-UART link enabling debugging and information flow. However this board includes several less common additional interfaces which are:

 

6.1     USB Hub

The board only has the single USB 2.0 type-B connector which seems limiting. I believe this USB hub allows multiple peripherals within the USB104-A7 to communicate on separate buses to a host device. What I thought would happen was that several COM ports might open up depending on the boards configuration - where one could transmit UART data to PuTTY on the host machine, another streams data to a bespoke software application on that host machine and another via a physical breakout allows a mouse or keyboard to be used on the USB104-A7. I was not able to prove or disprove that theory but it would be very limiting if that did not work in such a way. Personally another dedicated UART-USB would have allowed me to understand this better. The USB also even combines the JTAG programming function !

 

6.2     DPTI

I hadn't heard of the DPTI interface before and my initial foraging in the Digilent website for this board showed a lack of information, including some missing links. I believe this USB104-A7 board is new out December 2020 and therefore such omission is understandable and hopefully will be plugged in the coming months  - indeed roadtests like this will hopefully help inform Digilent of such issues. The main Digilent webpage for the USB104-A7 has some good links, including a DSPI demo detailed further down in my roadtest, but I couldn't initially see anything relating to the DPTI interface. The internet was luckily helpful as ever and I soon found reference to a DPTI IP block available in the Digilent Github library as well as two useful reference documents (hidden in the Adept 2 SDK v2.4.2 download files) for the Microblaze embedded code and the external PC/API. Once I had a read I thought a simplified diagram might help:

[Overview of DPTI and the USB port]

 

I was soon able to add the custom IP block to my DPTI test project but was lost as to how to use it. I did manage to find a project for the Digilent Nexys Video board that also used the AXI-DPTI IP block, although it didn't at first reveal exact what the block did. I tried to build that as a standalone project using the TCL script but it failed as I was using Vivado 2018.3 and many of the blocks were based on 2015 IP cores. I'm sure there was a way to change all that quickly but I'm no expert and therefore tried a different approach. Dropping down from 2018.3 to 2015 seemed counter-intuitive as my aim was to go upwards towards testing out Vitis. I could see several of my DPTI IP block's connections were flagged as missing during the development build. Some like resets and clocks I was able to manually route with success but a few still needed that connection and I was unsure where they went. Looking back at the Nexys Video project I was able to see they were configured in the same way as the constraints file (XDC) lists pins and ports. I looked at my constraints file and saw all the pins were already listed there and just needed commenting in...Doh, of course they would be there !

[My initial DPTI example]

 

Under the newly created BSP of my project there was a AXI-DPTI folder with source, header and a help document. For a 'novice' I only found the document to be slightly helpful as I was still unsure how the DPTI IP block interfaced to the USB connector: if I dragged the USB-UART from the board tab onto my design it soon got connected to a new AXI UART-lite. I actually kept the UART connected in case it was useful later. Knowing that some of these hardwired functions in the XDC sometimes don't need any further detailing in the block diagram I pressed on. There are only two functions available from the AXI_DPTI library:

  • DPTI_SimpleTransfer and
  • AXI_DPTI_Reg_SelfTest

 

I made a very simple SDK C example to run on my Microblaze. The code used was and the XPAR_AXI_DPTI address were to be found in the xparameters.h file

// RH's DPTI Test
#include "xil_printf.h"
#include "AXI_DPTI.h"

int main()
{
    init_platform();

    print("Hello World - DPTI Test 2\n\r");

    //XStatus DPTI_SimpleTransfer (u32 BaseAddress, u8 Direction, u32 TransferLength);
    //XPAR_AXI_DPTI_0_AXI4_LITE_BASEADDR

    int XStatus = DPTI_SimpleTransfer (XPAR_AXI_DPTI_0_AXI4_LITE_BASEADDR, 1, 12);
    print("Done\n\r");


    cleanup_platform();
    return 0;
}

 

The code ran without error. Then I turned my attention to the Adept 2 SDK that is a C/C++ library to interface the PC to this DPTI stream. I cut and pasted the C++ code into a Netbeans project and rang that on my PC....the results were very inconclusive having to wait until the reset was released to grab my bytes and blistering transfer rates of 1-2 bytes per second being achieved !

Eventually I left this project and moved on with other areas of my roadtest. When I returned to have another look I couldn't even compile up the bitstream again as I'd changed something!

 

Not wanting to give up I browsed around again and looked at the ZMOD examples on Digilent's website, whilst I did not have the ZMOD devices I had managed to upgrade to Vivado 2019.1 and this project used DPTI and that very package. I was therefore able to download and build the Vivado project to examine clearly how the DPTI IP block was configured. Once happy it built properly I deleted the ZMOD IP and a few other parts whilst adding constants etc to finish the design off. This compiled and I was able to export it to SDK:

[My modified DPTI Vivado example]

 

I was able to create a simple C based application in SDK that aimed to send a hundred floating point vales across the DPTI interface. It seemed to work whilst waiting for a non-existent PC application to grab that, therefore timing out. The bursts were every five seconds and I could see the activity LED by the UART/USB connector flashing as the code repeated that cycle.....great stuff.

 

What wasn't so good was that the Digilent PC application appeared to be targeted at Visual Studio and a Windows based PC. My Vivado development environment was on a Linux box. My attempts to import the source and headers and create my own simple app using Netbeans didn't go well. I had another thought....burn my design and code into the USB104-A7 flash and then use my Windows setup. In the process I found this very useful page of links on the Digilent website. The one I tried to follow on setting up the Quad SPI flash was also in that list. Whilst most of the stages made sense the setup failed after hours of working through with:

SREC SPI Bootloader
Loading SREC image from flash @ address:003d0900
ERROR in SREC line: 00000001SREC line is corrupted

 

Whilst I could not get this to work on a Linux machine I did manage to learn how to wire up the DPTI IP block and was fairly confident it transmitted data bursts. Hopefully the rest can be accomplished after this roadtest is submitted and I can then wrap that as a separate blog.

 

6.3     DSPI

An alternative to using the DPTI IP block is to opt for DSPI transfer via the AXI-Quad SPI block. A demo is provided by Digilent at https://reference.digilentinc.com/reference/programmable-logic/usb104a7/dspi which should be useful. After the DPTI 'saga' I soon spotted the requirement for Vitis and, not having that installed, decided to sidestep that demo. I did look into the code for the PC app to complement this demo to see how it handled the SPI information from the USB port. The code appears to be for producing a DLL and hence targets Windows OS.

 

6.4     Other board connectivity

As well as the DPTI and DSPI, this board also includes the more commonly found PMOD interfaces, in fact there are a generous three of these connectors provided. PMOD can utilise a variety of interfaces but is often configured as SPI or I2C. This board also includes a newer connection standard called SYZYGY which is also referred to as ZMOD by Digilent.

 

PMOD Boards

There are  great number of PMOD boards available from Digilent. I already owned three but took this roadtest as the ideal opportunity to add a couple of extras to my collection, and purchased the SD Card PMOD and RTCC PMOD. PMOD are a low-cost way of adding peripherals to this Digilent board and indeed to many other development platforms. The full range of PMOD boards available through Digilent can be found here . Additionally as the PMOD ports on the boards are serial interfaces to I2C or SPI the developer could quite easily make their own PMOD compliant device by mounting a specific IC or sensor and adding the 6/12 way pin header.

[My collection of PMOD boards: clockwise from top; compass unit, OLED display, RTCC, micro SD card and navigation module]

 

Once the Vivado IP library is added to the Vivado Project connecting the PMOD devices to a specific PMOD port is very straight forward:

{gallery} PMOD

[Screenshots showing simplicity of using Digilent IP]

 

ZMOD Boards

This is a fairly new interface standard that is officially known as SYZYGY but the term ZMOD has been used by Digilent. The throughput performance of ZMOD is better than the PMOD but less than another common standard used on Xilinx boards such as the FPGA Mezzanine Card (FMC) or a dedicated ethernet port or Small Form Pluggable (SPF+) connector. For comparison the typical clock rates on the pins of these standards are:

StandardMHz/Pin (min)MHz/Pin (max)
PMOD150
SYZYGY50500
FMC (gigabit pins)5005000

 

The good news is that SYZYGY is an open standard and developers are strongly encouraged to use it. However it doesn't seem to have been as successful yet as PMOD; there are only two boards supporting ZMOD - an ADC and DAC. Both are unfortunately out of my budget for this month but I was very taken with an article by Fred27 on building his own SYZYGY to HDMI board - Creating a SYZYGY board - assembling the board and testing. I found his articles very informative and decided to purchase my own ZMOD connectors to experiment with that capability in the future. Things then didn't quite go to plan as the ADC I decided to use is unavailable currently but is backordered. Looks like that will be a future roadtest catchup for me. Below is a photo of my SYZYGY connector along with a FMC (low pin count) connector and the PMOD for comparison.

[Diagram showing size difference between PMOD, ZMOD and FMC (LPC) ]

 

ZMOD provides the following on each connector and the differential pairs are very common on high speed Analog to Digital Converters (ADC):

  • Dedicated differential clocks for input and output

  • 8 differential I/Os

  • 16 single-ended I/Os

 

7.     Memory Options Available

7.1     "Memory is RAM" - IT Crowd

The Artix-7 used on this board can provide 4,860kB of Block RAM according to the Xilinx datasheet, although Digilent list it as 607.5kB so something for me to investigate further. As a fairly novice designer this is often where I make my program sit; Vivado and SDK build without errors which makes me happy. However in the course of this roadtest as I experimented and pulled in more libraries of C code to service the PMOD devices I had included I ended up with a dreaded message stating I was over the limit. It took me a while to learn and understand how to increase the program memory available (called Instruction RAM) - it was fairly easy when I realised the tab marked Address Editor was staring me in the face. This was a messy approach and if the rest of my design relied on those BRAM units I would have been stuck....the USB104-A7 has some other memory available to suit both the program (instruction) storage and variable (data) storage as required.

 

7.2     Quad SPI Flash

This roadtest has actually made me understand what Quad SPI flash is; where a standard SPI is a single dataline the data throughput has been increased by going to a quad line system...although they bizarrely still call it serial when it is more akin to parallel or at least four serials working together. Anyway, its fast and this USB104-A7 provides 16MB (128 Mbit) of storage in the form of the Spansion S25FL128 device, mounted on the rear of the USB104-A7 board.

 

The main purpose of this Quad SPI flash is to store the bitstream required by the FPGA on bootup. That typically uses 30.6Mbits and leaves about 76% of this Spansion device free. Therefore this extra capacity can be used to store the programs required by the Microblaze core(s) implemented in the user's design. This isn't something I've experimented with yet and it isn't really concentrating on the board capability of this roadtest. Of course the Quad SPI could hold other data required by the FPGA implementation - files, bitmaps or data required for that novel design.

 

7.3     DDR3

The USB104-A7 also includes an onboard 512MB DDR3 RAM device. Such memory can be used to store data that that FPGA has read, processed or otherwise used, received from an external device etc. It would be particularly useful for storing video images or matrixes during processing or for a OS to reside on. This is a reasonable amount of storage to create some useful designs although many of the Zynq based boards come with 1GB DDR or more. Perhaps for the targeted industrial users of the USB104-A7 Digilent could have increased this size accordingly.

 

8.     Development Tools

I had expected to get a Vivado license document or similar in the Digilent box but there wasn't. As I already had Vivado 2018.3 installed on my PC my aim was to develop the Digilent USB104-A7 using that software. I knew this was out-dated but I knew it currently was setup to work. Therefore I am unable to state how difficult it is to install a fresh version although I do believe Vivado at a basic level is free, the licenses that accompany higher specification products like the ZC702 add extra IP blocks and design tools. The free version is called Vivado WebPack.

 

As my roadtest progressed a fellow roadtester asked a few questions openly to the community but initially I could not assist as my version of Vivado was too old to import the IP blocks instantiated in those designs. What happens is that a design in Vivado is a list of commands known as TCL script and it pulls together the IP blocks and nets to create the design. However the IP blocks get upgraded and new functionality is added, perhaps new pins, and then this script can no longer complete the design. It would be like having spent the last 40 years building with a 555 timer to find the new 555 device has a 4-bit bus input...where would you connect that to? This was a really good situation as it was the perfect excuse to try and install other versions, and in doing so I was able to better understand the setup of each such as adding in the board files and IP repositories. The downside I wasn't considering was that each version would use vast amounts of my HDD ! I have therefore managed to install just another two versions of Vivado:

  • Vivado 2019.1
  • Vivado 2020.2

 

My future aim is to one of those and then to install and try out Vitis. If anyone has suggestions in this area I would be most grateful as I did wonder if a virtual machine would be useful, allowing several Vivado versions to be stored offline on another HDD?

 

9.     Project Time

This section list some of the areas I have explored on the Digilent USB104-A7, I'm still learning and therefore some areas were inconclusive for me as I was unable to finish the designs and get them to build but most of the bits I looked at did give positive results. Such failure is down to myself and my lack of understanding still rather than the board specification or Vivado/SDK issues.

9.1     An Enclosure

There seemed to be only one enclosure I wanted to keep this Digilent board safe from accidental knock with and I set about designing one as shown below. I've included my OpenSCAD code should anyone wish to replicate or improve on that design.

[Concept enclosure for USB104-A7]

[Printed enclosure for Digilent USB104-A7]

 

// USB104-A7 Enclosure for 3D Printed Model Purposes 
// Element14 Community
// Roadtest of Digilent USB104 A7 FPGA Board
// Version 1

// all Dimensions are in mm and taken from various online material, which might be incorrect

//*************************************************************
// Variables
//*************************************************************
$fn=50;

rail_upstand=8;

//ends...the panels holding the two rail/sides together
end_thickness=2;
end_panel_milling=30;
bar=3;
release_diam=6; // for the release switches etc

//cross members - upper is embossed, lower is thinner and not embossed
cross_member_thickness=12;
cross_member_thickness2=4;
cross_member_inlet=rail_upstand+end_thickness; //how far into the frames for cross members

rail_width = 8.5;
cubesat_width = 100;
rail_chamfer_rad =1;

//Digilent USB104A7 fixings
holeDigIn=5;
holeDigDia=3; //mm diameter
holeDigIn2=20; // holes for baseplate and end frames

//Baseplate required to mount PC104 board wilst also fixing separately to the end frames
baseplate_thickness=3;
baseplateHole=(cubesat_width/2)*1.25;


rail_len = cubesat_width-(end_thickness*2)+(cross_member_inlet*2);

//Digilent USB104_A7 FPGA Development Board
boardTolerance=0.1;
USB104_Width1=90.17+boardTolerance;
USB104_Width2=95.89+boardTolerance;
USB104_thickness=4; //nominal as not actually printed, just for checking fit

// Milling to allow boards to slot into the side frames
sideMilling1 = rail_width-((cubesat_width-USB104_Width1)/2);
sideMilling2 = rail_width-((cubesat_width-USB104_Width2)/2); //Z

crossmember_frame_thickness=(cubesat_width-USB104_Width2); //used for the embossed cross members

//fixings are M3
drill_r=3.5/2;
head_r=6/2;

endPanelPillarHole=drill_r;
endPanelBossRad=drill_r+2;

oversize=200; //helps ensure bits are cut out cleanly
smallOversize=1.005;

//pc-104 board dimensions, from Digilent board
x=90;
Y=96;

base_lip = 7;

assembly_hole_dia = 3.2;

// securing tags...for v1 only where I didn't design for the sides to be held in
tag_width=6;
tag_upstand=2;
tag_thick=2;
tag_offset=1; //position from the centerline

//*************************************************************
// To show full project add all together & how they fit together.
// for printing duplicates of upper/lower and left/right will suffice
// these bits can be selected individually using the ! without need for the positioning adjustment
//*************************************************************
// Component A: First Sideframe
SideFrame("Digilent USB104 A7");

// Component B: Second Sideframe
translate([-100+rail_width,0,(100-rail_width)])
  rotate([0,180,0])
  SideFrame("Element14");
   
// Component C: Bottom End Frame...RED
color("red") 
translate([0,-(rail_len/2)+rail_upstand,0])
  EndFrame();

// Component D: Top End Frame...PURPLE  
color("purple") 

translate([0,(rail_len/2)-rail_upstand-end_thickness,cubesat_width-rail_width])
  rotate([180,0,0]) EndFrame();
   
// Component E: the Digilent USB104-A7 board.....GREEN
// for fitment purposes only - not required for printing
Shim1 = (cubesat_width-USB104_Width1)/2;
Shim2 = (cubesat_width-USB104_Width2)/2;
color("lime") 
translate([Shim1,0,Shim2])
  Digilent_USB104A7();


// Component F: a baseplate to mount the Digilent USB104A7 and to fix to the end frames.....PINK
color("pink")
translate([Shim1,-40,Shim2])
  Baseplate(cross_member_thickness2);


// Component G: a baseplate to mount the Digilent USB104A7 and to fix to the end frames.....ORANGE
color("orange")
translate([Shim1,0,Shim2])
  Baseplate(cross_member_thickness);
   
   

//side frame x2 required
module SideFrame(textInput){
  difference(){
  union(){
  cube ([rail_width, rail_len,rail_width], center=true);
   
  //test length
  //translate([10,0,0]) cube ([5, 100,5], center=true);
   
  translate([-cubesat_width+rail_width,0,0]) cube ([rail_width, rail_len,rail_width], center=true);

  //cross members
  //top crossmember
  translate([-cubesat_width/2,(rail_len/2)-(cross_member_thickness/2)-cross_member_inlet,-0.5*(rail_width-crossmember_frame_thickness)]) 
  difference(){
  cube ([cubesat_width-rail_width, ,cross_member_thickness, crossmember_frame_thickness], center=true);
  translate([0,-2,-crossmember_frame_thickness+1]) linear_extrude(1.5)
  rotate([0,180,0]) text(textInput,size =6,halign="center"); 
  }
  //bottom cross member - wider for text?
  //translate([-cubesat_width/2,-(rail_len/2)+(cross_member_thickness2)+cross_member_inlet+end_thickness,-0.5*(rail_width-crossmember_frame_thickness)])  
  translate([-cubesat_width/2,-(rail_len/2)+rail_upstand+end_thickness+(cross_member_thickness2/2),-0.5*(rail_width-crossmember_frame_thickness)])  
  difference(){
  cube ([cubesat_width-rail_width,cross_member_thickness2, crossmember_frame_thickness], center=true); 

  }
  }//union

  //bits to remove
  adjust1=rail_width/2-sideMilling1/2;
  adjust2=rail_width/2-sideMilling2/2;
  adjust3=cross_member_thickness2/2-cross_member_thickness/2;
  milling_length=rail_len-(2*cross_member_inlet)-cross_member_thickness-cross_member_thickness2;
   
  translate([-adjust1,adjust3,adjust2])  
  cube ([sideMilling1*smallOversize, milling_length,sideMilling2*smallOversize], center=true);
   
  translate([-cubesat_width+rail_width,0,0])
  translate([adjust1,adjust3,adjust2])  
  cube ([sideMilling1*smallOversize, milling_length,sideMilling2*smallOversize], center=true);
   
  //remove for release switches
  catchlength=rail_upstand+end_thickness+2;
  translate([0,rail_len/2-catchlength/2+0.1,0])
  rotate([90,0,0])
  cylinder(catchlength, d=release_diam/2, center=true); 
   
  for (a =[0:0.1:4]) translate([0,cubesat_width/2-rail_upstand-end_thickness+a,rail_width/4])
  rotate([0,0,0])
  cylinder(rail_width, d=release_diam/2+1, center=true); 

  //remove for release springs
  translate([-cubesat_width+rail_width,rail_len/2-catchlength/2+0.1,0])
  rotate([90,0,0])
  cylinder(catchlength+1, d=release_diam/2, center=true); 
   
  for (a =[0:0.1:4]) translate([-cubesat_width+rail_width,cubesat_width/2-rail_upstand-end_thickness+a,rail_width/4])
  rotate([0,0,0])
  cylinder(rail_width, d=release_diam/2+1, center=true); 
   
   
  }//difference
}  
  

//end frames x2 required
module EndFrame(){
  translate([-cubesat_width+rail_width/2,0,-rail_width/2]) 
  difference(){
  union(){
  cube([cubesat_width,end_thickness,cubesat_width]);
   
  //side reinforcing bars
  translate([0,cross_member_thickness2/2,rail_width]) cube([crossmember_frame_thickness,cross_member_thickness2,cubesat_width-(2*rail_width)]);
  translate([cubesat_width-crossmember_frame_thickness,cross_member_thickness2/2,rail_width]) cube([crossmember_frame_thickness,cross_member_thickness2,cubesat_width-(2*rail_width)]);
  }
  //corners removed
  translate([cubesat_width-rail_width/2,0,cubesat_width-rail_width/2])
  cube ([rail_width*smallOversize,end_thickness*oversize, rail_width*smallOversize], center=true); 
   
  translate([cubesat_width-rail_width/2,0,rail_width/2])
  cube ([rail_width*smallOversize,end_thickness*oversize, rail_width*smallOversize], center=true); 
   
  translate([rail_width/2,0,cubesat_width-rail_width/2])
  cube ([rail_width*smallOversize,end_thickness*oversize, rail_width*smallOversize], center=true); 
   
  translate([rail_width/2,0,rail_width/2])
  cube ([rail_width*smallOversize,end_thickness*oversize, rail_width*smallOversize], center=true); 
   
  //middle section removed
  translate([cubesat_width/2+end_panel_milling/2+bar,0,cubesat_width/2+end_panel_milling/2+bar])
  cube ([end_panel_milling,end_thickness*oversize, end_panel_milling], center=true); 
   
  translate([cubesat_width/2-end_panel_milling/2-bar,0,cubesat_width/2+end_panel_milling/2+bar])
  cube ([end_panel_milling,end_thickness*oversize, end_panel_milling], center=true); 
   
  translate([cubesat_width/2-end_panel_milling/2-bar,0,cubesat_width/2-end_panel_milling/2-bar])
  cube ([end_panel_milling,end_thickness*oversize, end_panel_milling], center=true); 

  translate([cubesat_width/2+end_panel_milling/2+bar,0,cubesat_width/2-end_panel_milling/2-bar])
  cube ([end_panel_milling,end_thickness*oversize, end_panel_milling], center=true);
   
  //translate([(cubesat_width-USB104_Width1)/2,0,0])
  BaseplateFixings();
  }
  }

   
  
module Digilent_USB104A7(){
  translate([-cubesat_width+rail_width/2,0,-rail_width/2]) 
  difference(){
  cube([USB104_Width1,USB104_thickness,USB104_Width2]);
   
  USB104fixings();  
   

} 
}

module Baseplate(pillar_height){
  x1=(cubesat_width-USB104_Width1)/2;
  z1=(cubesat_width-USB104_Width2)/2;
  echo ("Baseplate dimensions...",pillar_height);
   
  thick = 4; //a one-shot adjustment...that I couldn't work out as a formula
   
  translate([-cubesat_width+rail_width/2,20,-rail_width/2]) 
  difference(){
  union(){
  cube([USB104_Width1,baseplate_thickness,USB104_Width2]); // the baseplate
  echo(USB104_Width1,baseplate_thickness,USB104_Width2);
  translate([-x1,0,-z1])AddBaseplatePillars(pillar_height); //fixing bosses
   
  //side infill and clip...an after though to remove and rework in v2
  translate([-x1+rail_width,0,-(rail_width-sideMilling2)]) cube([cubesat_width-rail_width*2,baseplate_thickness,sideMilling2]); 
   
  translate([-x1+rail_width,0,cubesat_width-thick-0.01]) cube([cubesat_width-rail_width*2,baseplate_thickness,(rail_width-sideMilling2)]);  

  //add clips....as a fix to my design v1 only
// tag_width=6;
// tag_upstand=2;
// tag_thick=2;
// tag_offset=30; 
  translate([-x1+rail_width+tag_offset,0,cubesat_width-thick+2]) 
  cube([tag_width,tag_upstand+baseplate_thickness,tag_thick]);
   
  translate([cubesat_width-(rail_width*2)-tag_width/2+0.5-tag_offset,0,cubesat_width-thick+2]) 
  cube([tag_width,tag_upstand+baseplate_thickness,tag_thick]);  

  translate([-x1+rail_width+tag_offset,0,-crossmember_frame_thickness]) 
  cube([tag_width,tag_upstand+baseplate_thickness,tag_thick]);
   
  translate([cubesat_width-(rail_width*2)-tag_width/2+0.5-tag_offset,0,-crossmember_frame_thickness]) 
  cube([tag_width,tag_upstand+baseplate_thickness,tag_thick]);  
   
  }
   
  USB104fixings(); 
  translate([-x1,0,-z1]) 
  BaseplateFixings();
  translate([USB104_Width1/2-baseplateHole/2,-baseplate_thickness/2,USB104_Width2/2-baseplateHole/2]) 
  cube([baseplateHole,baseplate_thickness*10,baseplateHole]);
  } 
}



module USB104fixings(){
  translate([holeDigIn,0,holeDigIn])
  rotate([90,0,0])
  cylinder(USB104_thickness*4, holeDigDia/2, center=true);
   
  translate([holeDigIn,0,USB104_Width2-holeDigIn])
  rotate([90,0,0])
  cylinder(USB104_thickness*4, holeDigDia/2, center=true);
   
  translate([USB104_Width1-holeDigIn,0,USB104_Width2-holeDigIn])
  rotate([90,0,0])
  cylinder(USB104_thickness*4, holeDigDia/2, center=true);
   
  translate([USB104_Width1-holeDigIn,0,holeDigIn])
  rotate([90,0,0])
  cylinder(USB104_thickness*4, holeDigDia/2, center=true);
  } 


module BaseplateFixings(){
  railAdjustment = rail_width*1.1;
  drillingMod=8;

  translate([holeDigIn2,0,railAdjustment])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);
  translate([cubesat_width-holeDigIn2,0,railAdjustment])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);  
   
  translate([holeDigIn2,0,cubesat_width-railAdjustment])
  rotate([90,0,0])  
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);
  translate([cubesat_width-holeDigIn2,0,cubesat_width-railAdjustment])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);  



  translate([railAdjustment,0,holeDigIn2])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);
  translate([railAdjustment,0,cubesat_width-holeDigIn2])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);  
   
  translate([cubesat_width-railAdjustment,0,holeDigIn2])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);
  translate([cubesat_width-railAdjustment,0,cubesat_width-holeDigIn2])
  rotate([90,0,0])
  cylinder(USB104_thickness*drillingMod, holeDigDia/2, center=true);  

  } 
   
module AddBaseplatePillars(pillarHeight){
  railAdjustment = rail_width*1.1;
  yOffset=pillarHeight/2+baseplate_thickness;

  translate([holeDigIn2,yOffset,railAdjustment])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);
   
  translate([cubesat_width-holeDigIn2,yOffset,railAdjustment])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);  
   
  translate([holeDigIn2,yOffset,cubesat_width-railAdjustment])
  rotate([90,0,0])  
  cylinder(pillarHeight, r=endPanelBossRad, center=true);
   
  translate([cubesat_width-holeDigIn2,yOffset,cubesat_width-railAdjustment])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);  



  translate([railAdjustment,yOffset,holeDigIn2])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);
   
  translate([railAdjustment,yOffset,cubesat_width-holeDigIn2])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);  
   
  translate([cubesat_width-railAdjustment,yOffset,holeDigIn2])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);
   
  translate([cubesat_width-railAdjustment,yOffset,cubesat_width-holeDigIn2])
  rotate([90,0,0])
  cylinder(pillarHeight, r=endPanelBossRad, center=true);  

  }

 

Once printed with PLA I realised the engraving wasn't deep enough to take the paint for highlighting, it ran into the 'grain' of the 3D print and makes it look blurred. Anyway, with some torx headed machine screws I think it looks interesting enough and definitely provides the board protection. The last thing I need to do is remove the rubber feet from the Digilent USB104-A7 and use the provided metal standoffs to mount the board permanently.

 

9.2     XADC - a Artix-7 embedded Analogue to Digital Converter (ADC)

The Artix-7 (and several other 7-series devices) contains an ADC embedded within the FPGA fabric and for the purpose of gaining knowledge of parameters inside that device. The ADC is fed and controllable via the AXI bus and hence a simple Microblaze design can leverage against that IP block to keep a watchful eye on important internal values. The IP block for this is the xadc_wizard and within that the user can select what attribute they wish to monitor. There are several to choose from including the internal voltage rails but I chose the die temperature for my example. Getting going was simple with a basic Vivado design having no build issues, programming the FPGA and then setting about creating a simple C code in SDK.

 

The temperature was stored in a 16-bit register (I presume on the IP block as BRAM) and was accessible via AXI as an address offset to the XADC's base address. The value was quite meaningless initially so I set about finding what it equates to in degrees centigrade. The article on pg 23 of UG480 gave a formula for the conversion. Initially that too was a long way out until I masked off the lower 3 bytes and formatted my print statement correctly. The value still seems wrong at 150 degrees centigrade. There is mention of a 0.2/1.0 factor for Full Scale Deflection which would drop my measurements to a very respectable 30 degrees. Anyway the functionality is there and is very useful in my opinion, and although FPGA side rather than Digilent board it was worth exploring.

 

9.3     Real Time Operating System(s) and Linux

 

FreeRTOS_Xilinx: Most of my designs as I have learnt about Vivado or FPGA are RTL, IP based and/or use Microblaze or Zynq cores. On the latter two I invariably test out the function with plain C code however in SDK when you create a new application project there is the choice of 'standalone' that I have used until now as well as freertos10_Xilinx and Linux. I decided to look at the FreeRTOS and just create a very simple program; this was a continuation of the XADC example but I also activated the interrupts on the Microblaze, added an AXI Interrupt controller as well as an AXI Timer. Once I remembered to re-program the FPGA (I seem to forget that step) the code example built and ran with a welcome message to my PuTTY terminal. I didn't really want to dig too deep into this as a roadtest because it is more a test of Vivado, SDK and my programming skills - however the Artix-7 and support software can allow a free RTOS to be built. Here the code will be managed and jump to functions as interrupts occur, are serviced and cleared. As long the the developer builds their functions correctly all the timing issues on that code are managed by RTOS. An insight into the heap, stack, routine, task and timer functionality in FreeRTOS can be found in the project's BSP under Microblaze/libsrc/freertos10_xilinx

 

Linux: In the new application drop down there was also a choice for Linux...so I decided to try that out also. I managed to waste time here hunting for "picolinux" which I was sure I had seen but only turned up links for Petalinux...what I had managed to do was confuse myself over Linux and the new(ish) 8-bit RISC implemented softcore called Picoblaze. Once that was sorted out onwards....I downloaded the Petalinux software from Xilinx which I believe is used to create the Linux packages based on the design architecture; Petalinux supports 32-bit Microblaze, 32-bit Cortex A9 (on Zynq boards) and a 32/64-bit on the Ultrascale devices.

 

After much fighting my OS and reading various snippets I had Petalinux installed but didn't manage to get much further. Again pulling myself back on track getting it going was not key to talking about this USB104-A7 board but more aligned to the workings of Xilinx support software. For me I appreciate what it is and will work on getting it going at a later date. I'm not too concerned at this stage by not getting Linux working; I would rather concentrate on experimenting with the FPGA fabric directly than having that experience 'masked' by the abstraction of a OS/libraries etc.

 

9.4     DSP functionality of Artix-7...a rocky road of ups and downs!

Something I'd noted but often ignore was the DSP slices; this Artix-7 has 240 of them so I thought I'd better have a read on what they are and how I can use them. A learned a little about DSP at college; computers were slow and it was self-contained exercise without a real-world application. At the time this was software that flowed and looped around to accumulate an answer as the PC clock ticked on; it would take a large number of clock cycles to return an answer. However DSP in an FPGA and especially with dedicated DSP Slices achieves a huge throughput as the additions and multiplications are done on single clock cycles via the very powerful DSP48 slices. A typical setup from the Xilinx datasheet is:

[DSP48 slice from Xilinx UG479 document ]

 

I made a powerful Microblaze project complete with DDR3 access and UART. I then tested that out with a couple of very basic C scripts (1) to say hello on the screen and (2) to confirm the DDR3 was accessible. Once completed I added a DSP48 slice to my design to explore and see what that IP can achieve. Now I was able to delve into that IP block and could immediately see that addition and multiplication of the various bus inputs could be achieved....all interesting stuff. I pondered and searched the internet as surely I wasn't meant to select all those values/coefficients manually to achieve a fantastic function. What I managed to determine was that Xilinx make a tool for this called System Generator for DSP

System Generator for DSP™ is the industry’s leading architecture-level* design tool to define, test and implement high-performance DSP algorithms on Xilinx devices. Designed as an add-on toolbox for MathWorks Simulink®, System Generator for DSP takes advantage of pre-existing IP optimized for the FPGA fabric, which can be parameterized by the user to meet the quality and cost goals of the algorithms. System Generator for DSP features combined with the benefits of a rich simulation and verification environment offered by Simulink® enables the creation of production-quality DSP algorithms in a fraction of time compared to traditional RTL development times.

There were two things here that stopped me in my tracks - the use of Matlab/Simulink and the mention of buy/pricing on the System Generator tool. Whilst I could probably download a free demo on both I knew once mastered and I was hooked they would expire and leave me back on the basic design. I searched around some more to see if there was anything else in the Opensource domain, but could not find anything obvious. I guess manufacturers and developers using DSP are a long way from the hobbyist development on a limited budget.

 

As I read around the DSP subject matter I soon found reference to some 'DSP' type of IP blocks and when I looked in my own IP catalog I was able to add those as blocks. These included:

  • Fast Fourier Transform
  • LTE Fast Fourier Transform
  • Discrete Fourier Transform
  • FIR Compiler

 

The last item was particularly interesting as it was obvious the user could select the tap coefficients and there was even a tab to be able to investigate the filter's performance.

[The FIR Compiler IP block in Vivado]

 

And when I tried these out in my design I could see that they used the DSP48 slices as resources - so I would be able to test them out. Perhaps I could digitise an audio signal and run a filter block on it before passing back through a DAC? That wouldn't happen as I don't have an add on - the two Digilent ZMOD boards would have been ideal at this stage. I soon found myself right back to generating sinusoidal signals in an RTL block and realised I knew very little in this area and essentially it was my learning rather than testing out the Digilent hardware itself. Therefore I also add DSP to my growing list of things to learn, which aside from the implementation in FPGA hardware will also need me to understand how to read in or obtain a stream of data representing audio (or another signals) and try out various toolsets like Octave or something in Python or R-Studio etc.....this is a bit daunting but quite exciting IMO. In my quest to show the USB104-A7 doing something cool I have started to digress again, I have found myself out of my depth in understanding and therefore stop again.

 

9.5     GTP Transceivers

The Artix-7 device used contains four of these ultra-high speed transceivers, the term GTP seems to not actually mean anything, although one hidden internet source eludes to the GT standing for "Gunning Transceiver". Online documentation pointed to IP block called 7 Series FPGA Transceiver Wizard but I did not seem to have anything related to that in my version of Vivado; perhaps it is a version issue as I was still using Vivado 2018.3 for this test or perhaps a licensing issue for my version.

 

I looked around at some of the IP blocks I did have access to to see if they used the GTP block in the same way that some IP blocks used the DSP48 slices but I could not find any evidence. The only block that may have been a contender was the SelectIO Interface Wizard but it did not implicitly mention GTP blocks.Therefore, although this board's Artix-7 touts these ultra high speed transceivers I am currently unsure how a designer gains access to them. I feel this is another function that is outside the realms of a hobbyist design due to the licensing costs for the IP; for a business designer the issue is less so.

 

9.6     "Hello World"

I guess it wouldn't be a proper test without having a 'Hello World' example (or maybe Blinky LED ? ). Therefore I ran through the design of a firmware consisting of a Microblaze, AXI UART, AXI GPIO, PMOD to OLED, PMOD to NAVigation module etc. I actually struggled as I had also pulled in my PMOD SD but could not get the SDK to compile properly; eventually I found that PMOD SD examples are C++ based and the rest of my project was using C ! The PMOD examples are not pulled across into the msystem/mss like those for AXI interfaces, instead they can be found in the downloaded and extracted Vivado-Library from Digilent or by browsing the Github pages here.

 

The main source code for my SDK project was:

/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

#include "PmodOLED.h"
#include "sleep.h"
#include "xil_cache.h"

#include "xparameters.h"

/* ------------------------------------------------------------ */
/*                  Global Variables                            */
/* ------------------------------------------------------------ */

PmodOLED myDevice;


/* ------------------------------------------------------------ */
/*                  Forward Declarations                        */
/* ------------------------------------------------------------ */
void DemoInitialize();
void DemoRun();
void DemoCleanup();
void EnableCaches();
void DisableCaches();
void SplashScreen();


// To change between PmodOLED and OnBoardOLED is to change Orientation
const u8 orientation = 0x0; // Set up for Normal PmodOLED(false) vs normal
                            // Onboard OLED(true)
const u8 invert = 0x0; // true = whitebackground/black letters
                       // false = black background /white letters


int main()
{
    init_platform();
    print("Hello World - PMOD FINAL test project\n\r");

    DemoInitialize();
    while(1){
        SplashScreen();
        sleep(5);
    }
    DemoRun();
    DemoCleanup();

    cleanup_platform();
    return 0;
}

void DemoRun() {
   int irow, ib, i;
   u8 *pat;
   char c;

   xil_printf("UART and SPI opened for PmodOLED Demo\n\r");

   while (1) {
      xil_printf("entering loop\r\n");
      // Choosing Fill pattern 0
      pat = OLED_GetStdPattern(0);
      OLED_SetFillPattern(&myDevice, pat);
      // Turn automatic updating off
      OLED_SetCharUpdate(&myDevice, 0);

      // Draw a rectangle over writing then slide the rectangle down slowly
      // displaying all writing
      for (irow = 0; irow < OledRowMax; irow++) {
         OLED_ClearBuffer(&myDevice);
         OLED_SetCursor(&myDevice, 0, 0);
         OLED_PutString(&myDevice, "PmodOLED");
         OLED_SetCursor(&myDevice, 0, 1);
         OLED_PutString(&myDevice, "by Digilent");
         OLED_SetCursor(&myDevice, 0, 2);
         OLED_PutString(&myDevice, "Simple Demo");

         OLED_MoveTo(&myDevice, 0, irow);
         OLED_FillRect(&myDevice, 127, 31);
         OLED_MoveTo(&myDevice, 0, irow);
         OLED_LineTo(&myDevice, 127, irow);
         OLED_Update(&myDevice);
         usleep(100000);
      }

      sleep(1);
      // Blink the display three times.
      for (i = 0; i < 3; i++) {
         OLED_DisplayOff(&myDevice);
         usleep(500000);
         OLED_DisplayOn(&myDevice);
         usleep(500000);
      }
      sleep(2);

      // Now erase the characters from the display
      for (irow = OledRowMax - 1; irow >= 0; irow--) {
         OLED_SetDrawColor(&myDevice, 1);
         OLED_SetDrawMode(&myDevice, OledModeSet);
         OLED_MoveTo(&myDevice, 0, irow);
         OLED_LineTo(&myDevice, 127, irow);
         OLED_Update(&myDevice);
         usleep(25000);
         OLED_SetDrawMode(&myDevice, OledModeXor);
         OLED_MoveTo(&myDevice, 0, irow);
         OLED_LineTo(&myDevice, 127, irow);
         OLED_Update(&myDevice);
      }

      sleep(1);

      // Draw a rectangle in center of screen
      // Display the 8 different patterns available
      OLED_SetDrawMode(&myDevice, OledModeSet);

      for (ib = 1; ib < 8; ib++) {
         OLED_ClearBuffer(&myDevice);
         pat = OLED_GetStdPattern(ib);
         OLED_SetFillPattern(&myDevice, pat);
         OLED_MoveTo(&myDevice, 55, 1);
         OLED_FillRect(&myDevice, 75, 27);
         OLED_DrawRect(&myDevice, 75, 27);
         OLED_Update(&myDevice);

         sleep(1);
      }

#ifdef __MICROBLAZE__
      c = 'q';
#else
      xil_printf("(q)uit or any key to continue:\n\r");
      c = inbyte();
#endif

      if (c == 'q' || c == 'Q')
         break;
   }
   xil_printf("Exiting PmodOLED Demo\n\r");
}

void DemoCleanup() {
   OLED_End(&myDevice);
   DisableCaches();
}

void EnableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
   Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
   Xil_DCacheEnable();
#endif
#endif
}

void DisableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_DCACHE
   Xil_DCacheDisable();
#endif
#ifdef XPAR_MICROBLAZE_USE_ICACHE
   Xil_ICacheDisable();
#endif
#endif
}


void DemoInitialize() {
   EnableCaches();
   OLED_Begin(&myDevice, XPAR_PMODOLED_0_AXI_LITE_GPIO_BASEADDR,
         XPAR_PMODOLED_0_AXI_LITE_SPI_BASEADDR, orientation, invert);
}


void SplashScreen(){

    OLED_ClearBuffer(&myDevice);
    OLED_SetCursor(&myDevice, 0, 0);
    OLED_PutString(&myDevice, "Hello to the");
    OLED_SetCursor(&myDevice, 0, 1);
    OLED_PutString(&myDevice, "Element 14");
    OLED_SetCursor(&myDevice, 0, 2);
    OLED_PutString(&myDevice, "Community");
    sleep(3);

    OLED_ClearBuffer(&myDevice);
    OLED_SetCursor(&myDevice, 0, 0);
    OLED_PutString(&myDevice, "from the");
    OLED_SetCursor(&myDevice, 0, 1);
    OLED_PutString(&myDevice, "Digilent");
    OLED_SetCursor(&myDevice, 0, 2);
    OLED_PutString(&myDevice, "USB104-A7");
    sleep(3);

    OLED_ClearBuffer(&myDevice);
    OLED_SetCursor(&myDevice, 0, 0);
    OLED_PutString(&myDevice, "an Artix-7");
    OLED_SetCursor(&myDevice, 0, 1);
    OLED_PutString(&myDevice, "based FPGA");
    OLED_SetCursor(&myDevice, 0, 2);
    OLED_PutString(&myDevice, "development");
    OLED_SetCursor(&myDevice, 0, 3);
    OLED_PutString(&myDevice, "board");
    sleep(3);

    OLED_ClearBuffer(&myDevice);
    OLED_SetCursor(&myDevice, 0, 0);
    OLED_PutString(&myDevice, "Roadtested for");
    OLED_SetCursor(&myDevice, 0, 1);
    OLED_PutString(&myDevice, "Element 14");
    OLED_SetCursor(&myDevice, 0, 2);
    OLED_PutString(&myDevice, "Roadtest");
    OLED_SetCursor(&myDevice, 0, 3);
    OLED_PutString(&myDevice, "Programme");
    sleep(3);

    return;
}

 

10.     Conclusions:

10.1     Positives and Negatives

Apart from my own lack of understanding still on the FPGA design process, but which has in my opinion improved dramatically during this roadtest, I list the following good and bad points about the Digilent USB104-A7 development board.

 

Positives:

  • as stated this is the "highest performance per Watt fabric" in the 7-series family of FPGA. All the fabric is available to the designer and includes the 240 powerful DSP slices. The Microblaze IP is also very powerful as a 32/64 bit Microcontroller Unit (MCU). I'm not sure how the Microblaze specification stands up against a Zynq based FPGA though and wish to answer this as my knowledge grows - indeed putting a Linux system on a Microblaze. As a training board the lack of peripherals could actually be an advantage too - gone is the temptation to immediately use the shiny HDMI or quickly drop in the Zynq based IP core.
  • PC/104 board dimensions
  • Fast DPTI/DSPI interface to USB

 

Negatives:

  • Few peripherals included if being used solely for learning about FPGA. If this were for a beginner there are other lower cost with more peripherals to experiment with
  • The PSU adapter not generic
  • Detail on using Adept-2 and DPTI seemed lacking for the USB104-A7 and Linux OS
  • Detail on programming the design into Quad SPI flash was not clear (e.g. FLASH_IMAGE_BASEADDR value not stated)
  • Several links on the Digilent website seemed to be missing
  • The JTAG/Quad SPI changeover DIP switches seem needlessly small
  • Lack of proper PC/104 interface connector
  • Placement of PMOD perhaps could be improved

 

10.2     Scoring for this product

I have marked the product impartially and hopefully this feedback will be useful to Digilent in honing their products and support. My marks are:

 

Product performed to expectations, 10/10

It says Artix-7 and PC/104, and ticks both !

 

Specifications were sufficient to design with, 9/10

Again, it does what the Artix-7 can and that is quite powerful. There was enough detail in the specs to allow proper evaluation; anything missing was more down to my learning or licensing issues.

 

Demo software was of good quality, 6/10

I found there to be a lack of support in the DPTI area at least in terms of a simple worked example on this specific board. I found the lack of Linux support across all available software to leave me confused and this resulted in not being able to prove the DPTI or DSPI transfer. When trying to program the Quad SPI Flash documentation did not explain what value was required on the USB104-A7 for FLASH_IMAGE_BASEADDR.

 

Product was easy to use, 9/10

This mark was high as I had used Digilent FPGA boards before and therefore already had Vivado installed and understood how to add in new boards and IP to support my ideas. Although I did set out with the intent of reinforcing my learning by looking at this different board.

 

Support materials were available,  8/10

Most documentation that the designer requires is available on the Xilinx and Digilent websites. Some of the material for the USB104-A7 seems lacking, missing or refers to other Digilent boards and some extra effort is required from Digilent to polish that up to help designers; DPTI was a prime example.

 

The price to performance ratio was good,  7/10

This really depends what the buyer needs from the development board - if they want something that fits into PC/104 and has Artix-7 power plus a ZMOD then this would be 10/10. Alternatively for a limited budget beginner there are many boards from Digilent that are half the price of this and include more features or power, thus a 5/10 would be more appropriate. I've scored this in the middle for that reason.

 

10.3     Overall Conclusion

The Digilent USB-104-A7

If you want to learn about the Artix-7 and are developing an industrial application and need something better than PMOD then this is a very good contender. In such an industrial development cycle the cost of additional tools (such as DSP system generator or Mathsworks Simulink) or IP to really use the power of the core Artix-7 device are often less significant than for a hobbyist. The board is less mainstream than many other FPGA boards, even within the Digilent product range, and naturally this often equates to less technical support. I think this is true where I had issues understanding the DPTI interface, Adept 2 software and the hyperlinks missing off the Digilent website. Digilent may decide to lower the price of this board to make it more appealing and therefore increase use and the user-base of material available online - one idea would be to bundle the USB104-A7 with both of the available ZMOD boards for a combined lower price starter kit.

 

Other Contender Boards

For those on a more limited budget there are other boards that could be more appealing as they include more board functionality for a lower price. For the Xilinx 7-series most of these are Digilent based, and looking at just the Artix-7 variants:

BoardPrice (US $ from Digilent store Jan 2021)Notes
Basys 3149
Arty A7129Arduino shield compatible pins (NB voltage may not be so check !!)
Nexys A7229
Cmod A775Lowest cost Artix-7
Nexys Video Artix-7479
Nexys 4 Artix-7213.33Price is as on offer as 26th Jan 2021
USB104 A7549This roadtest board

 

11.     Sources and References:

 

12.     Acknowledgements

Thank you to Digilent Inc for sponsoring this product and, along with [mention:55e535b498a841ed8f2949266bc56dc3:e9ed411860ed4f2ba0265705b8793d05] , for selecting me to undertake this roadtest. For every one of my subject areas I wanted to improve on I was forced by this roadtest to look further - that was my intention and although there is still a lot for me to learn I found it a complete success and excited to continue my investigations into designing and building with this product. I hope to follow up on several of the technologies and processes I just scratched the surface of in the future such as the DPTI port data transfer, DSP techniques and building my own ZMOD or PMOD devices.

 

If anyone has any questions about this board or roadtest please don't hesitate to ask.

13.     Revisions

1.     28th Jan 2021:     The GTP transceivers are not actually provided on the XC7A100T package used for the Digilent USB104-A7, credit for info to USB104 A7: Artix-7 FPGA Development Board - Review

Anonymous
  • Hi Alex,

     

    Thank you, I'm glad you liked it and hopefully found my comments helpful and constructive. Like any new product I hoped the documentation would get updated as more people started to use the USB104-A7 so thanks for the updated link. Indeed searching the internet already returns hits for my fellow E14 members' useful roadtest reports so knowledge on the board is flowing onto the internet.

     

    Whilst I was taught the basics of DSP in college, that was a 'few' decades ago and it was more of a text book learning rather than being able to reinforce that understanding by doing. Therefore we rigorously thought that sampling needed to be twice the maximum frequency and that filters etc were some hour long derivation on the chalk board! With the power of computer modelling and algorithm generation it appears to be a much quicker task to explore 'what if?' situations and changing a parameter.

     

    I have a few ideas which are not novel but would allow me to understand the basics, and which I would blog about on Element14. The most likely would be to digitise analog signals to create an oscilloscope function where a ZMOD ADC board undertakes the digitising before streaming that data to the FPGA for capture, processing and storage in the DDR before the attached PC downloads and displays; not dissimilar in functionality to the Digilent Analog Discovery 2 but where I'd be understanding the internal design and DSP. Realistically that would be a lot of work and it might become a shorter series of shorter blogs explaining each of the steps without a final polished project. Once digitised I'd really like to explore the FFT algorithms to explore frequency components of the sampled signal.

     

    While the specification of the ZMOD ADC is far greater than required for this application, another idea would be to automatically strip out rhythms and beats from an audio stream which could then trigger lighting displays. This would be a great way of exploring the DSP blocks in the Artix-7. With two channels it would seem logical to undertake this analysis on both left and right audio channels.

     

    My other thoughts are to use the ZMOD DAC to create a very useful arbitrary waveform generator and to explore the methods to create signals ranging from simple sinusoids to chirped waveforms to IQ modulation and bespoke patterns loaded from the PC. Again, I think the Analog Discovery does this but it would be a very useful learning exercise to create something from scratch.

  • Great review.  We have put some other guides and tutorials at https://reference.digilentinc.com/reference/programmable-logic/usb104a7/start It seems you are interested in some DSP applications on Artix 7. If we give you the Zmod, what kind of applications can you think of?

  • If you're trying to prototype an SDR receiver or anything with a JESD204B , flash ADC you'll find that DSPI, DPTI are actually the bottleneck.

  • Thanks

     

    You've reminded me, I wanted to read your and reviews in detail now and especially the final conclusions. I hope Digilent have a read as well; I really think they could make a good discounted bundle of this (or another ZMOD compatible board) with the existing ADC and DAC boards. Although I didn't mention in my report, some of the smaller designs I tried out along the way really gave me a boost in understanding Vivado. For instance I made a design with a 'bells and whistles' Microblaze plus a simple Microblaze. When I got to the SDK part I better understood how I could program or debug each separately. Trouble is I've now a huge list of subjects I wish to try out....but I'm keen to carry on learning

  • A nice road test. It's great that so far the 3 of us have looked at the same board in different ways. I'm looking forward to seeing what the final 2 come up with.

  • Most of my FPGA DSP stuff has been done on Lattice ECP3 parts. I've used Altera MAX10 and Artix7 as well.

     

    MK

  • Thank you   its nice to pick up a comment from a FPGA expert....I seem to recall you doing some DSP stuff in the past, on ICE40? so will have to re-read that and see if it helps me.

  • Thanks , much appreciated

  • Thanks , always appreciated