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

本编文章在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

【ZYNQ-7000开发之十】TGP+VDMA+HDMI搭建视频通路_第1张图片

点击Run Connection Automation,在弹出的对话框选择ALL,点击OK

点击ADD IP,添加一个TPG IP Core

双击刚刚添加的TPG,按照如图所示配置,这个主要为了简洁一些,去掉了一些不必要的功能

【ZYNQ-7000开发之十】TGP+VDMA+HDMI搭建视频通路_第2张图片

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

【ZYNQ-7000开发之十】TGP+VDMA+HDMI搭建视频通路_第3张图片

同理把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-7000开发之十】TGP+VDMA+HDMI搭建视频通路_第4张图片

总结

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

你可能感兴趣的:(FPGA,Zynq,ARM,嵌入式,AXI)