08. Anlu SparkRoad Domestic FPGA Evaluation [Learning] VGA Display
[Copy link]
This post was last edited by 1nnocent on 2022-7-30 09:19
This routine is mainly divided into three modules, which are used to realize the VGA drive display function. The top module instantiates the VGA clock module, VGA driver module and VGA display test module.
The vga clock module generates the VGA drive clock by calling the PLL IP core. It should be noted that different resolutions require different drive clocks. The drive clock corresponding to each resolution and the line and field signal information can be found on the VESA official website. Here is the " VESA and Computer Display Monitor Timing (DMT) Industry Standards and Guidelines ":
VESA-DMT-1.12.pdf
(747.23 KB, downloads: 3)
The vga driver module is used to drive the VGA display. Users can change the timing parameters of VGA resolution (here the timing parameters refer to the line field signal, where the line signal mainly includes: line display synchronization signal, line display front edge, line display valid data, line display back edge , where the line display valid data is the specific value of the resolution, such as 1920; field signal includes: field display synchronization signal, field display front edge, field display valid data, field display back edge , where the field display valid data is the specific value of the resolution, such as 1080; line synchronization signal uses specific pixel points as the basic unit [for example, the line display valid data has 1920 pixels], and field synchronization signal uses field synchronization signal as the basic unit [for example, the field display valid data has 1080 signals, here the basic unit is line position, a line signal contains not only valid data, but also front edge, back edge, etc., which is a complete line signal]) to realize different resolutions. The following figure can help you understand (the network picture found on the Internet):
I have used an oscilloscope to capture the line and field signals before, and I have posted them here for easy understanding (Figure 1 is the sum of the field signal [red], the line signal [yellow], and the enable signal [blue]; Figure 2 is the line signal and the enable signal. Figure 2 shows the display leading edge, valid data, that is, the blue enable signal, the display trailing edge, and the line synchronization signal):
The vga display module is used to test the VGA display.
Now analyze the code: the input interface is: system clock clk_24m, external button reset rst_n; the output interface is: pixel clock vga_clk (used to drive the display frequency), line synchronization signal vga_hs, field synchronization signal vga_hs, output data enable vga_de, red data channel vga_r, green data channel vga_g, blue data channel vga_b.
First is the PLL module. The PLL input clock is the system clock 24MHz, which generates a 108MHz clock to drive the display. By looking up the above-mentioned "VESA and Computer Display Monitor Timing (DMT) Industry Standards and Guidelines", we can know that this frequency is used to drive 1280x1024@60Hz resolution.
Next is the display driver module (Driver.v), which is used to generate line and field signals. 1. The module defines hcnt to count the horizontal synchronization signal. After the resolution counts 1688 times, hcnt is cleared and counted again. 2. When hcnt counts H_SYNC (112) times, the horizontal synchronization signal is generated, and lcd_hs is pulled high. 3. Define vcnt to count the field synchronization signal. After counting 1066 times, vcnt is cleared and counted again. When vcnt is self-incremented, it must also meet the requirement that the horizontal signal counts 1688 times. 4. When vcnt counts V_SYNC (3) times, the field synchronization signal is generated and lcd_vs is pulled high. 5. When hcnt meets the valid data interval of the line (hcnt >= H_SYNC + H_BACK - H_AHEAD && hcnt < H_SYNC + H_BACK + H_DISP - H_AHEAD), and vcnt meets the valid data interval of the field (vcnt >= V_SYNC + V_BACK && vcnt < V_SYNC + V_BACK + V_DISP) pulls up the data enable signal lcd_en, and then sends pixel data to the display.
`timescale 1ns/1ns
/* VGA参数配置表
************ clk H_SYNC H_BACK H_DISP H_FRONT H_TOTAL V_SYNC V_BACK V_DISP V_FRONT V_TOTAL *
640x480@60Hz 25.2MHz 96 48 640 16 800 2 33 480 10 525 *
800x600@60Hz 40MHz 128 88 800 40 1056 4 23 600 1 628 *
1024x768@60Hz 65MHz 136 160 1024 24 1344 6 29 768 3 806 *
1280x720@60Hz 74.25MHz 40 220 1280 110 1650 5 20 720 5 750 *
1280x1024@60Hz 108MHz 112 248 1280 48 1688 3 38 1024 1 1066 *
1920x1080@60Hz 148.5MHz 44 148 1920 88 2200 5 36 1080 4 1125 *
*/
module Driver
#(
parameter H_SYNC = 112 , // 行同步信号时间
parameter H_BACK = 248 , // 行消隐后肩时间
parameter H_DISP = 1280 , // 行数据有效时间
parameter H_FRONT = 48 , // 行消隐前肩时间
parameter H_TOTAL = 1688, // 行扫描总时间
parameter V_SYNC = 3 , // 列同步信号时间
parameter V_BACK = 38 , // 列消隐后肩时间
parameter V_DISP = 1024 , // 列数据有效时间
parameter V_FRONT = 1 , // 列消隐前肩时间
parameter V_TOTAL = 1066 // 列扫描总时间
)
(
input wire clk, //VGA clock
input wire rst_n, //sync reset
input wire [23:0] lcd_data, //lcd data
//lcd interface
output wire lcd_dclk, //lcd pixel clock
output wire lcd_hs, //lcd horizontal sync
output wire lcd_vs, //lcd vertical sync
output wire lcd_en, //lcd display enable
output wire [23:0] lcd_rgb, //lcd display data
//user interface
output wire [11:0] lcd_xpos, //lcd horizontal coordinate
output wire [11:0] lcd_ypos //lcd vertical coordinate
);
localparam H_AHEAD = 12'd1;
reg [11:0] hcnt;
reg [11:0] vcnt;
wire lcd_request;
/*******************************************
SYNC--BACK--DISP--FRONT
*******************************************/
//h_sync counter & generator
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
hcnt <= 12'd0;
else
begin
if(hcnt < H_TOTAL - 1'b1) //line over
hcnt <= hcnt + 1'b1;
else
hcnt <= 12'd0;
end
end
assign lcd_hs = (hcnt <= H_SYNC - 1'b1) ? 1'b0 : 1'b1; // line over flag
//v_sync counter & generator
always@(posedge clk or negedge rst_n)
begin
if (!rst_n)
vcnt <= 12'b0;
else if(hcnt == H_TOTAL - 1'b1) //line over
begin
if(vcnt == V_TOTAL - 1'b1) //frame over
vcnt <= 12'd0;
else
vcnt <= vcnt + 1'b1;
end
end
assign lcd_vs = (vcnt <= V_SYNC - 1'b1) ? 1'b0 : 1'b1; // frame over flag
// LED clock
assign lcd_dclk = ~clk;
// Control Display
assign lcd_en = (hcnt >= H_SYNC + H_BACK && hcnt < H_SYNC + H_BACK + H_DISP) &&
(vcnt >= V_SYNC + V_BACK && vcnt < V_SYNC + V_BACK + V_DISP)
? 1'b1 : 1'b0; // Display Enable Signal
assign lcd_rgb = lcd_en ? lcd_data : 24'h000000;
//ahead x clock
assign lcd_request = (hcnt >= H_SYNC + H_BACK - H_AHEAD && hcnt < H_SYNC + H_BACK + H_DISP - H_AHEAD) &&
(vcnt >= V_SYNC + V_BACK && vcnt < V_SYNC + V_BACK + V_DISP)
? 1'b1 : 1'b0;
//lcd xpos & ypos
assign lcd_xpos = lcd_request ? (hcnt - (H_SYNC + H_BACK - H_AHEAD)) : 12'd0;
assign lcd_ypos = lcd_request ? (vcnt - (V_SYNC + V_BACK)) : 12'd0;
endmodule
The last one is the display module (Display.v): This module outputs pixel data to the display according to the coordinate rule while the data is valid. A total of four playback modes are defined here.
`timescale 1ns/1ns
// Define colors RGB--8|8|8
`define RED 24'hFF0000
`define GREEN 24'h00FF00
`define BLUE 24'h0000FF
`define WHITE 24'hFFFFFF
`define BLACK 24'h000000
`define YELLOW 24'hFFFF00
`define CYAN 24'hFF00FF
`define ROYAL 24'h00FFFF
// Define Display Mode
// `define VGA_HORIZONTAL_COLOR // 八种颜色横彩条
// `define VGA_VERTICAL_COLOR // 八种颜色竖彩条
// `define VGA_GRAY_GRAPH // 红色彩条2x5
`define VGA_GRAFTAL_GRAPH // lcd_data <= lcd_xpos * lcd_ypos;
module Display
#(
parameter H_DISP = 1280,
parameter V_DISP = 1024
)
(
input wire clk,
input wire rst_n,
input wire [11:0] lcd_xpos, //lcd horizontal coordinate
input wire [11:0] lcd_ypos, //lcd vertical coordinate
output reg [23:0] lcd_data //lcd data
);
`ifdef VGA_HORIZONTAL_COLOR
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
lcd_data <= 24'h0;
else
begin
if (lcd_ypos >= 0 && lcd_ypos < (V_DISP/8)*1)
lcd_data <= `RED;
else if(lcd_ypos >= (V_DISP/8)*1 && lcd_ypos < (V_DISP/8)*2)
lcd_data <= `GREEN;
else if(lcd_ypos >= (V_DISP/8)*2 && lcd_ypos < (V_DISP/8)*3)
lcd_data <= `BLUE;
else if(lcd_ypos >= (V_DISP/8)*3 && lcd_ypos < (V_DISP/8)*4)
lcd_data <= `WHITE;
else if(lcd_ypos >= (V_DISP/8)*4 && lcd_ypos < (V_DISP/8)*5)
lcd_data <= `BLACK;
else if(lcd_ypos >= (V_DISP/8)*5 && lcd_ypos < (V_DISP/8)*6)
lcd_data <= `YELLOW;
else if(lcd_ypos >= (V_DISP/8)*6 && lcd_ypos < (V_DISP/8)*7)
lcd_data <= `CYAN;
else
lcd_data <= `ROYAL;
end
end
`endif
`ifdef VGA_VERTICAL_COLOR
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
lcd_data <= 24'h0;
else
begin
if (lcd_xpos >= 0 && lcd_xpos < (H_DISP/8)*1)
lcd_data <= `RED;
else if(lcd_xpos >= (H_DISP/8)*1 && lcd_xpos < (H_DISP/8)*2)
lcd_data <= `GREEN;
else if(lcd_xpos >= (H_DISP/8)*2 && lcd_xpos < (H_DISP/8)*3)
lcd_data <= `BLUE;
else if(lcd_xpos >= (H_DISP/8)*3 && lcd_xpos < (H_DISP/8)*4)
lcd_data <= `WHITE;
else if(lcd_xpos >= (H_DISP/8)*4 && lcd_xpos < (H_DISP/8)*5)
lcd_data <= `BLACK;
else if(lcd_xpos >= (H_DISP/8)*5 && lcd_xpos < (H_DISP/8)*6)
lcd_data <= `YELLOW;
else if(lcd_xpos >= (H_DISP/8)*6 && lcd_xpos < (H_DISP/8)*7)
lcd_data <= `CYAN;
else
lcd_data <= `ROYAL;
end
end
`endif
`ifdef VGA_GRAFTAL_GRAPH
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
lcd_data <= 24'h0;
else
lcd_data <= lcd_xpos * lcd_ypos;
end
`endif
`ifdef VGA_GRAY_GRAPH
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
lcd_data <= 24'h0;
else
begin
if(lcd_ypos < V_DISP/2)
lcd_data <= {lcd_ypos[7:0], lcd_ypos[7:0], lcd_ypos[7:0]};
else
lcd_data <= {lcd_xpos[7:0], lcd_xpos[7:0], lcd_xpos[7:0]};
end
end
`endif
endmodule
The following are four display effects. I will post a practical article on VGA display later. The VGA output display mode is controlled by buttons (four types are shown below), and another button controls the resolution of VGA output:
|