Introduction:
VGA (Video Graphics Array) is an analog interface used to display visual data on computer monitors. Till few years back, it was the most used display interface. It is now being slowly replaced by HDMI. The data can be displayed on monitors via VGA by using VGA Expansion Module and Saturn IO Breakout module with Styx Xilinx Zynq FPGA Module. In this tutorial, a simple project is implemented to display colours using VGA. Let’s get started!
Prerequisites:
To follow this article, you will need the following:
Hardware:
- Styx Xilinx Zynq FPGA Module
- Saturn IO Breakout Module
- VGA Expansion Module
- Xilinx Platform Cable USB II (optional)
- VGA cable and a compatible monitor
Software:
- Vivado (version 2017.3 or higher)
Step 1:
Open Vivado and select ‘Create Project’ in the “Quick Start” area. Click ‘Next’ in the “New Project” dialog window which opens.
Step 2:
In Project Name page, provide project name of your choice and choose the directory where you want to save the project.
Step 3:
Click Next without making any changes till you see the ‘Default Part’ tab and select ‘Styx’ from ‘Boards’ option. If you cannot see ‘Styx’ in the boards list then add BSP files from here to the following directory ..Vivado\2017.3\data\boards\board_files
Step 4:
Click Next and Finish to create the project. Then in the Sources tab, Left-click Design Sources and click ‘Add Sources’. It will open a new “Add Sources” window.
Step 5:
Click Next. In ‘Add or Create Design Sources’, select ‘Create File’, give ‘VGA.v’ as file name. Click OK and Finish.
Step 6:
In the ‘Define Module’ window, Click ‘OK’ followed by ‘Yes’ without making any changes.
Step 7:
Copy the following code in VGA.v and save the file.
VGA has five signals i.e. red
,green
, blue
,hsync
and vsync
. hsync
andvsync
are digital signals that are used for synchronization of signal timing with monitor whereasred
,green
and blue
signals are used as data to be displayed in the pixels on monitor. For 640*480 resolution, a mod-800 counter (hcount) is used to control horizontal timing and a mod-525 counter (vcount) is used to control vertical timing.
The image depicts the values of hsync
and vsync
signals corresponding to the value of hcount and vcount. The screen is scanned horizontally first, once it reaches the end, it goes to next line and again the same procedure is followed. When it reaches the last line, vcounter rolls back to starting point. The values of hcount and vcount are derived from VGA timing standard for 640×480@60Hz resolution.
The values of hcount and vcount denote the current pixel coordinates on screen. So in rtl code, the values to red
, green
and blue
signals are controlled by hcount and vcount.
For displaying various colours, logic is implemented to drive different values to red, green and blue pins of VGA for different pixel ranges. According to the combination of these 3 signals, different colours can be displayed. The digital values of red
, green
and blue
signals are converted into analog values by resistor ladder DAC in VGA Expansion Module.
The screen is divided into 8 columns and each column displays different colour according to the values given to red, green and blue signals. The columns are divided according to the value of hcount for vertical bars (vertical range remains same for each colour).
`timescale 1ns / 1ps module VGA( input clock, output reg [2:0 ] red, output reg [2:0 ] green, output reg [1:0 ] blue, output reg hsync, output reg vsync ); reg clock_50, clock_25; reg [9:0] hcount = 640; reg [9:0] vcount = 480; reg [9:0] next_hcount = 640; reg [9:0] next_vcount = 480; always @ (posedge clock) begin clock_50 =! clock_50; end always @ (posedge clock_50) begin clock_25 =! clock_25; end always @(posedge clock_25) begin if(hcount == 799) begin hcount <= 0; if(vcount == 524) vcount <= 0; else vcount <= vcount+1'b1; end else hcount <= hcount+1'b1; if (vcount >= 490 && vcount < 492) vsync <= 1'b0; else vsync <= 1'b1; if (hcount >= 656 && hcount < 752) hsync <= 1'b0; else hsync <= 1'b1; end always @ (posedge clock_25) begin if (hcount < 80 && vcount < 480) begin green <= 3'b111; blue <= 2'b11; red <= 3'b111; end else if (hcount < 160 && vcount < 480) begin green <= 3'b111; blue <= 2'b00; red <= 3'b111; end else if (hcount < 240 && vcount < 480) begin green <= 3'b111; blue <= 2'b11; red <= 3'b000; end else if (hcount < 320 && vcount < 480) begin green <= 3'b111; blue <= 2'b00; red <= 3'b000; end else if (hcount < 400 && vcount < 480) begin green <= 3'b000; blue <= 2'b11; red <= 3'b111; end else if (hcount < 480 && vcount < 480) begin green <= 3'b000; blue <= 2'b00; red <= 3'b111; end else if (hcount < 560 && vcount < 480) begin green <= 3'b000; blue <= 2'b11; red <= 3'b000; end else if (hcount < 640 && vcount < 480) begin green <= 3'b000; blue <= 2'b00; red <= 3'b000; end else begin green <= 3'b000; blue <= 2'b00; red <= 3'b000; end end endmodule
Step 8:
In sources tab, Left-Click ‘Constraints’ and click ‘Add Sources’.
Step 9:
Click ‘Create File’ and give ‘VGA’ as File name. Click ‘OK’ and ‘Finish’.
Step 10:
Copy the following constraints in your constrains file and save it
set_property -dict { PACKAGE_PIN "W18" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {red[0]}] set_property -dict { PACKAGE_PIN "R20" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {red[1]}] set_property -dict { PACKAGE_PIN "R21" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {red[2]}] set_property -dict { PACKAGE_PIN "Y15" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {green[0]}] set_property -dict { PACKAGE_PIN "P16" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {green[1]}] set_property -dict { PACKAGE_PIN "W17" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {green[2]}] set_property -dict { PACKAGE_PIN "Y16" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {blue[0]}] set_property -dict { PACKAGE_PIN "W16" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {blue[1]}] set_property -dict { PACKAGE_PIN "P15" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {hsync}] set_property -dict { PACKAGE_PIN "N15" IOSTANDARD LVCMOS33 SLEW FAST} [get_ports {vsync}] set_property -dict { PACKAGE_PIN "Y6" IOSTANDARD LVCMOS33 } [get_ports {clk}]
Step 11.
In Project Manager Tab, Click ‘Run Synthesis’. If Synthesis is successful, Click ‘Run Implementation’ and on successful implementation select ‘Generate Bitstream’.
Step 12:
Now, we will set up the hardware for programming the module. For this, connect Saturn IO Breakout Module to ‘Header P5’ of Styx. Also, Connect Header P1 of VGA Module to ‘Header P12’ of Saturn IO Breakout module and ‘Header P2’ of VGA Module to ‘Header P6’ of Saturn IO Breakout Module. Now connect power supply for Styx and Xilinx JTAG Cable.
Step 13:
Now click ‘Open Hardware Manager’ to program the FPGA.
Step 14:
Click on ‘Open target’ and ‘Auto Connect’. It will connect to the Module if the JTAG and power connections are correct.
Step 15:
Click on ‘Program Device’.
Step 16:
Click Program and observe the output. Connect a VGA cable to VGA Module and to the monitor where you want to see the output.
Step 17:
You will see the following output. You can change the code and observe different outputs!
So, that was it! Keep tinkering with the code to get different patterns on the display!