Display output#

We will use the FPGA to generate graphics on an HDMI display.

Steps:

  1. Create a project

  2. Clone hdmi-util/hdmi and add all the Systemverilog files under src/ to your project

  3. Add board’s constraint file. This example uses the standard constraint file of the Boolean board.

  4. Use Clocking Wizard from the IP Catalog to generate an clock generator with the following properties. Do not use block design.:

    1. name the module hdmi_pll

    2. select MMCM (PLL cannot generate the clock frequency that we require)

    3. clock input: 100 MHz named clk

    4. pixel clock: 74.25 MHz named clk_pixel

    5. 5x pixel clock: 371.25 MHz named clk_pixel_x5

  5. Use the template top.sv below and synthesize. Connect the board to a monitor with an HDMI cable. It should show a white screen.

Problems:

  1. Analyze top.sv. What are the clk_pixel, tmds, hdmi_tx_{p,n}, c{x,y} for? What does the parameter VIDEO_ID_CODE(4) do?

  2. Display only green.

  3. Display three vertical stripes with red, green and blue.

  4. Display a left to right red gradient, leftmost side should be black and rightmost side should be red.

  5. Display a white ball and make it move with a constant velocity. It should bounce back at the edges.

Project files#

module top (
	input clk,
	output [2:0] hdmi_tx_p, hdmi_tx_n,
	output hdmi_clk_p, hdmi_clk_n
);

logic clk_pixel_x5, clk_pixel, tmds_clock;
logic [23:0] rgb;
logic [2:0] tmds;
logic [10:0] cx;
logic [9:0] cy;

hdmi #(
	.DVI_OUTPUT(1),
	.VIDEO_ID_CODE(4),
	.VIDEO_REFRESH_RATE(60.0)
) hdmi(
	.clk_pixel_x5, .clk_pixel, .tmds_clock, .rgb, .tmds, .cx, .cy);

hdmi_pll hdmi_pll(.clk, .clk_pixel, .clk_pixel_x5);

localparam COLOR_CHANNEL_COUNT = 3;
genvar i;
generate
	for (i = 0; i < COLOR_CHANNEL_COUNT; ++i) begin: obufds_gen
		OBUFDS obufds_hdmi_tx(.I(tmds[i]), .O(hdmi_tx_p[i]), .OB(hdmi_tx_n[i]));
	end
	OBUFDS obufds_hdmi_clk(.I(tmds_clock), .O(hdmi_clk_p), .OB(hdmi_clk_n));
endgenerate

assign rgb = '1;

endmodule
from PIL import Image
img = Image.open('image.jpg')
img.thumbnail((320, 240))
with open('image.memh', 'w') as f:
    f.writelines(
        hex(
            (pixel[0]>>4 <<8) + (pixel[1]>>4 <<4) + (pixel[2]>>4)
        )[2:] + '\n'
        for pixel in img.getdata()
    )
include vsyn.mk

# hdmi should be made before vivctrl.tcl to account for hdmi/src/*.sv
# boolean.xdc for *.xdc
vivctrl.tcl: |hdmi boolean.xdc
hdmi: 
	git clone https://github.com/hdl-util/hdmi
	@echo
	@echo hdmi project cloned. Exiting with error. Rerun make!
	@exit 1
	@# Otherwise $(wildcard ...) in the makefile does not work

out/post_syn.dcp: image.memh

image.memh: image.jpg
	python image2memh.py

hdmi_pll/hdmi_pll.v hdmi_pll/hdmi_pll_clk_wiz.v &: hdmi_pll-create.tcl
	vivado -tempDir /tmp -nojournal -nolog -mode batch -source hdmi_pll-create.tcl
	
image.jpg:
	curl 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Siebenpunkt-Marienk%C3%A4fer_%28Coccinella_septempunctata%29_auf_Bl%C3%BCte_im_FFH-Gebiet_%22Viernheimer_Waldheide_und_angrenzende_Fl%C3%A4chen%22.jpg/1280px-Siebenpunkt-Marienk%C3%A4fer_%28Coccinella_septempunctata%29_auf_Bl%C3%BCte_im_FFH-Gebiet_%22Viernheimer_Waldheide_und_angrenzende_Fl%C3%A4chen%22.jpg' -o $@

clean::
	$(RM) -r hdmi hdmi_pll
	$(RM) image.{jpg,memh}
create_project -in_memory -part xc7s50csga324-1
create_ip -name clk_wiz -dir . -module_name hdmi_pll
set_property -dict [list \
  CONFIG.PRIMITIVE {MMCM} \
  CONFIG.PRIMARY_PORT {clk} \
  CONFIG.CLKOUT1_USED {true} \
  CONFIG.CLKOUT2_USED {true} \
  CONFIG.CLK_OUT1_PORT {clk_pixel} \
  CONFIG.CLK_OUT2_PORT {clk_pixel_x5} \
  CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {74.25} \
  CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {371.25} \
] [get_ips hdmi_pll]
generate_target synthesis [get_ips hdmi_pll]