PYNQ: PYTHON PRODUCTIVITY

Build PYNQ OS for ZCU102 with Yocto

Hi all, apologies if this isn’t located in the right location of the forum.

I’m working with a ZCU102 board at the moment (ultimately I’ll be working with a custom board very similar to the ZCU102), and have an existing workflow to build a custom OS with Yocto (and xilinx yocto-manifests). I’d like to incorporate PYNQ into the build.

I’ve been looking at meta-xilinx-pynq but I’m having trouble figuring out what I potentially need to change to be able to do this for the ZCU102. This recipe is just valid for the ZCU104 and Ultra96 as preexisting PYNQ boards, so I believe it just points pynq to the proper boards.

After reading through the SDCard flow on readthedocs and the readme on github, it seems like this should be possible, since all you really need is an hdf file. I’m passing in the .hdf file to the OS build already with meta-xilinx-tools external-hdf so it seems like this should be doable. Has anyone done something similar or have ideas where to start?

Thanks! And sorry for the very general questions.

Are you looking to install the PYNQ python package inside your Yocto image or create a Ubuntu-derivative PYNQ image for your board? Both are possible but have different paths.

Peter

I’d like to install the PYNQ python package in the Yocto image, mainly for the use of the DMA code that’s available in PYNQ.

With Petalinux 2020.1 and later you should just be able to include the python3-pynq package in your Yocto project the same as any other. The board-specific parts are there to add notebooks/bitstreams that we ship with PYNQ or via our partners for the ZCU104 and Ultra96 so you can safely ignore it - we don’t have any for the ZCU102.

Peter

Ah okay thanks for heads up! I’ll try doing this outside of the meta-xilinx-pynq and doing it as you say for any other python package.

You can still use meta-xilinx-pynq to get the python3-pynq recipe. What I mean is you shouldn’t need to modify it for your board.

Ah okay thanks. When I stopped trying to include pynq-overlays I then got an error complaining that the XRT environment isn’t set up. I see on the PYNQ gitlab that " For Alveo cards, PYNQ currently requires a Xilinx Runtime (XRT) version above or equal to 2.3 to be installed in the system," but is XRT also required for Zynq devices?

You shouldn’t need XRT. If the pynq-overlay recipe isn’t working you may need manually add the xlnk entry to your device-tree - specifically lines 5-7 of this fragment. They can got either under the amba node or directly in the root node.

Peter

After adding the xlnk device tree entry I now get the following (sorry for the long error output):

 >>> import pynq
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/site-packages/pynq/__init__.py", line 33, in <module>
from .pl import PL
  File "/usr/lib/python3.7/site-packages/pynq/pl.py", line 39, in <module>
from .ps import CPU_ARCH_IS_SUPPORTED, CPU_ARCH, ZYNQ_ARCH, ZU_ARCH
  File "/usr/lib/python3.7/site-packages/pynq/ps.py", line 322, in <module>
class _ClocksUltrascale(_ClocksMeta):
  File "/usr/lib/python3.7/site-packages/pynq/ps.py", line 382, in _ClocksUltrascale
IOPLL_CTRL = Register(CRL_APB_ADDRESS + IOPLL_CTRL_OFFSET)
  File "/usr/lib/python3.7/site-packages/pynq/registers.py", line 115, in __init__
array = MMIO(address, np.dtype(register_type).itemsize).array
  File "/usr/lib/python3.7/site-packages/pynq/mmio.py", line 82, in __init__
device = Device.active_device
  File "/usr/lib/python3.7/site-packages/pynq/pl_server/device.py", line 95, in active_device
raise RuntimeError("No Devices Found")
RuntimeError: No Devices Found

I took a look at device.py but I’m not sure why the device isn’t being found. What types of devices are expected here?

It’s looking for /dev/xlnk which is the main device used by PYNQ for allocating memory. Can you make sure that CONFIG_XILINX_APF is enabled in your kernel? That and the device-tree fragments should be the only things needed to enable it.

Peter

Hi Peter I think that worked, thanks! It seems like to use the DMA code, you have to load an overlay. In examples it seems like the overlay is a bitfile, but when I tried to load a bitfile I got an error. Is there more code I need to write to define an overlay that I can use with my board? Sorry for the basic questions again.

