Showing results for 
Show  only  | Search instead for 
Did you mean: 

Video Series 23: Generate a video output on Pynq-Z2 HDMI out

6 17 7,971


In previous video series entries ( Video Series 19, Video Series 20 and Video Series 21), we have seen how to generate a video output on the HDMI connector of a Zynq®-7000 SoC ZC702 Evaluation Kit. The ZC702 board uses an ADV7511 HDMI transmitter for the Video interface, but not all solutions use an external device.

For example, on a PYNQ™-Z2 board (link to Pynq-z2 product page), the HDMI connector is directly connected to the Zynq serial I/Os (note that this is also different from the solution on the ZCU102/ZCU104 or ZCU106 boards which use Gigabit Transceivers). The same steps could be applied to other boards such as the Digilent Arty Z7, Arty A7 or Zybo Z7.

In this entry in the Video Series, we will show how to create a small design to generate a pattern on the HDMI output of the Pynq-Z2 board.

About the PYNQ-Z2

The PYNQ-Z2 is a low cost board based on Xilinx Zynq SoC, designed to support the PYNQ (Python Productivity for Zynq) framework and embedded systems development.




Tutorial – DVI output using TMDS I/Os on a PYNQ-Z2 board


Note: This tutorial is intended to be used only with Vivado Design Suite 2018.1 and only with the PYNQ-Z2 board.

Build the Vivado project

  1. Download the tutorial files and unzip the folder

  2. Download the Vivado board files for the PYNQ-Z2 from the TUL webpage:

  1. Extract the folder and copy the content to Xilinx\Vivado\2018.1\data\boards


  1. Open Vivado 2018.1

  2. Create a new project

  3. In the Default Part window, you should see the pynq-z2 in the list. Select the PYNQ-Z2 board for the project



  1. In Vivado, create a new block design (Select Flow > Create Block Design).

  2. In the Block Design (BD), add the ZYNQ7 Processing System IP.

  3. At the top of the BD click on Run Block Automation



  1. Make sure that Apply Board Preset is enabled and click OK



  1. Add a Video Test Pattern Generator (TPG) IP

  2. At the top of the BD, click on Run Connection Automation



  1. Double click on the ZYNQ7 processing system IP to configure it. In the Clock Configuration section, under PL Fabric Clocks, enable FCLK_CLK1 and set its clock frequency to 40MHz.



  1. Close the ZYNQ7 processing system IP configuration GUI by clicking OK

  2. Add a Video Timing Controller (VTC) IP and double click on it to open its configuration GUI

  3. In the Detection/Generation Tab select Include AXI4-Lite Interface and deselect Enable Detection


  1. In the Default/Constant tab, set the video mode to 800x600p

  2. Connect the clk input from the VTC to the FLCK_CLK1 output of the Zynq PS IP

  3. Add an AXI4-Stream to Video Out IP to the BD and double click on the IP to configure it. Change the clock mode to Independent



  1. In the Tcl console, source the script tcl from the tutorial folder (XVES_0023/src/tcl)

This script will connect all of the IPs properly for this design.

