RoadTest: AVNET MicroZed SOM 7Z010 + Carrier Card
Author: vmate
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?: Digilent's various development boards, PYNQ
What were the biggest problems encountered?: Lack of documentation for beginners
Detailed Review:
Introduction
The MicroZed SOM 7010 is a module using a Zynq 7010 SoC with 1GB of DDR3 RAM, providing 108 IO pins, 1Gbit Ethernet, and USB2.0.
The Arduino Carrier Card provides 2 PMOD connectors, one connected to the PL, the other connected to the PS. All of the Arduino pins are connected to the PL.
PS vs PL
The PS(Processing System) is a dual core ARM CPU in the case of this board, which can run C/C++ code, an RTOS, or Linux.
The PL(Programmable Logic) is the FPGA part of the chip.
These two parts can be connected together, for example, a hardware SPI controller can be created in the PL and connected to the PS, in case the 2 built-in SPI controllers aren’t enough.
There are separate pins on the Zynq that are connected to the PL, and another set of pins that are connected to the PS. The PL pins however can be used with the PS, by using AXI GPIO IP.
After installing Vivado, the board definition files need to be installed as well. Unfortunately, the MicroZed page has an outdated version of this file available. After downloading the latest version from GitHub, the microzed_7010 folder needs to be copied to
<install_location>\Vivado\<version>\data\boards\board_files
{gallery} Creating Vivado project |
---|
Creating Vivado Project: Create new project |
Creating Vivado Project: New project start screen |
Creating Vivado Project: Name and location of new project |
Creating Vivado Project: Set project type |
Creating Vivado Project: Select board preset |
Creating Vivado Project: New project summary |
Next, add the constraints file to the project.
Unfortunately, Avnet doesn't provide a "generic" XDC file for the Arduino Carrier Card, so I made one:
set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D15}]; set_property -dict { PACKAGE_PIN Y17 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D14}]; set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D13}]; set_property -dict { PACKAGE_PIN Y14 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D12}]; set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D11}]; set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D10}]; set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D9}]; set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D8}]; set_property -dict { PACKAGE_PIN N18 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D7}]; set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D6}]; set_property -dict { PACKAGE_PIN N20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D5}]; set_property -dict { PACKAGE_PIN P20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D4}]; set_property -dict { PACKAGE_PIN T20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D3}]; set_property -dict { PACKAGE_PIN U20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D2}]; set_property -dict { PACKAGE_PIN W20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D1}]; set_property -dict { PACKAGE_PIN V20 IOSTANDARD LVCMOS33 } [get_ports {ARDUINO_D0}]; set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports {PMOD_1}]; set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports {PMOD_2}]; set_property -dict { PACKAGE_PIN F19 IOSTANDARD LVCMOS33 } [get_ports {PMOD_3}]; set_property -dict { PACKAGE_PIN F20 IOSTANDARD LVCMOS33 } [get_ports {PMOD_4}]; set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports {PMOD_7}]; set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports {PMOD_8}]; set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports {PMOD_9}]; set_property -dict { PACKAGE_PIN L15 IOSTANDARD LVCMOS33 } [get_ports {PMOD_10}];
Import the constraints file to the Vivado project
{gallery} Importing Constraints |
---|
Importing Constraints: Add sources button |
Importing Constraints: Select source type |
Importing Constraints: Choose constraints file |
Importing Constraints: Finalizing |
Next, create a block design, add the ZYNQ7 Processing System, and generate an HDL wrapper
{gallery} ZYNQ Processing System |
---|
ZYNQ Processing System: Creating Block Design |
ZYNQ Processing System: Block Design name and location |
ZYNQ Processing System: Adding IP |
ZYNQ Processing System: Add ZYNQ7 Processing System IP |
ZYNQ Processing System: Run Block Automation |
ZYNQ Processing System: Block Automation settings |
ZYNQ Processing System: Creating HDL Wrapper |
ZYNQ Processing System: HDL Wrapper settings |
After creating the wrapper, generate a bitstream and export hardware
{gallery} Exporting Hardware |
---|
Exporting Hardware: Generate Bitstream |
Exporting Hardware: Bitstream generation settings |
Exporting Hardware: Completion of bitstream generation |
Exporting Hardware: Export Hardware button |
Exporting Hardware: Export Hardware dialog |
Exporting Hardware: Export settings |
Exporting Hardware: Save location and name |
Exporting Hardware: Finalizing |
{gallery} Creating Vitis Application Project |
---|
Creating Vitis Application Project: Start |
Creating Vitis Application Project: Import platform exported from Vivado |
Creating Vitis Application Project: Name project |
Creating Vitis Application Project: Create domain |
Creating Vitis Application Project: Finalize |
The User LED on the MicroZed is connected to the PS. The following code will blink the LED with a 1 second delay.
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #include "sleep.h" XGpioPs Gpio; int main() { init_platform(); XGpioPs_Config *GPIOConfigPtr; GPIOConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); XGpioPs_CfgInitialize(&Gpio, GPIOConfigPtr, GPIOConfigPtr->BaseAddr); XGpioPs_SetDirectionPin(&Gpio, 47, 1); XGpioPs_SetOutputEnablePin(&Gpio, 47, 1); while(1) { XGpioPs_WritePin(&Gpio, 47, 0); sleep(1); XGpioPs_WritePin(&Gpio, 47, 1); sleep(1); } cleanup_platform(); return 0; }
The following code reads the User Button state and controls the User LED accordingly.
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #include "sleep.h" XGpioPs Gpio; int main() { init_platform(); XGpioPs_Config *GPIOConfigPtr; GPIOConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); XGpioPs_CfgInitialize(&Gpio, GPIOConfigPtr, GPIOConfigPtr->BaseAddr); XGpioPs_SetDirectionPin(&Gpio, 47, 1); XGpioPs_SetOutputEnablePin(&Gpio, 47, 1); XGpioPs_SetDirectionPin(&Gpio, 51, 0); while(1) { int state = XGpioPs_ReadPin(&Gpio, 51); XGpioPs_WritePin(&Gpio, 47, state); } cleanup_platform(); return 0; }
Additional GPIO "controllers" can be created in the FPGA part of the Zynq, which also allows us to connect custom HDL modules to the input/output of those GPIO controllers.
In this example, we'll create a NAND gate in the FPGA, the output of which is connected to an AXI GPIO IP, which is also implemented in the FPGA, which is then read by the PS, that controls the User LED according to the output of the NAND gate.
First, create a new Verilog module that implements a NAND gate
{gallery} Creating Verilog NAND gate |
---|
Creating Verilog module: Add Sources |
Creating Verilog module: Select source type |
Creating Verilog module: Create new file |
Creating Verilog module: New file properties |
Creating Verilog module: Finish adding new source |
Creating Verilog module: Specify I/O Ports |
Creating Verilog module: Create NAND gate |
Then, add the NAND gate module to the Block Diagram
Enable the AXI master interface in the Zynq Processing System by double clicking on it, and selecting the appropriate option shown below.
Add the AXI GPIO IP to the block diagram
Run Connection Automation for AXI port on the AXI GPIO IP
Configure AXI GPIO as a single input
Connect NAND gate output to AXI GPIO input
Connect inputs on NAND gate to physical pins on the FPGA
Rename external connection to a pin name from the constraints(.xdc) file.
Repeat for input "b"
Completed block diagram
Generate the bitstream and export hardware, then launch Vitis and create new hardware project as shown previously.
Processing System code for reading NAND gate output through AXI GPIO, and controlling User LED accordingly:
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #include "sleep.h" #include "xgpio.h" #include "xparameters.h" XGpioPs Gpio; XGpio FPGA_Gpio; int main() { init_platform(); XGpioPs_Config *GPIOConfigPtr; GPIOConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID); XGpioPs_CfgInitialize(&Gpio, GPIOConfigPtr, GPIOConfigPtr->BaseAddr); XGpioPs_SetDirectionPin(&Gpio, 47, 1); XGpioPs_SetOutputEnablePin(&Gpio, 47, 1); XGpio_Initialize($FPGA_Gpio, XPAR_AXO_GPIO_0_DEVICE_ID); XGpio_SetDataDirection($FPGA_Gpio, 1, 0); while(1) { int state = XGpio_DiscreteRead(&FPGA_Gpio, 1); XGpioPs_WritePin(&Gpio, 47, state); } cleanup_platform(); return 0; }
The MicroZed is a very capable board with plenty of documentation, however there is some very basic information missing for people who haven't worked with a Xilinx FPGA/Zynq SoC before. The first thing I wanted to do with this board was make a NOT gate in the FPGA using the User Button and User LED, but as it turned out after doing some research, the User LED and User Button are connected to the MIO pins, which can only be controlled from the PS. Basic information like this could be very useful for a beginner, just like providing a generic constraints file for the Arduino Carrier Card. Otherwise, the documentation is well made, and there are plenty of example projects available to download.
Having more PMOD connectors on the Arduino Carrier Card would be useful, even if it shared pins with the Arduino headers. The current configuration of one PS PMOD and one PL PMOD makes it inconvenient to use PMODs that require two connectors, requiring the use of jumper cables to interface with the Arduino headers as well for the second PMOD connector.
A PL PMOD in addition to the PS PMOD on the MicroZed itself would be favorable as well.
Top Comments
Nice road test report.
DAB