0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA实现一个VGA/LCD显示控制器的实例

FPGA技术江湖 来源:FPGA技术江湖 作者:FPGA技术江湖 2022-08-01 10:49 次阅读

今天给大侠带来基于FPGA的VGA/LCD显示控制器设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试以及总结话不多说,上货。

导读

VGA (Video Graphics Array) 即视频图形阵列,是IBM于1987年随PS/2机(PersonalSystem 2)一起推出的使用模拟信号的一种视频传输标准。这个标准对于现今的个人电脑市场已经十分过时。但在当时具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域取得了广泛的应用,是众多制造商所共同支持的一个低标准。

LCD ( Liquid Crystal Display 的简称)液晶显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。按照背光源的不同,LCD可以分为CCFL显示器和LED显示器两种。LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分普及。

在之前的文章中介绍了如何获取、处理摄像头提供的视频信号,在实际应用中还需要将经过处理的信号显示在显示器上。这个过程与信号处理中的过程上是相反的,将数字信号按照电视信号的制式组成合乎时序、格式要求的信号,并加入用于控制的各种同步信号。本篇将通过 FPGA实现一个 VGA/LCD 显示控制器的实例,并详细介绍实现过程。

第三篇内容摘要:本篇会介绍程序的仿真与测试以及总结等相关内容。

四、程序的仿真与测试

为了检验程序是否实现预先设定的功能,需要编写仿真程序。仿真程序的主要代码如下:


module test;    //寄存器    reg clk;    reg rst;    //参数    parameter LINE_FIFO_AWIDTH = 7;    //wire 申明    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;        // 测试程序变量    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;        // 常量定义    `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;        //测试内容    initial        begin            $timeformat (-9, 1, " ns", 12);            $display("

");            $display("******************************************************");            $display("*VGA/LCD Controller Simulation started ... *");            $display("******************************************************");            $display("
");                `ifdef WAVES        $shm_open("waves");        $shm_probe("AS",test,"AS");        $display("INFO: Signal dump enabled ...

");      `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                // 测试区域    $display("

");    $display("*****************************************************");    $display("*** XXX Test ***");    $display("*****************************************************
");            s0.fill_mem(1);        repeat(10) @(posedge clk);        //参数设置        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);        // 每一行数据    for(l=0;l    // For each Pixel    for(p=0;p        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;                        // 各种显示模式            //像素数目 = 行数* (thgate + 1) + p            pn = l * (thgate + 1) + p;                        case(mode)                0: // 24 位模式                begin                    pra = pn[31:2] * 3;                    paa = pra + vbase; // 像素决定地址                                // 像素数据                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 位灰度模式                begin                    pra = pn[31:2]; // 像素相对地址                    paa = pra + vbase; // 像素绝对地址                    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 位伪彩色模式                begin                    pra = pn[31:2]; //像素相对地址                    paa = pra + vbase; //像素绝对地址                    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 位模式              begin                  pra = pn[31:1]; //像素相对地址                  paa = pra + vbase; //像素绝对地址                  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("*****************************************************

");   end        repeat(10) @(posedge clk);      $finish;  end    //同步监视    `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 ) );            // 视频数据监视    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 ) );
    //看门狗计数器    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("

*************************************
");                $display("ERROR: Watch Dog Counter Expired
");                $display("*************************************


");                $finish;            end                always @(posedge int)        if(int_warn)            begin                $display("

*************************************
");                $display("WARNING: Recieved Interrupt (%0t)", $time);                $display("*************************************


");            end        always #2.5 clk = ~clk;    always #(PCLK_C/2) pclk_i = ~pclk_i;        //模块原型    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 ),        //从信号        .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 ),        //主信号        .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 信号        .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

五、总结

本篇介绍了一个 VGA/LCD 显示控制器的实例。首先介绍了 VGA/LCD 显示的相关知识,然后介绍了程序的主要结构和主要功能模块的实现过程。最后用一个测试程序验证程序的功能是否满足要求。本章为各位大侠设计自己的 VGA/LCD 显示控制器提供了一个可以使用的方案。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1625

    文章

    21644

    浏览量

    601419
  • 控制器
    +关注

    关注

    112

    文章

    16149

    浏览量

    177195
  • lcd
    lcd
    +关注

    关注

    34

    文章

    4407

    浏览量

    166973

原文标题:系统设计精选 | 基于FPGA的VGA/LCD显示控制器设计(附代码)

