Hello, great Xia. Welcome to the FPGA technology Jianghu. The Jianghu is so big. It's fate to meet each other.
Today, we bring you the design of VGA/LCD display controller based on FPGA. Due to the long length, it is divided into three parts. Today, I will bring the third and second parts, the simulation, testing and summary of the program. I don't say much and deliver the goods.
The first two articles and articles related to VGA display pushed before. Here is a hyperlink for your reference.
Design of VGA/LCD display controller based on FPGA (Part 1)
Design of VGA/LCD display controller based on FPGA (Part 2)
Source code series: VGA driver design based on FPGA (attached source project)
Reading guide
VGA (Video Graphics Array), namely video graphics array, is a video transmission standard using analog signals launched by IBM with PS/2 machine (personal system 2) in 1987. This standard is very outdated for today's personal computer market. However, at that time, it had the advantages of high resolution, fast display speed and rich colors. It was widely used in the field of color display and was a low standard jointly supported by many manufacturers.
LCD (short for Liquid Crystal Display) Liquid Crystal Display. The structure of LCD is to place liquid crystal cells in two parallel glass substrates, TFT (thin film transistor) is set on the lower substrate glass, and color filter is set on the upper substrate glass. The rotation direction of liquid crystal molecules is controlled through the change of signal and voltage on TFT, so as to control the emission of polarized light at each pixel and achieve the purpose of display. According to different backlights, LCD can be divided into CCFL display and LED display. LCD has replaced CRT as the mainstream, and the price has dropped a lot and has been fully popularized.
In the previous article, we introduced how to obtain and process the video signal provided by the camera. In practical application, we also need to display the processed signal on the display. This process is opposite to the process in signal processing. The digital signal is composed of signals meeting the requirements of timing and format according to the system of TV signal, and various synchronization signals for control are added. This paper will implement an example of VGA/LCD display controller through FPGA, and introduce the implementation process in detail.
Summary of the third part: this part will introduce the simulation, testing and summary of the program.
4, Simulation and test of program
In order to check whether the program realizes the preset function, it is necessary to write a simulation program. The main codes of the simulation program are as follows:
5, Summarymodule test; //register reg clk; reg rst; //parameter parameter LINE_FIFO_AWIDTH = 7; //wire statement wire int; wire [31:0] wb_addr_o; wire [31:0] wb_data_i; wire [31:0] wb_data_o; wire [3:0] wb_sel_o; wire wb_we_o; wire wb_stb_o; wire wb_cyc_o; wire [2:0] wb_cti_o; wire [1:0] wb_bte_o; wire wb_ack_i; wire wb_err_i; wire [31:0] wb_addr_i; wire [31:0] wbm_data_i; wire [3:0] wb_sel_i; wire wb_we_i; wire wb_stb_i; wire wb_cyc_i; wire wb_ack_o; wire wb_rty_o; wire wb_err_o; reg pclk_i; wire pclk; wire hsync; wire vsync; wire csync; wire blanc; wire [7:0] red; wire [7:0] green; wire [7:0] blue; wire dvi_pclk_p_o; wire dvi_pclk_m_o; wire dvi_hsync_o; wire dvi_vsync_o; wire dvi_de_o; wire [11:0] dvi_d_o; wire vga_stb_i; wire clut_stb_i; reg scen; // Test program variables integer wd_cnt; integer error_cnt; reg [31:0] data; reg [31:0] pattern; reg int_warn; integer n; integer mode; reg [7:0] thsync, thgdel; reg [15:0] thgate, thlen; reg [7:0] tvsync, tvgdel; reg [15:0] tvgate, tvlen; reg hpol; reg vpol; reg cpol; reg bpol; integer p, l; reg [31:0] pn; reg [31:0] pra, paa, tmp; reg [23:0] pd; reg [1:0] cd; reg pc; reg [31:0] vbase; reg [31:0] cbase; reg [31:0] vbara; reg [31:0] vbarb; reg [7:0] bank; // Constant definition `define CTRL 32'h0000_0000 `define STAT 32'h0000_0004 `define HTIM 32'h0000_0008 `define VTIM 32'h0000_000c `define HVLEN 32'h0000_0010 `define VBARA 32'h0000_0014 `define VBARB 32'h0000_0018 `define USE_VC 1 parameter PCLK_C = 20; //Test content initial begin $timeformat (-9, 1, " ns", 12); $display("\n\n"); $display("******************************************************"); $display("*VGA/LCD Controller Simulation started ... *"); $display("******************************************************"); $display("\n"); `ifdef WAVES $shm_open("waves"); $shm_probe("AS",test,"AS"); $display("INFO: Signal dump enabled ...\n\n"); `endif scen = 0; error_cnt = 0; clk = 0; pclk_i = 0; rst = 0; int_warn=1; repeat(20) @(posedge clk); rst = 1; repeat(20) @(posedge clk); if(0) begin end else if(1) begin `ifdef VGA_12BIT_DVI dvi_pd_test; `endif end else begin // Test area $display("\n\n"); $display("*****************************************************"); $display("*** XXX Test ***"); $display("*****************************************************\n"); s0.fill_mem(1); repeat(10) @(posedge clk); //Parameter setting vbara = 32'h0000_0000; vbarb = 32'h0001_0000; m0.wb_wr1( `VBARA, 4'hf, vbara ); m0.wb_wr1( `VBARB, 4'hf, vbarb ); thsync = 0; thgdel = 0; thgate = 340; thlen = 345; tvsync = 0; tvgdel = 0; tvgate = 240; tvlen = 245; /* thsync = 0; thgdel = 0; thgate = 63; thlen = 70; tvsync = 0; tvgdel = 0; tvgate = 32; tvlen = 36; */ hpol = 0; vpol = 0; cpol = 0; bpol = 0; m0.wb_wr1( `HTIM, 4'hf, {thsync, thgdel, thgate} ); m0.wb_wr1( `VTIM, 4'hf, {tvsync, tvgdel, tvgate} ); m0.wb_wr1( `HVLEN, 4'hf, {thlen, tvlen} ); mode = 2; for(bank=0;bank<3;bank=bank + 1) begin case(mode) 0: begin cd = 2'h2; pc = 1'b0; end 1: begin cd = 2'h0; pc = 1'b0; end 2: begin cd = 2'h0; pc = 1'b1; end 3: begin cd = 2'h1; pc = 1'b0; end endcase m0.wb_wr1( `CTRL, 4'hf, { 16'h0, // Reserved bpol, cpol, vpol, hpol, pc, // 1'b0, // PC cd, // 2'h2, // CD 2'h0, // VBL 1'b0, // Reserved 1'b1, // CBSWE 1'b1, // VBSWE 1'b0, // BSIE 1'b0, // HIE 1'b0, // VIE 1'b1 // Video Enable }); $display("Mode: %0d Screen: %0d", mode, bank); //repeat(2) @(posedge vsync); @(posedge vsync); // Each row of data for(l=0;l<tvgate+1;l=l+1) // For each Pixel for(p=0;p<thgate+1;p=p+1) begin while(blanc) @(posedge pclk); if(bank[0]) vbase = vbarb[31:2]; else vbase = vbara[31:2]; if(bank[0]) cbase = 32'h0000_0c00; else cbase = 32'h0000_0800; // Various display modes //Number of pixels = number of rows * (thgate + 1) + p pn = l * (thgate + 1) + p; case(mode) 0: // 24 bit mode begin pra = pn[31:2] * 3; paa = pra + vbase; // Pixel determined address // pixel data case(pn[1:0]) 0: begin tmp = s0.mem[paa]; pd = tmp[31:8]; end 1: begin tmp = s0.mem[paa]; pd[23:16] = tmp[7:0]; tmp = s0.mem[paa+1]; pd[15:0] = tmp[31:16]; end 2: begin tmp = s0.mem[paa+1]; pd[23:8] = tmp[15:0]; tmp = s0.mem[paa+2]; pd[7:0] = tmp[31:24]; end 3: begin tmp = s0.mem[paa+2]; pd = tmp[23:0]; end endcase end 1: // 8-bit grayscale mode begin pra = pn[31:2]; // Pixel relative address paa = pra + vbase; // Pixel absolute address case(pn[1:0]) 0: begin tmp = s0.mem[paa]; pd = { tmp[31:24], tmp[31:24], tmp[31:24] }; end 1: begin tmp = s0.mem[paa]; pd = { tmp[23:16], tmp[23:16], tmp[23:16] }; end 2: begin tmp = s0.mem[paa]; pd = { tmp[15:8], tmp[15:8], tmp[15:8] }; end 3: begin tmp = s0.mem[paa]; pd = { tmp[7:0], tmp[7:0], tmp[7:0] }; end endcase end 2: // 8-bit pseudo color mode begin pra = pn[31:2]; //Pixel relative address paa = pra + vbase; //Pixel absolute address case(pn[1:0]) 0: begin tmp = s0.mem[paa]; tmp = s0.mem[cbase[31:2] + tmp[31:24]]; pd = tmp[23:0]; end 1: begin tmp = s0.mem[paa]; tmp = s0.mem[cbase[31:2] + tmp[23:16]]; pd = tmp[23:0]; end 2: begin tmp = s0.mem[paa]; tmp = s0.mem[cbase[31:2] + tmp[15:8]]; pd = tmp[23:0]; end 3: begin tmp = s0.mem[paa]; tmp = s0.mem[cbase[31:2] + tmp[7:0]]; pd = tmp[23:0]; end endcase end 3: // 16 bit mode begin pra = pn[31:1]; //Pixel relative address paa = pra + vbase; //Pixel absolute address case(pn[0]) 0: begin tmp = s0.mem[paa]; tmp[15:0] = tmp[31:16]; pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0}; end 1: begin tmp = s0.mem[paa]; pd = {tmp[15:11], 3'h0, tmp[10:5], 2'h0, tmp[4:0], 3'h0}; end endcase end endcase if(pd !== {red, green, blue} ) begin $display("ERROR: Pixel Data Mismatch: Expected: %h, Got: %h %h %h", pd, red, green, blue); $display(" pixel=%0d, line=%0d, (%0t)",p,l,$time); error_cnt = error_cnt + 1; end @(posedge pclk); end end show_errors; $display("*****************************************************"); $display("*** Test DONE ... ***"); $display("*****************************************************\n\n"); end repeat(10) @(posedge clk); $finish; end //Synchronous monitoring `ifdef VGA_12BIT_DVI sync_check #(PCLK_C*2) ucheck( `else sync_check #(PCLK_C) ucheck( `endif .pclk( pclk ), .rst( rst ), .enable( scen ), .hsync( hsync ), .vsync( vsync ), .csync( csync ), .blanc( blanc ), .hpol( hpol ), .vpol( vpol ), .cpol( cpol ), .bpol( bpol ), .thsync( thsync ), .thgdel( thgdel ), .thgate( thgate ), .thlen( thlen ), .tvsync( tvsync ), .tvgdel( tvgdel ), .tvgate( tvgate ), .tvlen( tvlen ) ); // Video data monitoring wb_b3_check u_wb_check ( .clk_i ( clk ), .cyc_i ( wb_cyc_o ), .stb_i ( wb_stb_o ), .cti_i ( wb_cti_o ), .bte_i ( wb_bte_o ), .we_i ( wb_we_o ), .ack_i ( wb_ack_i ), .err_i ( wb_err_i ), .rty_i ( 1'b0 ) ); //Watchdog counter always @(posedge clk) if(wb_cyc_i | wb_cyc_o | wb_ack_i | wb_ack_o | hsync) wd_cnt <= #1 0; else wd_cnt <= #1 wd_cnt + 1; always @(wd_cnt) if(wd_cnt>9000) begin $display("\n\n*************************************\n"); $display("ERROR: Watch Dog Counter Expired\n"); $display("*************************************\n\n\n"); $finish; end always @(posedge int) if(int_warn) begin $display("\n\n*************************************\n"); $display("WARNING: Recieved Interrupt (%0t)", $time); $display("*************************************\n\n\n"); end always #2.5 clk = ~clk; always #(PCLK_C/2) pclk_i = ~pclk_i; //Module prototype vga_enh_top #(1'b0, LINE_FIFO_AWIDTH) u0 ( .wb_clk_i ( clk ), .wb_rst_i ( 1'b0 ), .rst_i ( rst ), .wb_inta_o ( int ), //Slave signal .wbs_adr_i ( wb_addr_i[11:0] ), .wbs_dat_i ( wb_data_i ), .wbs_dat_o ( wb_data_o ), .wbs_sel_i ( wb_sel_i ), .wbs_we_i ( wb_we_i ), .wbs_stb_i ( wb_stb_i ), .wbs_cyc_i ( wb_cyc_i ), .wbs_ack_o ( wb_ack_o ), .wbs_rty_o ( wb_rty_o ), .wbs_err_o ( wb_err_o ), //Main signal .wbm_adr_o ( wb_addr_o[31:0] ), .wbm_dat_i ( wbm_data_i ), .wbm_sel_o ( wb_sel_o ), .wbm_we_o ( wb_we_o ), .wbm_stb_o ( wb_stb_o ), .wbm_cyc_o ( wb_cyc_o ), .wbm_cti_o ( wb_cti_o ), .wbm_bte_o ( wb_bte_o ), .wbm_ack_i ( wb_ack_i ), .wbm_err_i ( wb_err_i ), //VGA signal .clk_p_i ( pclk_i ), `ifdef VGA_12BIT_DVI .dvi_pclk_p_o ( dvi_pclk_p_o ), .dvi_pclk_m_o ( dvi_pclk_m_o ), .dvi_hsync_o ( dvi_hsync_o ), .dvi_vsync_o ( dvi_vsync_o ), .dvi_de_o ( dvi_de_o ), .dvi_d_o ( dvi_d_o ), `endif .clk_p_o ( pclk ), .hsync_pad_o ( hsync ), .vsync_pad_o ( vsync ), .csync_pad_o ( csync ), .blank_pad_o ( blanc ), .r_pad_o ( red ), .g_pad_o ( green ), .b_pad_o ( blue ) ); wb_mast m0( .clk( clk ), .rst( rst ), .adr( wb_addr_i ), .din( wb_data_o ), .dout( wb_data_i ), .cyc( wb_cyc_i ), .stb( wb_stb_i ), .sel( wb_sel_i ), .we( wb_we_i ), .ack( wb_ack_o ), .err( wb_err_o ), .rty( 1'b0 ) ); wb_slv #(24) s0(.clk( clk ), .rst( rst ), .adr( {1'b0, wb_addr_o[30:0]} ), .din( 32'h0 ), .dout( wbm_data_i ), .cyc( wb_cyc_o ), .stb( wb_stb_o ), .sel( wb_sel_o ), .we( wb_we_o ), .ack( wb_ack_i ), .err( wb_err_i ), .rty( ) ); `include "tests.v" endmodule
This paper introduces an example of VGA/LCD display controller. This paper first introduces the relevant knowledge of VGA/LCD display, and then introduces the main structure of the program and the implementation process of the main functional modules. Finally, a test program is used to verify whether the function of the program meets the requirements. This chapter provides a usable scheme for you to design your own VGA/LCD display controller.
This is the end of this article. Great Xia, goodbye! END
The follow-up will be continuously updated, bringing installation related design tutorials such as Vivado, ISE, Quartus II and candence, learning resources, project resources, good article recommendations, etc. I hope you will continue to pay attention.
Heroes, the Jianghu is so big. Continue to wander. May everything be well. See you again!