I do a lot of work for clients using the PYNQ framework on a wide range of different boards. I have noticed a few great things about it, especially when creating custom overlays, so I thought they would make for a good blog. A few weeks ago, I wrote about the benefit of using PYNQ in development; so in this blog, we are going to examine a few more interesting aspects of PYNQ.
We can determine what IP blocks are included in an overlay and which driver is being used by simply using the command print(<overlay>.__doc__). This is particularly useful when we are working with custom overlays and we want to understand what they contain and how to use them.
If we need to know the physical address of IP within an overlay, we can access this information using the IP dictionary for that overlay using the command: <overlay>.ip_dict.
It is possible to search within this dictionary for physical addresses and so on.
The four fabric clocks from the PS to the PL can be changed on the fly using the frompynq.ps import clocks package in Jupyter. Using this package, we not only can read the current settings of the PS clocks, but change the frequency as well. This is important as it lets us stress test our design in the programmable logic. Take for example, an image processing application where the ability to increase the clock frequency enables the corner case of performance to be generated.
We can read the current setting of the PS clocks and the CPU clock. In this case, the base platforms are all set to 100 MHz.
Changing the clock frequency is straightforward. We just set the desired frequency in MHz. If the PLL settings do not support that exact frequency output, a warning in the notebook will be generated showing the actual frequency achieved by the PLL.
We can use this ease of changing the clock frequency to try out and push boundaries. For instance, setting the clock to 375 MHz causes corruption in the output image of an image processing algorithm as shown in the image below.
When running the same image processing chain at frequencies below 300 MHz, there is no corruption of the image.
If we want to see what the current divisors are set too, we can issue the command <overlay_name>.clock_dict.
From within the Jupyter cells, we can run command land functions. This means we can change the directory, access files, grab information from the internet and perform many more things all from within our notebook. This becomes especially useful if we wish to call programs from within our notebook. For example, drivers which configure external devices using I2C or SPI. To run command line instructions from our notebook, we prefix the command with ! which passes the command to the command line.
To aid with the development of our embedded applications using PYNQ, we can create and compile C programs directly on the target using GCC. In the Jupyter environment, we can make a new text file and enter our C application. See below for an example.
We can then compile and run this code from within a Jupyter Notebook thanks to the ability to pass command line arguments. Inside the notebook, we can inspect the contents of the C file and compile and execute it as shown in the diagram below.
As we work and create our PYNQ applications using Jupyter over a network interface, we are also able to map this into our network. This makes transferring new overlays and data to and from the PYNQ board simple. We can map the network drive in windows using the Map Network Drive option in the file explorer. The address is \\pynq\\xilinx and the username and password are both Xilinx.
Once this is completed, you will see the network drive now available under the file explorer.
These few simple tips allow us to work with PYNQ more effectively in our developments. PYNQ in turn, enables us to develop our applications and reduce risk much faster.
See My FPGA / SoC Projects: Adam Taylor on Hackster.io
Get the Code: ATaylorCEngFIET (Adam Taylor)