This post is an extension of “Creating a simple overlay for PYNQ-Z1 board from Vivado HLx“, which presented an Overlay creation methodology for an accelerator block. The implemented block only communicates with Zynq Processing System (PS) and does not explain the PYNQ peripherals management. This work was developed with the help of Wagner Wesner.
The “base” Overlay found inside the PYNQ package is composed of the basic structures needed to handle PYNQ functionalities. The Vivado project (built on Vivado 2016.1) used to develop the “base” Overlay can be reconstructed from the Tcl file and observed:
For the proof of concept, an Overlay that controls PYNQ LEDs and Switches is developed. The “IP” responsible to control the LEDs and Switches is found and zoomed:
The base Overlay uses an “AXI GPIO” IP to interface the LEDs and Switches “GPIO” pins with the “AXI” bus protocol. The ARM processor inside the Zynq chip uses the AXI bus to communicate the Processing System with the Programmable Logic.
With reverse engineering, the implementation starts by opening Vivado (2017.2) and creating a new project with the “xc7z020clg400-1” part.
In the “IP INTEGRATOR” tab, select “Create Block Design”, the “Diagram” window opens. Right-click inside the “Diagram” window and add “ZYNQ7 Processing System” and “AXI GPIO” IPs:
Change “AXI GPIO” IP settings to match the base Overlay IP:
Then run Block and Connection automation:
The result after regenerating the layout should look as this:
Remember to change the name of the GPIO pins on the “AXI GPIO” block to match the names used on the “base” Overlay. These namings are important to virtually connect the pins to the physical peripherals.
The next step is creating an HDL wrapper to the design. On the “Sources” tab viewed from the “Diagram” window, right-click on the “design_1” with “design_1.bd” attached (or something similar) and select “Create HDL wrapper.” Keep the option “Let Vivado manage wrapper and auto-update” selected.
The “AXI GPIO” pins need a constraint file to prevent possible damage to the board, without it the bitstream generation would return DRC errors. The “base” Overlay repository contains all the constraints for its diagram. Inside the constraints file (top.xdc), it is possible to find the lines corresponding to the LEDs and Switches. A new constraint file is created with those lines:
The new constraints file is imported at Vivado with “PROJECT MANAGER->Add Sources”.
To generate the Overlay files:
- Select “Generate Bitstream”
- “File->Export->Export Bitstream File…”
- On Tcl Console -> “write_bd_tcl filename”
Both files should have the same name to be inter-referenced in the PYNQ environment.
Before moving to the PYNQ board, its is necessary to check the address assigned to the placed IP inside the “Address Editor” tab:
Since the “AXI GPIO” block came within the Vivado package, there is not a straight forward file indicating the address to control the GPIO pins. For the reference, the “base” overlay repository contains drivers for those pins management. Inside the drivers files, there are addresses assigned to control the LEDs luminosity and read the Switch positions:
For some reason, the switch reads a value from a default address on the “_mmio.read()” function, “_mmio” is an object of the “MMIO” class.
With all files and information required, transfer the overlay data (‘.bit’ and ‘.tcl’) to the PYNQ board and open it on a browser to visualize the Jupyter notebooks.
The Overlay class is used to download the created files on the PYNQ Programmable Logic. MMIO class is used to facilitate the communication between Programmable Logic and the Processing System. The time class will be used further to relieve the processor.
from pynq import Overlay from pynq import MMIO from time import sleep
Indicate the path of the Overlay files and download it:
ol = Overlay("/home/xilinx/jupyter_notebooks/control_led_overlay/led_sw_overlay.bit") ol.download()
Instantiate the “AXI GPIO” IP with its address and memory size:
led_sw_ip = MMIO(0x41200000,0x10000)
To write a value on the LEDs, indicate a single hexadecimal number. For example, “0xC” would turn first two LEDs on and last two LEDs off (C = 1100). Use the address found inside the “base” Overlay drivers.
The line below will print a single number from 0 to 3 indicating both Switches position (00-01-10-11).
To play with both peripherals at the same time, a program that light two LEDs accordingly to the Switches position is shown below:
while (cont<300): write_led = "0x"+str(led_sw_ip.read()) write_led = int(write_led,16) led_sw_ip.write(0x8,write_led) sleep(1) cont=cont+1
Source files can be found in: