本帖最后由 RZJM 于 2016-1-26 20:46 编辑
本编文章在ADI官方HDMI例程的基础上进行修改,实现视频通路,为使用ZYNQ视频处理做好必要准备。 在 【ZYNQ-7000开发之九】使用VDMA在PL和PS之间传输视频流数据 这篇文章中,介绍了如何使用VDMA传输stream类型的视频流数据,本次实验将结合【ZYNQ-7000开发之三】ZYNQ平台的HDMI驱动测试这篇文章,本次实验默认大家已经完成了【三】和【九】,至少要完成【三】,本次实验将在【三】的基础上直接修改。
本篇文章的思想是使用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 Register
- Xil_Out32(VDMA_BASEADDR + 0x30, 0x8); //genlock
- Xil_Out32(VDMA_BASEADDR + 0xAC, 0x08000000);//S2MM Start Addresses
- Xil_Out32(VDMA_BASEADDR + 0xAC+4, 0x0A000000);
- Xil_Out32(VDMA_BASEADDR + 0xAC+8, 0x0D000000);
- Xil_Out32(VDMA_BASEADDR + 0xA4, 640*4);//S2MM Horizontal Size
- Xil_Out32(VDMA_BASEADDR + 0xA8, 640*4);//S2MM Frame Delay and Stride
- Xil_Out32(VDMA_BASEADDR + 0x30, 0x3);//S2MM VDMA Control Register
- Xil_Out32(VDMA_BASEADDR + 0xA0, 480);//S2MM Vertical Size start an S2M
- Xil_DCacheFlush();
-
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_DMA_CTRL),
- 0x00000003); // enable circular mode
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_1),
- 0x08000000); // start address
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_2),
- 0x0A000000); // start address
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_START_3),
- 0x0D000000); // start address
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_FRMDLY_STRIDE),
- (horizontalActiveTime*4)); // h offset
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_H_SIZE),
- (horizontalActiveTime*4)); // h size
- Xil_Out32((VDMA_BASEADDR + AXI_VDMA_REG_V_SIZE),
- verticalActiveTime); // v size
- }
复制代码
分别配置好FPGA和ARM后,在串口终端按‘6’,选择640*480分辨率,看到如下所示的效果就成功了。大家可以更换TPG的输出类型,查看不同的效果。总结目前通过zynq实现了640*480的视频显示,大家可以调试下其它的分辨率。此外,串口终端发送数据的时候会断开,不知道大家是否会遇到这个BUG。
|