In AMD's FPGA line-up, some of their 7 series devices have beefier siblings in the UltraScale+ device portfolio. The Artix-7 chip is one of my preferred 7 series devices for projects due to its balance between DSP bandwidth/transceiver speed and cost, so I was curious to start playing with an Artix UltraScale+ device.
AMD was kind enough to let me play with one of Opal Kelly's Artix UltraScale+ development boards, the XEM8320. This board has 6 SYZYGY ports and coupled with the various offerings of SYZYGY peripheral boards, the XEM8320 looks to be a fairly versatile option.
I chose to start with the SZG-SENSOR board that is all-in-one multi-sensor module including GNSS (GPS, GLONASS, Galileo), pressure, temperature, humidity, and ambient light / proximity that also has an accelerometer, gyroscope, and magnetometer built in. These are similar to the sensors I have commonly used with my Artix-7 boards and I wanted to get a better idea of how the Artix UltraScale+ performed.
I'm using Vivado 2022.1 in this project, but from what I can tell the same steps should apply in 2021.x. I have not verified it in 2022.2 yet.
Hardware SetupConnect the SZG-SENSOR board to Port A of the XEM8320 (this is important because this is where there reference design files from Opal Kelly expect it to be):
Provide 8v-14v power via the barrel jack wall adapter or one of the AMD 6-pin power supplies from this list. Further details for power requirements can be found on Opal Kelly's website here.
Finally connect to the XEM8320's USB C port to your host PC for the host interface via Opal Kelly's FrontPanel okHost
module that will be on the FPGA.
Download and extract folder to desired location. I created a dedicated Opal Kelly directory in my home folder:
~$ mkdir -p ./opalkelly
~$ cd ./opalkelly/
Add the downloaded repository as a default IP repository to Vivado by specifying its search path to Vivado. Add the IP location as a default IP repository search path under Tools > Settings > IP Defaults.
Clone the design examples repository to get the design source files for the XEM8320 with SZG-SENSOR board:
~/opalkelly$ git clone https://github.com/opalkelly-opensource/design-resources.git
Source the Vivado tools to the environment and launch the Vivado GUI:
~/opalkelly$ source /tools/Xilinx/Vivado/2022.1/settings64.sh
~/opalkelly$ vivado
In the Vivado TCL console, issue the following commands listed below to create the example project for the XEM8320 with SZG-SENSOR board (do not create a project manually).
First, change directories into the Sensor_Sample/XEM8320
directory of the cloned design examples repository:
cd /<path>/design-resources/ExampleProjects/Sensor_Sample/XEM8320/
Then source the project TCL script:
source ./project.tcl
After project generates, change project to target board instead of just the part. Open the Settings window from the Flow Navigator window and change the Project device from the the xcau25p-ffvb676-2-e part to the XEM8320 board:
When the project initially generated, it did not pick up the FrontPanel IP even though it should have when I added it's directory location to the default IP path for Vivado in the first step. I also noticed that the instantiation of it in the top level file (sensor.v
) seemed to actually be the lower level instantiation used in the auto-generated wrapper source file (<frontpanel_inst_name>_wrapper_synthesis.v
) when an instance of the FrontPanel IP is added to the project and generates.
I tried the scripts out in a few different versions of Vivado (2021.1, 2021.2, 2022.1) with the same result, which is why I ultimately added the same FrontPanel IP repository as a User IP repository to the project itself as well.
Once the FrontPanel IP repository is added open the IP Catalog from the Flow Navigator window and add an instance of the FrontPanel Subsystem. Configure it to have the following port settings:
- 7 WireIn (addr 0x00 - 0x06)
- 6 WireOut (addr 0x20, 0x22 - 0x26)
- 3 TriggerIn (addr 0x40 - 0x42)
- 1 TriggerOut (addr 0x60)
- 0 PipeIn
- 0 BTPipeIn
- 1 PipeOut (addr 0xa0)
- 0 BTPipeOut
Comment out the low-level instantiation of the FrontPanel in sensor.v
(lines 302 - 333), and replace it with the top-level FrontPanel IP instantiation:
assign ep20wire[31:8] = 24'd0;
assign ep22wire[31:13] = 19'd0;
assign ep23wire[31:9] = 23'd0;
assign ep24wire[31:9] = 23'd0;
assign ep25wire[31:9] = 23'd0;
assign ep26wire[31:9] = 23'd0;
assign to60_okClk[31:1] = 31'd0;
frontpanel_0 frontpanel_xem8320 (
.okUH(okUH), // input wire [4 : 0] okUH
.okHU(okHU), // output wire [2 : 0] okHU
.okUHU(okUHU), // inout wire [31 : 0] okUHU
.okAA(okAA), // inout wire okAA
.okClk(okClk), // output wire okClk
.wi00_ep_dataout(ep00wire), // output wire [31 : 0] wi00_ep_dataout
.wi01_ep_dataout(ep01wire), // output wire [31 : 0] wi01_ep_dataout
.wi02_ep_dataout(ep02wire), // output wire [31 : 0] wi02_ep_dataout
.wi03_ep_dataout(ep03wire), // output wire [31 : 0] wi03_ep_dataout
.wi04_ep_dataout(ep04wire), // output wire [31 : 0] wi04_ep_dataout
.wi05_ep_dataout(ep05wire), // output wire [31 : 0] wi05_ep_dataout
.wi06_ep_dataout(ep06wire), // output wire [31 : 0] wi06_ep_dataout
.wo20_ep_datain(ep20wire), // input wire [31 : 0] wo20_ep_datain
.wo22_ep_datain(ep22wire), // input wire [31 : 0] wo22_ep_datain
.wo23_ep_datain(ep23wire), // input wire [31 : 0] wo23_ep_datain
.wo24_ep_datain(ep24wire), // input wire [31 : 0] wo24_ep_datain
.wo25_ep_datain(ep25wire), // input wire [31 : 0] wo25_ep_datain
.wo26_ep_datain(ep26wire), // input wire [31 : 0] wo26_ep_datain
.ti40_ep_trigger(ti40_okClk), // output wire [31 : 0] ti40_ep_trigger
.ti40_ep_clk(okClk), // input wire ti40_ep_clk
.ti41_ep_trigger(ti41_okClk), // output wire [31 : 0] ti41_ep_trigger
.ti41_ep_clk(okClk), // input wire ti41_ep_clk
.ti42_ep_trigger(ti42_okClk), // output wire [31 : 0] ti42_ep_trigger
.ti42_ep_clk(okClk), // input wire ti42_ep_clk
.to60_ep_trigger(to60_okClk), // input wire [31 : 0] to60_ep_trigger
.to60_ep_clk(okClk), // input wire to60_ep_clk
.poa0_ep_datain(epA0pipe), // input wire [31 : 0] poa0_ep_datain
.poa0_ep_read(epA0read) // output wire poa0_ep_read
);
I did have to tie off a few unused bus line signals to ground to prevent unexpected behavior from the design due to the place & route stage randomly assigning them.
At this point, you can add any custom RTL and/or IP desired. Otherwise you can skip straight to running synthesis, implementation (place & route), and generate a bitstream.
A few critical warnings may pop-up in-between synthesis and implementation, but they can be ignored as long as there is only one critical warning left after bitstream generation about one clock name overriding another:
I was curious about this Artix UltraScale+ hardware design as to how it would stack up to my Artix-7 based Arty A7 board with a similar peripheral design to the sensor board on port A of the XEM8320.
Opening the Implemented Design and switching to the power tab, I found that the Artix UltraScale+ drew about twice the power and its regular Artix-7 sibling.
I'm getting a whole lot more processing power and programmable logic (PL) space on the Artix UltraScale+ however, so I was expecting a higher power draw. Look at how little of the PL is used for the simple sensor peripheral interface:
I did get stuck waiting for a license from Opal Kelly for the FrontPanel SDK to interface with the XEM8320 from my host PC, so I'll post a follow-up project once I get that installed to test out this bitstream!
Note: This tutorial is part of a paid partnership with AMD.
Comments