Now, we have nearly built the same design as in the Video Series 21 which was on the ZC702 board. On the ZC702 board, the HDMI interface was done using the external ADV7511 HDMI Transmitter. On the PYNQ-Z2 we need to take care of the video interface inside the Programmable Logic (PL).  We can do this using a free IP from Digilent called the rgb2dvi, which will generate DVI signals that we can use on the HDMI output connector of the PYNQ-Z2 board.

  1. Download and unzip the Vivado-library from the Digilent git repository (Select Clone or Download > Download ZIP):

  1. In Vivado, click Settings > IP > Repository, then add the path to the extracted Vivado-library folder to the IP Repositories list. Click Apply and OK



  1. In the BD, add the RGB to DVI Video Encoder (rgb2dvi) IP which should now appear in the IP catalog

  2. Double click on the rgb2dvi IP to configure it. Change the TMDS clock range to <80MHz (720p) and click OK


  1. Connect the RGB input of the rgb2dvi IP to the vid_io_out output of the AXI4-Stream to Video Out IP

  2. Connect the PixelClk input of the rgb2dvi IP to the FCLK_CLK1 output of the Zynq processor

  3. Extend the TMDS interface of the rgb2dvi IP and make all of the signals (TMDS_Clk_p/n and TMDS_Data_p/n) external to the BD (right click in the pin and click Make External)



  1. Validate the BD. Validation should be successful. Save the BD

  2. In the sources window, right click on the BD and click Generate Output Products



  1. When the generation completes, right-click again on the BD and click Create HDL Wrapper

  2. Download the Master XDC file for the PYNQ-Z2 from the TUL webpage:

  1. Extract the folder and add the XDC file to the project (File > Add Sources > Add or Create constraints)

  2. Double click on the XDC file in the source window to open it in the text editor. Find the lines corresponding to the HDMI TX and uncomment the following lines (by removing the “#” symbol at the start of the line):
set_property -dict { PACKAGE_PIN L17   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_clk_n }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n
set_property -dict { PACKAGE_PIN L16   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_clk_p }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p
set_property -dict { PACKAGE_PIN K18   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_n[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0]
set_property -dict { PACKAGE_PIN K17   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_p[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0]
set_property -dict { PACKAGE_PIN J19   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_n[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1]
set_property -dict { PACKAGE_PIN K19   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_p[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1]
set_property -dict { PACKAGE_PIN H18   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_n[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2]
set_property -dict { PACKAGE_PIN J18   IOSTANDARD TMDS_33  } [get_ports { hdmi_tx_d_p[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2]
  1. Change the name of the ports to match the names from your BD. By default it should be as follows:


set_property -dict { PACKAGE_PIN L17   IOSTANDARD TMDS_33  } [get_ports { TMDS_Clk_n_0 }]; #IO_L11N_T1_SRCC_35 Sch=hdmi_tx_clk_n
set_property -dict { PACKAGE_PIN L16   IOSTANDARD TMDS_33  } [get_ports { TMDS_Clk_p_0 }]; #IO_L11P_T1_SRCC_35 Sch=hdmi_tx_clk_p
set_property -dict { PACKAGE_PIN K18   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_n_0[0] }]; #IO_L12N_T1_MRCC_35 Sch=hdmi_tx_d_n[0]
set_property -dict { PACKAGE_PIN K17   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_p_0[0] }]; #IO_L12P_T1_MRCC_35 Sch=hdmi_tx_d_p[0]
set_property -dict { PACKAGE_PIN J19   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_n_0[1] }]; #IO_L10N_T1_AD11N_35 Sch=hdmi_tx_d_n[1]
set_property -dict { PACKAGE_PIN K19   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_p_0[1] }]; #IO_L10P_T1_AD11P_35 Sch=hdmi_tx_d_p[1]
set_property -dict { PACKAGE_PIN H18   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_n_0[2] }]; #IO_L14N_T2_AD4N_SRCC_35 Sch=hdmi_tx_d_n[2]
set_property -dict { PACKAGE_PIN J18   IOSTANDARD TMDS_33  } [get_ports { TMDS_Data_p_0[2] }]; #IO_L14P_T2_AD4P_SRCC_35 Sch=hdmi_tx_d_p[2]
  1. Save the XDC file

  2. Run Synthesis and Implementation, and Generate the bitstream

  3. Export the hardware to SDK, including the bitstream (File > Export > Export Hardware)


 Create the Software Application

  1. Launch SDK from Vivado (File > Launch SDK)

  2. In SDK, create a new application project (File > New application project) and select the Hello World template



  1. Open the helloworld.c file in the SDK text editor



  1. Edit the file as follows (refer to Entry 21 of the Video Series for more detail on the code)


include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xv_tpg.h"

XV_tpg tpg_inst;
int Status;

int main()

    print("Hello World\n\r");

    /* TPG Initialization */
    Status = XV_tpg_Initialize(&tpg_inst, XPAR_V_TPG_0_DEVICE_ID);
    if(Status!= XST_SUCCESS)
    	xil_printf("TPG configuration failed\r\n");

    // Set Resolution to 800x600
    XV_tpg_Set_height(&tpg_inst, 600);
    XV_tpg_Set_width(&tpg_inst, 800);

    // Set Color Space to RGB
    XV_tpg_Set_colorFormat(&tpg_inst, 0x0);

    //Set pattern to color bar
    XV_tpg_Set_bckgndId(&tpg_inst, XTPG_BKGND_COLOR_BARS);

    //Start the TPG
    xil_printf("TPG started!\r\n");
    /* End of TPG code*/

    return 0;


  1. Save the file

  2. Connect the Pynq-Z2 to your computer using a micro USB cable and set the boot mode jumper to JTAG. Connect the PYNQ-Z2 to a HDMI monitor using the HDMI Out connector. Power on the PYNQ-Z2 board



  1. Open a UART terminal and configure it for the correct COM port for the PYNQ-Z2




  1. Program the FPGA and launch the application

  2. You should see a pattern displayed on the monitor
Tags (3)

Can I use Pynq's Python Overlay to control the design ?

Following is my python code.

from pynq import Overlay
ov = Overlay("tpgHdmi.bit")
tpg = ov.v_tpg_0
vtc = ov.v_tc_0

vtc.write(0x00,0x01) <---- Need to add this to make it work.



Hi @tzechienchu ,

Yes, I assume you could use this design as overlay and then use it from python

I have done all the stuff but nothing happened on my monitor. I am using 2018.3. When i hit the validate design button i receive an error that states vtc ap_clk is not connected. Thus i have run connection automation for this block even it is not stated in the guidelines. Anıl,

Hi @anilcelebi ,

Remember the note at the top of the tutorial "Note: This tutorial is intended to be used only with Vivado Design Suite 2018.1".

Please use 2018.1 as this is the only version I have tested

Hi @florentw, I know your note but since i always use the latest release of any Vivado in my class (all of the students are using this release also) i wanted to test it with 2018.3. It is sad to experience such incompatibilities even between very close releases. Regards,

Hi @anilcelebi ,

The way to move between releases is with a full project. When you have tcl script you need to be careful with the different version of the IP. Here this might be my custom script connect_nets_XVES0023.tcl which is missing an update on the vtc IP. But I cannot create a script for every version of vivado.

If you build the project on vivado 2018.1 and then move the full project to 2018.3, then it should be easier.




Hi @florentw,

I will try. Regards,



Hi @florentw 

I configured it according to your tutorial. But the test pattern on my projector does not look right. 


I have checked it many times, the clock and configuration are correct, Vivado also did not report any error. Do you have any ideas? Thanks.

Kind regards,



Hi @garytavish ,

This looks like a mismatch between the clock, video timing and tpg resolution configuration.

Could you recheck:

> The clock configuration from the clocking wizard

> The configuration of the VTC (AXI4-Lite is not selected and resolution is 800x600)

> and you are using the exact same code as in the video series


Hi @florentw 

I connected the board to a computer monitor and it is working now. The projector I tested previously used Toshiba's bridge chip TC358779. I haven't looked carefully yet, but it may be this chip requires HDMI control data. Anyway, thank you for help.

Kind regards,




I am doing this on pynq board . After connecting the rgb2dvi IP, the validate design gives the warning .

Capture.PNGThe generate bitstream further gives this error Capture1.PNG

Is there anything I am doing wrong?



Are you using 2018.1 as mentioned in th tutorial?

It also seems that you are not fully following the steps. For example, I am not setting the interface TMDS as external interface but the individual signals.

I guees you are also missing the configuration of the rgb2hdmi (<80MHz)



I sorted the problem out. I added the rgb2dvi and forgot to add the interface. The video was displayed as expected. Thank you



I have followed all the steps using vivado 2018.1 as mentioned but nothing happened on my monitor. 

However I am using a monitor with a only VGA-input using a vga to hdmi  cable on my pynq-Z2 board. Could this be an issue? 





HI @EmilyDM 

This is hard to say but that might be the reason because I only tried with HDMI monitor.

One way you can confirm this is by adding an ILA (see link and link) to capture the locked and status signal from the AXI4-Stream to video out and the output from the rgb2DVI.

If you need assistance with that please create a topic on the forums as this might not be suitable as comments for the blog




A few comments on this (I was able to get this to run on 2018.3):

- It is implied, but not actually stated, that you need to add the Video Test Pattern generator. This will allow the tcl script to run.

- I had to run connection automation to get everything to actually function. You will get a critical warning of:

[BD 41-1343] Reset pin /v_tc_0/resetn (associated clock /v_tc_0/clk) is connected to reset source /rst_ps7_0_100M/peripheral_aresetn (synchronous to clock source /processing_system7_0/FCLK_CLK0).
This may prevent design from meeting timing. Please add Processor System Reset module to create a reset that is synchronous to the associated clock source /processing_system7_0/FCLK_CLK1.

I however could not figure this out, and it did not seem to affect the design.

I had to add this to the constraints file:

set_property DONT_TOUCH true [get_cells design_1_i/v_tpg_0/inst/v_tpg_CTRL_s_axi_U/FSM_onehot_wstate[1]_i_1]

Or else the implimentation will not work.

EmilieDM: This set up will NOT work with an VGA. The HDMI is outputiing a digital signal that is imcompatible with VGA. In theory, you can replace to "RGBtoDVI" with a simliar RGBto VGA design and hook it up to the right pins, but that excerise is left up to the reader.


Hi @Chris_T 

Adding the Test Pattern Generator is mentioned. Refer to step 11

For the second comment, I guess there is a miss in the steps. You need to add a processor system reset connected to FCLK1 so you can connect the reset output to the VTC