PYNQ学习笔记-在PS端调用FPGA模块

PYNQ简介

PYNQ(Python On Zynq)是一个软件开发框架,指导硬件层、驱动层和应用层之间的接口设计,通过python编程可调用FPGA模块,从而更方便地使用FPGA实现硬件加速等功能。

PYNQ包含两大功能块:PS(Processing System)部分和PL(Programmable Logic)部分。以PYNQ-Z2开发板为例,其PS部分是650MHz双核Cortex-A9处理器,PL部分是Artix-7系列可编程逻辑。
使用PYNQ进行编程的各部分框架关系如下图所示:
PYNQ学习笔记-在PS端调用FPGA模块_第1张图片

PYNQ Overlay简介

Overlays(硬件库),是一种可编程FPGA的设计理念,通过它可把PS端的应用在FPGA实现,从而用来加速软件应用,在vivado HLS进行编程并封装成ip核后,在vivado将各ip核进行组合连接然后生成比特流文件,在PS端进行调用。
Overlay包含两个主要的组件:FPGA逻辑设计(bitstream)以及工程block diagram的tcl文件,这两个文件都是使用vivado生成的。

PYNQ学习笔记-在PS端调用FPGA模块_第2张图片

基于Overlay的设计

加载overlay:
通过Jupyter notebook输入http://PPYNQ在局域网中的ip地址:9090 进入jupyter界面,然后在代码文件中输入:

from pynq import Overlay
overlay=Overlay("xxx.bit")

加载在vivado端生成的.bit文件中的信息。
在overlay名称后加?能够获取overlay的内容,如:overlay?
Overlay中所有的入口都可以通过overlay的类属性来访问,这些属性里包含了特定的驱动。
例如访问Overlay中的x属性时,将会为这个IP创建驱动,如:

x_ip=overlay.xxx
x_ip?

注:xxx代表vivado设计中某ip核的名称
通过读取hls的源代码得知此ip的具体使用方法,在相应的偏移地址出写入/读取相应参数/计算结果即可

x_ip.write(0x10,1)
x_ip.write(0x18,6)
x_ip.read(0x20)

即可完成FPGA部分的模块调用。

使用DMA时

当ip设计时使用了用于数据传输的DMA控制器(Engine),操作如下:

首先实例化dma的ip:

dma = overlay.axi_dma_0

DMA驱动会传输数据到事先通过xlnk()方法allocate DRAM的空间。
以处理图像为例,首先分配内存来处理PL上的数据,数据作为连续的存储块提供,缓冲区的大小取决于输入或输出数据的大小,从读取图像中提取的图像尺寸用于分配连续的存储块。 通过调用cma_array()执行分配。相关操作如下:

from pynq import Xlnk
from numpy as np
from PIL import Image
from IPython.display import display

xlnk = Xlnk()
in_buffer = xlnk.cma_array(shape=(pic_height, pic_width), 
                           dtype=np.uint8)
out_buffer = xlnk.cma_array(shape=(pic_height, pic_width), 
                            dtype=np.uint8)
                            
image_path = "1.jpg"
original_image = Image.open(image_path) 
input_array = np.array(original_image)                            
np.copyto(in_buffer,input_array)

buf_image = Image.fromarray(in_buffer)

然后调用相应图像处理的IP核(此处以x_ip代表)

输入图片参数,这部分根据自己编写的IP定

x_ip.write(0x14, pic_height) #rows
x_ip.write(0x1c, pic_width) #cols

.
将数据从输入缓冲区通过管道推送到输出缓冲区,向图像处理的IP核写入起始信号

dma.sendchannel.transfer(in_buffer)
dma.recvchannel.transfer(out_buffer)    
x_ip.write(0x00,0x81) # start
dma.sendchannel.wait()
dma.recvchannel.wait()

最后得到图像信息并进行显示

result = Image.fromarray(out_buffer)
result = Image.fromarray(out_buffer)
display(result)

最后需要关闭并且重启xlnk避免发生内存泄漏

in_buffer.close()
out_buffer.close()
#%%
xlnk.xlnk_reset()

参考:xilinx官网相关例程与资料

你可能感兴趣的:(PYNQ,fpga)