Introduction

In this tutorial we will create a VGA controller to display
an image on a monitor using the ZedBoard and Xilinx Vivado 2017.2 (but it
should work with any other release of Xilinx Vivado). The controller will be
coded using VHDL.

Introduction to video display

What is an image?

An image is an array of pixel (for picture (x)
elements). For a Black and white image, a pixel is defined by one value
representing the luminosity. If this value is high, the pixel will be bright
(white) and if it is low, the pixel will be dark (black). For a colour image,
in most cases the pixel is composed of three values: its level of Red, its
level of Green and its level of Blue (this is why we usually call colour images
RGB images (for Red Green and Blue)). The combination of these 3 values will
give the final colour of the pixel. For example, in a lot a software tools, you
can create customs colours by setting the value of Red, Green and Blue. As
shown in the Figure 1, if you select the maximum value for Green and Blue (255
in this case) and 0 for Red, you obtain the colour cyan.

Figure 1 - Example of custom colour definition tool

To display an image on a monitor, the image is sent line per
line, starting with the top one and each line is sent pixel per pixel, starting
with the left one.

For example, the Figure 2 shows how a 3x3 pixels image could
be sent to a monitor using 3 data lanes (Red Green Blue).

Figure 2 - Example of how an image is sent to a monitor

Introduction to VGA on the ZedBoard

A colour VGA video signal is composed by 5 different signals:
two synchronization signals (HSYNC and VSYNC) and three analog colour signals
(R, G, B).

The Figure 3shows an example of a
video frame along with the synchronization signals. During the Active Video
period, the data are sent to the monitors. During the Horizontal and Vertical
blanking, no data are sent and after a defined period (which depends on the
output video format) synchronisation pulses (HSYNC and VSYNC) are sent to the
monitor. These pulses can be positives or negatives (depending on the output
video format). The periods before a synchronisation signal and after a
synchronisation signal are called respectively Front Porch and Back Porch.

Figure 4 - VGA connector schematic on the ZedBoard

In VGA, the colour data are voltage value between +0V and
+3.3V. On the ZedBoard, these values are sent using a 4-bit input Digital to
Analog converter as shown on the Figure 4.

Figure 5 - VGA Connector on the ZedBoard

The Figure 5 shows how the signals are connected to the VGA
connector of the ZedBoard. From the ZedBoard user guide (link)
we can see that the red signal is connected to the ports V20,
U20, V19 and V18 of the FPGA, the green signal is connected to AB22, AA22, AB21
and AA21, the blue signal is connected to Y21, Y20, AB20 and AB19, the HSYNC is
connected to AA19 and VSYNC is connected to Y19.

Timing information (1680 x 1050 @60Hz)

For this tutorial, we will output a VGA signal with the
output format 1680 x 1050 @60Hz. In this format the pixel are send with a
147.14 MHz frequency.

Horizontal timing

With the output format 1680 x 1050@60Hz, the size of the
active line is 1680 pixels, the horizontal synchronisation signal, which is
negative, is sent after 104 clock signals in the blanking period, and last 184
clock signals and there are 288 clock signals between the horizontal
synchronisation signal and a new active line. The Table 1 summarise the
horizontal timing.

Line Part

Clock Signals

Time [µs]

Visible area

1680

11.417697431018

Front porch

104

0.70680984096779

Sync pulse

184

1.2505097186353

Back porch

288

1.9573195596031

Whole line

2256

15.332336550224

Table
1 - 1680 x 1050 @ 60 Hz Horizontal timing

Vertical Timing

With the output format 1680 x 1050@60Hz, the size of the
active frame is 1050 lines, the vertical synchronisation signal, which is
positive, is sent after a period corresponding to 1 line signals in the
blanking period, and last for a period of 3 lines. This synchronisation signals
is followed by a period corresponding to 33 lines before a new active frame.
The Table 2 summarise the vertical timing.

Frame Part

Lines

Time [ms]

Visible area

1050

16.098953377735

Front porch

1

0.015332336550224

Sync pulse

3

0.045997009650673

Back porch

33

0.5059671061574

Whole frame

1087

16.666249830094

Table 2 - 1680 x 1050 @ 60 Hz Vertical timing

Clocking on the ZedBoard

According to the ZedBoard Hardware User’s Guide: “An
on-board 100 MHz oscillator, IC17, Fox 767-100-136, supplies the PL subsystem
clock input on bank 13, pin Y9”. As we need a 147.14 MHz frequency clock we
will use the clocking wizard to generate the needed clock using an MMCM.

Create the timing controller

Open Vivado 2017.2 and create a new RTL project targeting
the ZedBoard.

Firstly, we have a 100MHz clock in input but we need to
convert it to a 147.14MHz (pixel clock). To do this, we will use the Xilinx IP
Clocking Wizard. In the flow navigator, click on “IP Catalog”. In the
search bar, enter “clocking” and then double click on the “Clocking
Wizard” IP to add it to the project.

Figure 6 - Add a Clocking Wizard IP to the project

A GUI window should appear to customize the IP. The
component name for this IP should be clk_wiz_0. In the page “Clocking
Option”, check that the Primary Input clock frequency is set to 100MHz.

Figure 7 - Clocking Wizard GUI - Clocking Options

In the “Output Clocks” page, set 147.14MHz for the
requested frequency for clk_out1 and disable “reset” and “locked”
in the “Enable Optional Inputs / Outputs for MMCP/PLL” and then click
OK.

Figure 8 - Clocking Wizard GUI - Output Clocks

A “Generate Outputs Products” window should appear.
Select “Out of context per IP” and click “Generate”.

Figure 9 - Generate Outputs Products Window

Add the VDHL files hdl/TOP_LEVEL, hdl/VGA_timing_controller.vhd
and hdl/reset_synchronizer.vhd to the project. You should see the hierarchy
showed in the Figure 10 in the Sources window.

Figure 10 - Project Hierarchy

The file reset_synchronizer.vhd contains a simple reset
synchronizer, the file VGA_timing_controller.vhd contains a code used to
generate the horizontal and vertical pulses and a signal which indicates when
the timing is in the “Active Video” part. The file TOP_LEVEL outputs
values for the signals R, G and B when the video is active.

Try the project on board

Add the constraint file constr/phys_const.xdc to the project
and generate the Bitstream.

When the Bitstream has been generated, open Hardware Manger
in Vivado and program the FPGA. Connect the ZedBoard to a monitor. Make sure
that the SW0 (used as reset) is on position ‘0’. You should see a green screen
on the monitor. If this is not working, try the Bitstream from the downloaded
folder.