I am new to PYNQ environment and trying out this online example using PYNQ-Z2 board How to accelerate a Python function with PYNQ - FPGA Developer
Except for folder and design names, I have followed the tutorial closely and below is my overlay diagram and notebook. I have placed the .tcl, .bit and .hwh files in the overlay folder. FIR_Accel.pdf (80.3 KB) FIR_Acceleration.ipynb (434.2 KB)
I am able to run the codes until the part where it tries to address the FIR filter and got the error below:
On trying to debug the issue, I noticed there is no âfir_filterâ in the block design and I donât understand why the tutorial is able to run this line without issue. I tried changing it to overlay.filter.fir but still getting the error.
Can someone kindly point to me where I might have done wrong?
You are missing the custom driver that is being created to handle the FIR. .fir_filter does not refer to an IP, but rather is a method of the FirDriver class. This is cell 8 in the notebook.
Thank you for pointing out my misunderstanding bur I will like to seek further clarity. I ran cell 8 so shouldnât the function âfir_filterâ be recognized by my environment? Or am I missing some file on my PYNQ board? In the usual Python sense, I should invoke it using FirDriver.fir_filter isnât it?
You need to run cell 8 before using the Overlay class. Have you done that?
When you call Overlay, pynq assigns defaultHierarchy by default unless there is a class that inherits from defaultHierarchy in the environment. In such case, pynq will assign the corresponding class
Yes, I ran cell 8. The call to overlay.filter.fir_filter in my original post is in cell 9. After running cell 9 with error, I did a print out of the overlay details and copped out the following:
The tutorial was create with an older version of pynq. In the latest version, the fir is not part of the .ip_dict, so the hierarchy class needs updating. Note, that I also update to allocate, Xlnk is deprecated.
from pynq import DefaultHierarchy
from pynq import allocate
class FirDriver(DefaultHierarchy):
def __init__(self, description):
super().__init__(description)
def fir_filter(self, data):
with allocate(shape=(len(data),), dtype=np.int32) as in_buffer,\
allocate(shape=(len(data),), dtype=np.int32) as out_buffer:
np.copyto(in_buffer,data)
self.fir_dma.sendchannel.transfer(in_buffer)
self.fir_dma.recvchannel.transfer(out_buffer)
self.fir_dma.sendchannel.wait()
self.fir_dma.recvchannel.wait()
result = out_buffer.copy()
return result
# use @staticmethod... Can't change class state, just as a utility function
# remove check for FIR in the desc because somehow it's not there.
@staticmethod
def checkhierarchy(description):
if 'fir_dma' in description['ip']:
return True
else:
return False
I am able to overcome the issue with your inputs and obtain the output as you have shown. However, my issue persists with my environment complaining of âPynqBufferâ object has no attribute âfree_bufferâ on exiting the driver call when the function exit was invoked.
The PYNQ version I am using is Release 2019_10_03. When I reverted the two âallocateâ call to âxlnk.cma_arrayâ, I am still getting no free_buffer attribute error.
On my ZCU104, I get the following times:
Software FIR execution time: 0.0432887077331543
Hardware FIR execution time: 0.003331422805786133
Hardware FIR execution time (with driver): 0.07016849517822266
So using the the driver slows it down to much slower than just doing it in the CPU. Is this expected or does anyone have suggestions on how to optimize the driver code?
I am new to this and will update if I figure something out.
As alternative to upgrading to 2.6 as suggested, as a temporary workaround the notebook can be modified. The error is due to a bug in Pynq v2.5, specifically in buffer.py where PynqBuffer calls âfree_bufferâ at exit, but the implemented method is actually called âfreebufferâ. This is triggered by the use of the with block (regardless of the status of the buffers), so a solution is to make the driver method look more like the code in the earlier cell, just with a result = out_buffer.copy() instead of plotting.