当前位置: 代码迷 >> 综合 >> 【ZYNQ-7000开发之十】TGP+VDMA+HDMI搭建视频通路
  详细解决方案

【ZYNQ-7000开发之十】TGP+VDMA+HDMI搭建视频通路

热度:87   发布时间:2024-01-06 17:58:46.0

本编文章在ADI官方HDMI例程的基础上进行修改,实现视频通路,为使用ZYNQ视频处理做好必要准备。

在 【ZYNQ-7000开发之九】使用VDMA在PL和PS之间传输视频流数据 这篇文章中,介绍了如何使用VDMA传输stream类型的视频流数据,本次实验将结合【ZYNQ-7000开发之三】ZYNQ平台的HDMI驱动测试这篇文章,本次实验默认大家已经完成了【ZYNQ-7000开发之三】和【ZYNQ-7000开发之九,至少要完成【ZYNQ-7000开发之三】,本次实验将在【ZYNQ-7000开发之三】的基础上直接修改。
本篇文章的思想是使用TPG产生stream类型的数据,然后用VDMA转换成Memory Map类型的数据写入到DDR3缓存,最后再用VDMA 从DDR3读出来转换成stream类型,发送给HDMI控制器,进而显示在HDMI显示器上。

TGP VDMA等的规范说明可以到官网下载最新版本

本文所使用的开发板是Miz702(兼容zedboard)
PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2
其它:HDMI显示器,串口线

修改硬件系统工程

打开【ZYNQ-7000开发之三】做好的vivado工程,打开Block Design
找到VDMA双击,选中Enable Write Channel,同时设置Memory Map Data Width为64,点击OK

这里写图片描述

点击Run Connection Automation,在弹出的对话框选择ALL,点击OK
点击ADD IP,添加一个TPG IP Core
双击刚刚添加的TPG,按照如图所示配置,这个主要为了简洁一些,去掉了一些不必要的功能

这里写图片描述

把TPG的video_out和VDMA的S_AXIS_S2MM连接在一起,如图所示

这里写图片描述

同理把TPG的aclk连接到VDMA的aclk,把TPG的aresetn连接到VDMA的resetn,此外VDMA的s_axis_s2mm_aclk也和VDMA的aclk连在一起
然后按下F6快捷键,验证下系统是不是有问题,没有问题就保存工程,点击generate bitstream
完成后,导出硬件,Launch SDK

修改软件工程

找到cf_hdmi.c文件,把InitHdmiVideoPcore函数修改如下:
/***************************************************************************//*** @brief InitHdmiVideoPcore.
*******************************************************************************/ void InitHdmiVideoPcore(unsigned short horizontalActiveTime,unsigned short horizontalBlankingTime,unsigned short horizontalSyncOffset,unsigned short horizontalSyncPulseWidth,unsigned short verticalActiveTime,unsigned short verticalBlankingTime,unsigned short verticalSyncOffset,unsigned short verticalSyncPulseWidth) {unsigned short horizontalCount = 0;unsigned short verticalCount = 0;unsigned short horizontalBackPorch = 0;unsigned short verticalBackPorch = 0;unsigned short horizontalDeMin = 0;unsigned short horizontalDeMax = 0;unsigned short verticalDeMin = 0;unsigned short verticalDeMax = 0;DDRVideoWr(horizontalActiveTime, verticalActiveTime);horizontalCount = horizontalActiveTime +horizontalBlankingTime;verticalCount = verticalActiveTime +verticalBlankingTime;horizontalBackPorch = horizontalBlankingTime -horizontalSyncOffset -horizontalSyncPulseWidth;verticalBackPorch = verticalBlankingTime -verticalSyncOffset -verticalSyncPulseWidth;horizontalDeMin = horizontalSyncPulseWidth +horizontalBackPorch;horizontalDeMax = horizontalDeMin +horizontalActiveTime;verticalDeMin = verticalSyncPulseWidth +verticalBackPorch;verticalDeMax = verticalDeMin +verticalActiveTime;Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_HTIMING1),((horizontalActiveTime << 16) | horizontalCount));Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_HTIMING2),horizontalSyncPulseWidth);Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_HTIMING3),((horizontalDeMax << 16) | horizontalDeMin));Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_VTIMING1),((verticalActiveTime << 16) | verticalCount));Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_VTIMING2),verticalSyncPulseWidth);Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_VTIMING3),((verticalDeMax << 16) | verticalDeMin));Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_RESET), 0x1);Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_SOURCE_SEL), 0x0);Xil_Out32((CFV_BASEADDR + AXI_HDMI_REG_SOURCE_SEL), 0x1);Xil_Out32(VDMA_BASEADDR + 0x30, 0x4); //reset S2MM VDMA Control RegisterXil_Out32(VDMA_BASEADDR + 0x30, 0x8); //genlockXil_Out32(VDMA_BASEADDR + 0xAC, 0x08000000);//S2MM Start AddressesXil_Out32(VDMA_BASEADDR + 0xAC+4, 0x0A000000);Xil_Out32(VDMA_BASEADDR + 0xAC+8, 0x0D000000);Xil_Out32(VDMA_BASEADDR + 0xA4, 640*4);//S2MM Horizontal SizeXil_Out32(VDMA_BASEADDR + 0xA8, 640*4);//S2MM Frame Delay and StrideXil_Out32(VDMA_BASEADDR + 0x30, 0x3);//S2MM VDMA Control RegisterXil_Out32(VDMA_BASEADDR + 0xA0, 480);//S2MM Vertical Size start an S2MXil_DCacheFlush();Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_DMA_CTRL),0x00000003); // enable circular modeXil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_1),0x08000000); // start address Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_2),0x0A000000); // start addressXil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_3),0x0D000000); // start addressXil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_FRMDLY_STRIDE),(horizontalActiveTime*4)); // h offsetXil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_H_SIZE),(horizontalActiveTime*4)); // h sizeXil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_V_SIZE),verticalActiveTime); // v size }
分别配置好FPGA和ARM后,在串口终端按‘6’,选择640*480分辨率,看到如下所示的效果就成功了。大家可以更换TPG的输出类型,查看不同的效果。

这里写图片描述

总结

目前通过zynq实现了640*480的视频显示,大家可以调试下其它的分辨率。此外,串口终端发送数据的时候会断开,不知道大家是否会遇到这个BUG。

  相关解决方案