前言
为了在fpga开发平台上实现一个高速相机检测系统,学习在axu9eg开发板上实现基于原厂工程的an5641(ov5640摄像模组)视频流输入获取以及目标检测识别的dpu加速
处理方案
使用的软件版本
Vivado 2020.1、Petalinux 2020.1、vitis sdk 2020.1
视频流输入部分
这里基于原厂的fpga部分进行修改,原厂的硬件布置方案为mipi输入->AXI4-Stream Subset Converter->vpss(色彩空间转换)->frame buffer,为了提高系统的效率,我将vpss修改为了scaler only模式(附加色彩空间转换支持),这样可以减少软件层在图片缩放上的开销。
dpu加速部分
由于编译设备性能较弱,我放弃了alinx教程推荐的导出可拓展的硬件描述文件,再petalinux导出sdk供vitis添加dpu的操作;通过vivado在工程中直接加入dpu ip核,这样的步骤可以减少编译设备负载,不过后续驱动需要自己编译。
实践
vivado部分
首先,我将vpss修改为了scaler only mode,并开启了色彩空间转换功能,修改后根据端口定义,重新对ip核进行连线(由于不需要通过vpss来同步,因此aresetn_io_axis悬空),并且需要重新配置vpss的地址空间大小,由原来的64k修改为256k,否则,使用地址空间不够的情况会发生,导致驱动加载卡死(详见此贴描述)。
然后添加了dpu ip(dpu ip核从xilinx github的vitis ai中得到),连线及时钟配置参考了xilinx的pg338文档,中断方式大部分教程推荐使用axi gpio,我选择了连接pl_ps_irq的方式(与pg338中提供方式相同),替代axi gpio(只是为了尝试其他中断的方案)
petalinux部分
在设备树中,首先按照alinx在github上提供的设备树,添加ov5640的摄像头描述及vpss、视频设备的管线,由于vpss的功能从csc更改成了scaler,驱动兼容信息(compatible)也要修改,同时为了vpss被正确识别为v4l2设备,compatible信息不得留空给petalinux自行生成,如果让petalinux自行生成,compatible信息则会优先匹配drm的vpss驱动(这些信息根据petalinux生成的device tree[components/plnx_workspace/device-tree/device-tree目录下内容],按照需要和规则,添加到system-user.dtsi,信息会覆盖自动生成的device tree内容)。再添加alinx提供的ov5640 mipi版本patch,它会修补ov5640的驱动,并且配置内核中需要开启的选项,至此摄像头视频输入配置完成。
#需要添加的内容
/ {
cam_reg_1v8: regulator-1v8 {
compatible = "regulator-fixed";
regulator-name = "1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
cam_reg_2v8: regulator-2v8 {
compatible = "regulator-fixed";
regulator-name = "2v8";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
cam_reg_1v5: regulator-1v5 {
compatible = "regulator-fixed";
regulator-name = "1v5";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
};
};
&i2c0 {
clock-frequency = <400000>;
eeprom@50{
compatible = "atmel,24c04";
reg = <0x50>;
pagesize = <16>;
};
lm75@48 {
compatible = "nxp,lm75";
reg = <0x48>;
};
};
&i2c1 {
ov5640: camera@3c {
compatible = "ovti,ov5640";
reg = <0x3c>;
clocks = <&misc_clk_a>;
clock-names = "xclk";
/* rotation = <180>; */
DOVDD-supply = <&cam_reg_1v8>;
AVDD-supply = <&cam_reg_2v8>;
DVDD-supply = <&cam_reg_1v5>;
port {
/* MIPI CSI-2 bus endpoint */
ov5640_to_mipi_csi2: endpoint {
remote-endpoint = <&csiss_in>;
clock-lanes = <0>;
data-lanes = <1 2>;
};
};
};
};
&mipi_csi2_rx_subsyst_0{
compatible = "xlnx,mipi-csi2-rx-subsystem-5.0";
csiss_ports: ports {
#address-cells = <1>;
#size-cells = <0>;
csiss_port0: port@0 {
reg = <0>;
xlnx,video-format = <0>;
xlnx,video-width = <8>;
csiss_out: endpoint {
remote-endpoint = <&csc_in>;
};
};
csiss_port1: port@1 {
reg = <1>;
xlnx,video-format = <0>;
xlnx,video-width = <8>;
csiss_in: endpoint {
data-lanes = <1 2>;
remote-endpoint = <&ov5640_to_mipi_csi2>;
};
};
};
};
&v_proc_ss_0{
compatible = "xlnx,v-vpss-scaler-2.2";
reset-gpios = <&gpio 86 1>;
csc_ports: ports {
#address-cells = <1>;
#size-cells = <0>;
csc_port0: port@0 {
reg = <0>;
xlnx,video-format = ;
xlnx,video-width = <8>;
csc_in: endpoint {
remote-endpoint = <&csiss_out>;
};
};
csc_port1: port@1 {
reg = <1>;
xlnx,video-format = ;
xlnx,video-width = <8>;
csc_out: endpoint {
remote-endpoint = <&vcap_in>;
};
};
};
};
&v_frmbuf_wr_0 {
compatible = "xlnx,axi-frmbuf-wr-v2.1";
reset-gpios = <&gpio 85 1>;
};
&amba_pl {
vcap_mipi {
compatible = "xlnx,video";
dma-names = "port0";
dmas = <&v_frmbuf_wr_0 0>;
vcap_ports: ports {
#address-cells = <1>;
#size-cells = <0>;
vcap_port: port@0 {
direction = "input";
reg = <0>;
vcap_in: endpoint {
remote-endpoint = <&csc_out>;
};
};
};
};
};
然后配置dpu,由于petalinux自动配置设备树中的compatible信息有误无法被dpu驱动正确识别,需要手动覆盖compatible信息为"xilinx,dpu",并且给出地址信息为当前dpu的基地址(或者修改dpu驱动源码,将驱动compatible信息改成petalinux生成的信息也行)。
#需要添加的内容,根据自己的设备树实际定义修改
&amba_pl {
DPUCZDX8G_0: DPUCZDX8G@81000000 {
compatible = "xilinx,dpu";
base-addr = <0x81000000>;
};
};
为保证以上内容的正常使用,我们需要在petalinux的rootfs配置中开启以下软件包组
packagegroup-petalinux-vitisai
packagegroup-petalinux-v4lutils
packagegroup-petalinux-xrt
packagegroup-petalinux-opencv
packagegroup-petalinux-python-modules
编译之后,dpu需要对应的驱动、vitis ai dnndk才能在Linux上正常调用,dpu驱动的源码在vitis ai中,驱动编译所需的内核源码在项目目录下的`build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts/`文件夹中,编译命令示例:`make ARCH=arm64 CROSS_COMPILE=aarch64-xilinx-linux- KERNELDIR=[项目目录]/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts/`(需要vitis sdk 2020.1),编译之后后,在开发板上通过insmod即可加载驱动。
然后vitis ai的dnndk可以通过Vitis-AI中的教程来编译,或者直接使用alinx提供的包,之后部署到开发板上,至此dpu部署完成。
Alinx提供DPU加速示例运行效果及后续优化
这里使用了tf_yolov3_voc示例,可以看到实际运行效率较低,代码中opencv对图像的resize以及nms算法在该开发板上的运用产生了较大的计算使延迟增加
这里,因为我们为vpss增加了视频缩放功能,所以我们将代码中用于缩放的功能删去,直接使用指定输入图像大小,可以看到速度有提升
pre-processing time中省去了获取图像的部分开销明显减少了约46ms,最终帧率提升了约1.7fps,有非常好的效果
post-processing time中省去了绘制框图和nms计算的部分开销
参考资料
[2]
[3]
[4]