An Overlay instance also needs the an hwh file to go alongside it. You can find it inside the Vivado project. The hwh file should be named the same as the bitstream - e.g. my_overlay.bit and my_overlay.hwh. If you don’t want to use the hwh file lyou can instead create a Bitstream object but then you won’t have access to any of the PYNQ drivers/discovery as we can’t determine what’s inside the file.

Peter

Hi we did actually include the .hwh file as there was an error asking for it, but we see a problem with the fpga manager, so we will have to keep trying to debug. Thanks again for your help!

[ 659.777637] fpga_manager fpga0: writing AXI_DMA.bin to Xilinx ZynqMP FPGA Manager
[ 659.796087] fpga_manager fpga0: Error while writing image data to FPGA
OSError: [Errno 22] Invalid argument

Have a look in dmesg and you might find more info on what’s gone wrong. The most common reason I’ve seen is a part mismatch so it’s worth double checking the revision of the board being used.

Peter

Hello, we were able to generate a binfile that works with the fpga manager using the vivado shell environment instead of the gui. Is there a way to pass pynq a binfile or does it need the header in the bitfile? At the moment if we just give the binfile we get an error which I think is related to the lack of header:

overlay = Overlay('/home/root/AXI_DMA.bit.bin')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/site-packages/pynq/overlay.py", line 344, in __init__
    self.download()
  File "/usr/lib/python3.7/site-packages/pynq/overlay.py", line 403, in download
    super().download(self.parser)
  File "/usr/lib/python3.7/site-packages/pynq/bitstream.py", line 154, in download
    self.device.download(self, parser)
  File "/usr/lib/python3.7/site-packages/pynq/pl_server/device.py", line 617, in download
    _preload_binfile(bitstream)
  File "/usr/lib/python3.7/site-packages/pynq/pl_server/device.py", line 547, in _preload_binfile
    bit_dict = parse_bit_header(bitstream.bitfile_name)
  File "/usr/lib/python3.7/site-packages/pynq/pl_server/device.py", line 513, in parse_bit_header
    contents[offset:offset + length])[0]
struct.error: bad char in struct format

We don’t have a defined way to pass a .bin file to PYNQ. You might be able to hack around it by doing something like

overlay = Overlay('...', download=False)
overlay.binfile_name = "Name of bin file in /lib/firmware"
overlay.download()

One thing you could do is compare the bin file you have that works with the one PYNQ creates in /lib/firmware/ and see what’s different. It’s possible we’re not doing the conversion properly so it would be good to have a test case.

Peter

Hi @PeterOgden with the workaround we were able to load the overlay, but now get an error associated with interrupts:

dma = overlay.axi_dma_0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/site-packages/pynq/overlay.py", line 356, in __getattr__
    return getattr(self._ip_map, key)
  File "/usr/lib/python3.7/site-packages/pynq/overlay.py", line 861, in __getattr__
    driver = ipdescription['driver'](ipdescription)
  File "/usr/lib/python3.7/site-packages/pynq/lib/dma.py", line 190, in __init__
    super().__init__(description=description)
  File "/usr/lib/python3.7/site-packages/pynq/overlay.py", line 649, in __init__
    setattr(self, interrupt, Interrupt(details['fullpath']))
  File "/usr/lib/python3.7/site-packages/pynq/interrupt.py", line 98, in __init__
    _InterruptController.get_controller(parentname))
  File "/usr/lib/python3.7/site-packages/pynq/interrupt.py", line 159, in get_controller
    ret = _InterruptController(name)
  File "/usr/lib/python3.7/site-packages/pynq/interrupt.py", line 191, in __init__
    'for IRQ number {}'.format(number))
ValueError: Could not find UIO device for interrupt pin for IRQ number 0

I found this post: ValueError: Could not find UIO device for interrupt pin for IRQ number 0 which is very similar to our problem. I do have the proper entry in the device tree, but is there a way to check if the interrupt is binding to another entry first, or that I have the correct UIO device drivers compiled into the kernel? Thanks!

To clarify, the device tree has this fragment included, but nothing like the one here:

uio_0: uio_int0@0{
            compatible="generic-uio";
            status="okay";
            interrupt-controller;
            interrupt-parent=<&intc>;
            interrupts=<0x0 0x1d 0x4>;
};

Does the UIO device appear in /proc/interrupts?

Hi @PeterOgden it looks like no it does not