摄像机检测开发:从视频流输入到dpu加速

前言

为了在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计算的部分开销

参考资料

[1] Zynq DPU Product Guide (PG338)

[2] xlnx,v-vpss-scaler.txt

[3] Xilinx V4L2 VPSS Scaler driver - Xilinx Wiki - Confluence (atlassian.net)

[4] AN5641 (alinx.vip)

[5] Alinx教程 - vitis-ai基础-v1.2.4

发表评论

评论内容会被上传至 百度智能云 审核,电子邮件地址不会被公开。必填项已用 * 标注