文章出处:【微信号:HXSLH1010101010,微信公众号:FPGA技术江湖】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于FPGALCD1602液晶显示模块驱动设计

    本文通过以LCD1602液晶显示模块为基础,介绍FPGA驱动LCD1602原理,详细介绍硬件原理图设计及FPGA驱动
    的头像 发表于 10-24 14:42 534次阅读
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>LCD</b>1602液晶<b class='flag-5'>显示</b>模块驱动设计

    什么是LCD控制器?爱普生LCD控制器的作用和功能、概述和产品列表

    什么是LCD控制器LCD控制器的作用和功能LCD控制器(液晶
    的头像 发表于 10-09 11:10 227次阅读
    什么是<b class='flag-5'>LCD</b><b class='flag-5'>控制器</b>?爱普生<b class='flag-5'>LCD</b><b class='flag-5'>控制器</b>的作用和功能、概述和产品列表

    新型微控制器S1C31W73非常适合带LCD显示器的可穿戴产品

    新型Arm®微控制器“S1C31W73”配备大容量闪存和高分辨率LCD驱动-非常适合办公室、工业设备和带LCD显示器的可穿戴产品-精工爱普
    的头像 发表于 08-13 15:08 253次阅读
    新型微<b class='flag-5'>控制器</b>S1C31W73非常适合带<b class='flag-5'>LCD</b><b class='flag-5'>显示器</b>的可穿戴产品

    组合逻辑控制器是用什么实现

    组合逻辑控制器种用于控制和管理复杂系统中各个组件之间交互的逻辑设备。它可以应用于各种领域,如计算机科学、通信、自动化控制等。在这篇文章中,我们将详细探讨组合逻辑
    的头像 发表于 06-30 10:11 449次阅读

    在STM32F429使用内部TFT控制器进行LCD显示,是否可以存在锁住屏幕的操作?

    在STM32F429使用内部TFT控制器进行LCD显示,是否可以存在锁住屏幕 的操作。即不读SDRAM,LCD显示的内容可以不变。 有这种
    发表于 05-17 08:08

    浅谈母联控制器

    WQ7C母联控制器种具有自动化测量、LCD显示、数字通讯为体的智能化母联控制模块。
    的头像 发表于 04-23 14:43 817次阅读
    浅谈母联<b class='flag-5'>控制器</b>

    补偿控制器显示低无功是什么意思

    补偿控制器是电力系统中的种重要设备,用于改善电力传输和配电中的功率因数,并提高系统的稳定性和效率。在补偿控制器上,有
    的头像 发表于 04-07 14:14 1573次阅读
    补偿<b class='flag-5'>控制器</b><b class='flag-5'>显示</b>低无功是什么意思

    FPGA实现的“俄罗斯方块”游戏系统设计

    本项目主要在FPGA实现经典小游戏“俄罗斯方块”。本项目基本解决方案是,使用Xilinx Zynq系列开发板 ZedBoard 作为平台,
    发表于 03-28 10:41 1901次阅读
    <b class='flag-5'>FPGA</b><b class='flag-5'>实现</b>的“俄罗斯方块”游戏系统设计

    Led显示控制系统怎么使用 led显示控制器怎么设置

    Led显示控制系统是种用于控制LED显示屏的硬件设备,通过它可以实现对LED
    的头像 发表于 02-03 14:03 7351次阅读

    液晶显示控制器LCDC

    液晶显示控制器
    Piezoman压电侠
    发布于 :2024年01月23日 15:43:34

    内存显示控制器介绍

    内存显示控制器
    Piezoman压电侠
    发布于 :2024年01月23日 11:33:39

    平视显示控制器应用于汽车

    显示控制器
    Piezoman压电侠
    发布于 :2024年01月19日 14:58:05

    S1D13L02 VGA简单的液晶控制器

    S1D13L02是款简单、低成本、低功耗、多用途的液晶控制器,具有1024 KB的嵌入式SRAM显示缓冲区。 S1D13L02提供了
    发表于 01-16 09:57 0次下载

    补偿控制器为什么会显示负数?

    在自动控制领域,补偿控制器种常用的控制器类型,它可以对系统的误差进行补偿,并实现系统的稳定性和精确性。然而,有时候我们会遇到
    的头像 发表于 01-12 14:21 2010次阅读
    补偿<b class='flag-5'>控制器</b>为什么会<b class='flag-5'>显示</b>负数?

    液晶显示控制器LCDC

    LCD显示控制器
    Piezoman压电侠
    发布于 :2024年01月10日 15:45:45