The PYNQ Ubuntu-based Linux system is designed for development but we have been getting an increasing number of questions about how PYNQ can be used in a more traditional embedded context where an 8 GB filesystem is not practical. At its heart PYNQ is a Python library with a set of drivers and overlays that do not need a fully-fledge desktop Linux system to run. To this end we have been working to include PYNQ as part of Petalinux with the 2019.2 release now including PYNQ version 2.4.
In this post I’ll run through creating a new Petalinux project targeting the ZCU104, configuring it to work with PYNQ and finally adding a design that uses PYNQ as a new recipe. For this walkthrough I will assume that you already have Petalinux installed and on the PATH but no additional tools will be required.
Creating the initial image
Fortunately the ZCU104 already has a publically available BSP available for download. With this file we can start by creating the reference project
> petalinux-create -t project -s xilinx-zcu104-v2019.2-final.bsp
Once the project is created we can enter the project directory to continue setting it up for PYNQ
> cd xilinx-zcu104-2019.2
One change we need to make to the project configuration is enabling the FPGA manager. This will prevent the default bitstream from being loaded at boot and loading all of the Linux kernel drivers for the pre-packaged design. Without this option reprogramming the bitstream after boot has the potential to crash the kernel as devices that Linux expects to see are no longer in the prgorammable logic.
To do this we us the petalinux-config
command and look for the desired option.
> petalinux-config
We also need to add the required kernel driver (CONFIG_XILINX_APF
) into the kernel. Again we can use the petalinux-config tool to perform the configuration
> petalinux-config -c kernel
Creating a recipe for PYNQ-Helloworld
Next we need to create a recipe for the design we want to add. I’m going use the PYNQ-HelloWorld example as it supports the ZCU104 and is the recommended starting point for other PYNQ projects providing an image-resizer hardware design and accompanying Python code.
Petalinux is based on the Yocto Project which is a system for creating embedded Linux distributions. It uses the bitbake build system for building recipes. Recipes are organised into layers. You can see that the Petalinux project that has been created contains two layers in the project_spec
folder – namely meta-user
where we should put new recipes and meta-plnx-generated
which is where Petalinux will place any recipes it generates as part of its configuration process.
To create our recipe first we need to create a new directory to contain all of the files we need – project-spec/meta-user/recipes-apps
seems tailor made for this.
> mkdir project-spec/meta-user/recipes-apps/python3-pynq-helloworld
> cd project-spec/meta-user/recipes-apps/python3-pynq-helloworld
The name of project is import as having the python3-
prefix will help the build system use the correct version of Python when building the package.
Next we need a .bb
file which contains the main recipe for the package. This should be named in accordance with the folder we’ve just created.
> vim python3-pynq-helloworld.bb
A recipe contains several sections that required. First we need to specify the license of the package and where the license is specified in the tarball along with the user-visible summary of the package.
SUMMARY = "PYNQ Helloworld"
LICENSE = "BSD"
LIC_FILES_CHKSUM = "file://LICENSE;md5=f9990fcc34ccf1f82ccf1bc5a1cc3bfc"
Next we have where the package can be obtained. In this case we are going to pull directly from the Xilinx github repository. We also need to tell bitbake where the root of the project is in the S
variable. For anything fetched with git this will be the git
subdirectory. Note that Yocto will check the checksums of the package files to ensure that nothing has changed since we created the recipe. This is part of its strategy for ensuring that builds are repeatable.
SRC_URI = "git://github.com/Xilinx/PYNQ-HelloWorld.git;protocol=https"
SRC_URI[md5sum] = "ac1bfe94a18301b26ae5110ea26ca596"
SRC_URI[sha256sum] = "f522c54c9418d1b1fdb6098cd7139439d47b041900000812c51200482d423460"
SRCREV = "0e10a7ee06c3e7d873f4468e06e523e2d58d07f8"
S = "${WORKDIR}/git"
Next we have the actual build portion. Luckily for us there are already bitbake recipes for projects that use setuptools and PYNQ so all we need to is inherit from the correct recipes.
inherit xilinx-pynq setuptools3
The xilinx-pynq
class will create a PYNQ_NOTEBOOK_DIR
variable that will be packaged up into the notebooks
sub-package but we are still required to ensure that the environment is correct for the recipe to run correctly. In this case we need to set the PYNQ_JUPYTER_NOTEBOOKS
and BOARD
environment variables. setup.py also expects that the notebook directory exists so we need to create it. For this we can prepend instructions to the various steps of the build
do_compile_prepend() {
export BOARD=ZCU104
export PYNQ_JUPYTER_NOTEBOOKS=${D}${PYNQ_NOTEBOOK_DIR}
}
do_install_prepend() {
export BOARD=ZCU104
export PYNQ_JUPYTER_NOTEBOOKS=${D}${PYNQ_NOTEBOOK_DIR}
install -d ${PYNQ_JUPYTER_NOTEBOOKS}
}
do_configure_prepend() {
export BOARD=ZCU104
export PYNQ_JUPYTER_NOTEBOOKS=${D}${PYNQ_NOTEBOOK_DIR}
install -d ${PYNQ_JUPYTER_NOTEBOOKS}
}
Finally we need to specify our dependencies. We’ll make the core package only depend on PYNQ and the other core libraries we need and the notebooks package also depend on Jupyter. Note the ${PN}
in these recipes is a short-hand for the current package name and RDEPENDS
means runtime dependencies. Note that we include need to include the python3-audio
and pynq-overlay
dependencies to ensure that all of the feature of PYNQ used by the helloworld application work correctly.
RDEPENDS_${PN} += "\
python3-pynq \
python3-audio \
python3-pillow \
pynq-overlay \
libstdc++ \
"
RDEPENDS_${PN}-notebooks += "\
python3-jupyter \
"
Now we have our completed recipe we can try and build it
> petalinux-build -c python3-pynq-helloworld
Which produces an error:
Which appears to be caused by a format string (f''
) in the package’s setup.py
which isn’t supported in the version of Python being used to perform the installation. To fix this we need to create a patch that replaces the format string with a plain addition. Looking more thoroughly at the notebooks we also see that the locations that the notebooks are installed will also need to change. Fixing both of those results in the following patch
diff --git a/setup.py b/setup.py
index 708dc25..21595f1 100644
--- a/setup.py
+++ b/setup.py
@@ -34,13 +34,13 @@ import shutil
# global variables
board = os.environ['BOARD']
-repo_board_folder = f'boards/{board}/resizer'
+repo_board_folder = 'boards/'+board+'/resizer'
board_notebooks_dir = os.environ['PYNQ_JUPYTER_NOTEBOOKS']
hw_data_files = []
# check whether board is supported
def check_env():
if not os.path.isdir(repo_board_folder):
raise ValueError("Board {} is not supported.".format(board))
if not os.path.isdir(board_notebooks_dir):
--
diff --git a/boards/ZCU104/resizer/notebooks/resizer_PL.ipynb b/boards/ZCU104/resizer/notebooks/resizer_PL.ipynb
index 1658d78..cd04d93 100644
--- a/boards/ZCU104/resizer/notebooks/resizer_PL.ipynb
+++ b/boards/ZCU104/resizer/notebooks/resizer_PL.ipynb
@@ -78,7 +78,7 @@
"outputs": [],
"source": [
"resize_design = Overlay(\n",
- " \"/usr/local/lib/python3.6/dist-packages/helloworld/bitstream/resizer.bit\")"
+ " \"/usr/lib/python3.5/site-packages/helloworld/bitstream/resizer.bit\")"
]
},
{
--
For Yocto to find the patch we need to place it another sub-folder also named according to the recipe name
> mkdir python3-pynq-helloworld
> cp $patch_file python3-pynq-helloworld/build-fixes.patch
We also need to update the SRC_URI
entry in the .bb file to include our new patch
SRC_URI = "git://github.com/Xilinx/PYNQ-HelloWorld.git;protocol=https \
file://build-fixes.patch \
"
Now our build completes succesfully
Adding the image to the filesystem
To add our new packages to the root filesystem we need to let Petalinux know of their existance. One way to do this is to add them to the user-rootfsconfig
> cd ../../
> vim conf/user-rootfsconfig
and add a line for each new package – the core and notebooks package for our new recipe in this case.
CONFIG_python3-pynq-helloworld
CONFIG_python3-pynq-helloworld-notebooks
Now we can run the Petalinux root filesystem configuration and select our two new packages
> petalinux-config -c rootfs
Building and testing
With everything set up we can now build the complete image
> petalinux-build
This will take a while and once it has completed our Linux image will be in images/linux
. For this example we will just use the image.ub
file which contains the kernel and root filesystem all packaged together. We will also need to generate a BOOT.BIN
file to perform the initial board set-up. In order for Linux to run our BOOT.BIN needs to contain u-boot, the arm trusted firmware and the platform management firmware in addition to the main bootloader
> petalinux-package --boot --u-boot --atf --pmufw
To test on the board we copy the BOOT.bin
and image.ub
files from images/linux
directory and boot the board.
Once the board is booted and Ethernet is configured you can go into the notebooks directory and start Jupyter
> cd /usr/share/notebooks
> jupyter notebook --ip=0.0.0.0 --no-browser --allow-root
Jupyter will start and give you an address to access the server in the terminal
Jupyter can now be interacted with the same as with the off-the-shelf PYNQ image.
Further reading
This has only been a very brief introduction to Petalinux and the creation of Yocto recipes. For a more in-depth exploration I recommend looking through the Yocto user-guide which contains much more detail on the steps that are invoked when running a bitbake recipe. The Petalinux documentation provides more details on how to build and run embedded Linux images. If you want to look through the code behind this have a look at:
- meta-xilinx which contains the PYNQ recipes
- meta-jupyter which is a Xilinx fork containing updated Jupyter recipes for Jupyter
- The example shown here is available as a GIST
If you have more questions or want to discuss further feel free to comment below or elsewhere in our forum.