Over several articles in this series, we will have examined the PYNQ frameworks and available PYNQ boards most recently on the ZCU111 and Ultra96.

Xilinx boards for which PYNQ images are available: ZCU111, ZCU104, Zynq Z1, Zynq Z2 and Ultra96

If this is the first time you have come across PYNQ, PYNQ is an open source project started by Xilinx, which fuses the productivity of Python with the acceleration provided by programmable logic within the Zynq / Zynq MPSoC.

The tight coupling of processing system (PS) and programmable logic (PL) in the Zynq / Zynq MPSoC allows for the creation of systems that are more responsive, deterministic, and power efficient when compared to traditional CPU or GPU-based applications. This increase in performance is due to the ability to leverage the parallel nature of the programmable logic to move accelerate the application from the sequential software world to the parallel world enabled by programmable logic. However, developing the programmable logic solution requires advanced digital design skills limiting accessibility to software developers.

The PYNQ framework really is game changer in the programmable logic world. It enables the performance of programmable logic provided by Xilinx heterogeneous SoCs to be leveraged using Python one of the hottest programming languages, without the need to learn the digital design skills.

Most popular programming languages (📷: IEEE Spectrum)

As PYNQ is such a game changer, this is the first blog in a special edition of the MicroZed Chronicles which will be focused on PYNQ. In this special edition, we are going to be looking at the entire PYNQ ecosystem. Some of the key topics we are going to explore include:

Community overlays — what overlays are available for our PYNQ applications?

Creating applications using available overlays, e.g. image processing, BNN, etc.

Creation of our own overlays — how do we make a simple overlay from scratch?

Custom PYNQ images — how do we build and deploy PYNQ images for custom boards? PYNQ images can be generated for both Zynq and Zynq MPSoC-based boards.

Let’s start our journey into the PYNQ architecture by looking at the constituent parts of the PYNQ framework.

Starting at the top, the PYNQ framework uses iPython and Juypter notebooks enabling a browser-based development flow.

To be able to run the iPython kernel, and Jupyter webserver PYNQ images run an Ubuntu-based Linux image containing Ubuntu’s root file system, package manager and repositories on the processing system.

As we will see when we create our own PYNQ image, the PYNQ build flow itself is based upon the standard Xilinx PetaLinux build flow. This allows the PYNQ build to access all the Xilinx Kernel patches, board support packages, and crucially add in new drivers for processor system / programmable logic interfacing.

PYNQ framework stack

To transfer data between IP within the programmable logic and Jupyter notebooks, C-based drivers associated with the IP are encased in Python wrappers.

Communication between the processor system and the programmable logic depends on the interface used. In our PYNQ implementations, there are five different PS / PL interfaces which are used:

1) Bitstream — This configures the programmable logic for the desired application. In the PYNQ framework, the xdevcfg driver is used.

2) GPIO — This provides simple IO in both directions. In the PYNQ framework, this is supported by the sysgpio driver.

3) Interrupts — Support interrupt generation from the programmable logic to the processing system. In the PYNQ framework, this is supported by the Userspace IO driver.

4) Master AXI Interfaces — These are used to transfer data between the PS to the PL when the PS is the initiator of the transaction. The PYNQ framework uses devmem when employing master AXI interface.

5) Slave AXI Interfaces — These are used to transfer data between the PS and PL when the PL is the initiator of the transaction. The PYNQ framework uses xlnk to enable these transfers.

Interfacing between the PS and the PL in the PYNQ framework

The PYNQ framework builds upon these Linux Kernel drivers and offerse a range of PYNQ specific APIs, which provide specific PYNQ libraries and drivers. These APIs let the Jupyter notebooks bridge the gap, accessing the programmable logic.

As many of the applications require transfer of large quantities of data between the PS and PL, these APIs include support for Direct Memory Access (DMA) using the xlnk driver.

As developers, we leverage the PYNQ framework by connecting to the Jupyter server over a wired ethernet link and developing our application in a browser-based interface.

Browser-based development

One example of a PYNQ project is my recent Hackster.io project which used the PYNQ Z2 board to implement a PID control algorithm.

This project implements PID control algorithm to control the light level detected by a ambient light sensor. In this project, the programmable logic overlay used contains MicroBlaze softcore processors and interfacing logic that control the DAC and ambient light sensor, while the Python application implements the PID algorithm which both reads and writes values to the programmable logic to achieve the correct illumination level.

PID control loop driving to a set point

The videos below show the algorithm running:

Now we understand the PYNQ framework and what goes into it! In our next PYNQ edition blog, we will be looking in more depth at programmable logic overlays and how we work with them.

See My FPGA / SoC Projects: Adam Taylor on Hackster.io

Get the Code: ATaylorCEngFIET (Adam Taylor)

Access the MicroZed Chronicles Archives with over 270 articles on the Zynq / Zynq MpSoC updated weekly at MicroZed Chronicles.