基于verilog实现的VGA

VGA原理

视频图形阵列(Video Graphics Array,VGA),是IBM在1987年推出的视频传输标准。

VGA从屏幕左上角第一个像素点开始,自左向右进行扫描,每一行扫描完成后,回到下一行最左位置的像素点,继续上述过程,最后一行像素点扫描完成后,回到屏幕左上角,继续下一轮扫描。

VGA接口重点需要明确每一行的扫描时间,称为行时序,以及每一次屏幕扫描的时间,称为场时序

行时序由四个部分组成,行同步(Hor Sync)行消隐(Hor Back Porch)行视频有效(Hor Active Video)行前肩(Hor Front Porch)。先后顺序为,

Hor Sync -> Hor Back Porch -> Hor Active Video -> Hor Front Porch

其中,行同步信号需要是负脉冲,且行时序中的每个部分持续的时间单位为像素,即时钟周期

场时序由四个部分组成,场同步(Ver Sync)场消隐(Ver Back Porch)场视频有效(Ver Active Video)场前肩(Ver Front Porch)。先后顺序为,

Ver Sync -> Ver Back Porch -> Ver Active Video -> Ver Front Porch

其中,场同步信号需要时负脉冲,且场时序中每个部分持续的时间单位为

VGA在不同的分辨率刷新频率下,对于行时序和场时序各个部分的时间要求也不相同,VGA时序参数给出常用显示模式与对应的行时序和场时序的参数。

VGA实现

本文实现的在分辨率为640*480,刷新频率为60Hz的VGA驱动。

  • 时钟:25.175 MHz
  • 行时序参数(单位:像素)
    • 行同步(Hor Sync):96
    • 行消隐(Hor Back Porch):48
    • 行视频有效(Hor Active Video):640
    • 行前肩(Hor Front Porch):16
  • 场时序参数(单位:行)
    • 场同步(Ver Sync):2
    • 场消隐(Ver Back Porch):33
    • 场视频有效(Ver Active Video):480
    • 场前肩(Ver Front Porch) :10

VGA同步信号

module vga_dirver(
input wire clk_i,
input wire rst_i,

output reg hor_sync_o,
output reg ver_sync_o,

output wire display_en_o
);
localparam HOR_SYNC_CNT = 96;
localparam HOR_BACK_PORCH_CNT = 48;
localparam HOR_ACTIVE_VIDEO_CNT = 640;
localparam HOR_FRONT_PORCH_CNT = 16;
localparam HOR_PERIOD = 800;

localparam VER_SYNC_CNT = 2;
localparam VER_BACK_PORCH_CNT = 33;
localparam VER_ACTIVE_VIDEO_CNT = 480;
localparam VER_FRONT_PORCH_CNT = 10;
localparam VER_PERIOD = 525;

reg [31:0] hor_count;
reg [31:0] ver_count;
reg hor_sync;
reg ver_sync;
// hor_sync
always @ (*) begin
    if(rst_i == 1'b1) begin
        hor_sync = 1'b1;
    end else begin
        hor_sync = (hor_count < HOR_SYNC_CNT) ? 1'b0 : 1'b1;
    end
end
// 访问显存,hor_sync_o 打一拍输出
always @ (posedge clk_i) begin
    if(rst_i == 1'b1) begin
        hor_sync_o <= 1'b1;
    end else begin
        hor_sync_o <= hor_sync;
    end
end
// ver_sync
always @ (*) begin
    if(rst_i == 1'b1) begin
        ver_sync = 1'b1;
    end else begin
        ver_sync = (ver_count < VER_SYNC_CNT) ? 1'b0 : 1'b1;
    end
end
// 访问显存,ver_sync_o 打一拍输出
always @ (posedge clk_i) begin
    if(rst_i == 1'b1) begin
        ver_sync_o <= 1'b1;
    end else begin
        ver_sync_o <= ver_sync;
    end
end
// display_en_o
assign display_en_o = (hor_count >= HOR_SYNC_CNT + HOR_BACK_PORCH_CNT) && 
                      (hor_count < HOR_SYNC_CNT + HOR_BACK_PORCH_CNT + HOR_ACTIVE_VIDEO_CNT) &&
                      (ver_count >= VER_SYNC_CNT + VER_BACK_PORCH_CNT) &&
                      (ver_count < VER_SYNC_CNT + VER_BACK_PORCH_CNT + VER_ACTIVE_VIDEO_CNT);
// hor_count
always @ (posedge clk_i) begin
    if(rst_i == 1'b1) begin
        hor_count <= 0;
    end else begin
        if(hor_count == HOR_PERIOD - 1) begin
            hor_count <= 0;
        end else begin
            hor_count <= hor_count + 1;
        end
    end
end
// ver_count
always @ (posedge clk_i) begin
    if(rst_i == 1'b1) begin
        ver_count <= 0;
    end else begin
        if(ver_count == VER_PERIOD - 1) begin
            if(hor_count == HOR_PERIOD - 1) begin
                ver_count <= 0;
            end else begin
                ver_count <= ver_count;
            end
        end else begin
            if(hor_count == HOR_PERIOD - 1) begin
                ver_count <= ver_count + 1;
            end else begin
                ver_count <= ver_count;
            end
        end
    end
end

endmodule

VGA显示存储

module vga_rom(
input wire clk_i,

input wire wr_en_i,
input wire [9:0] wr_addr_i,
input wire [11:0] wr_data_i,

input wire [9:0] rd_addr_i,

output reg [11:0] rd_data_o
);

reg [11:0] vga_rom [0:1023];

always @ (posedge clk_i) begin
    if(wr_en_i == 1'b1) begin
        vga_rom[wr_addr_i] <= wr_data_i;
    end else begin
    end
end

always @ (posedge clk_i) begin
    rd_data_o <= vga_rom[rd_addr_i];
end
endmodule

VGA顶层文件

module vga_top(
input wire clk_i,
input wire rst_i,

input wire [11:0] display_rd_data_i,

output reg [9:0] display_rd_addr_o,

output reg [3:0] red_o,
output reg [3:0] grn_o,
output reg [3:0] blu_o,

output wire hor_sync_o,
output wire ver_sync_o
);

wire display_en;
reg [11:0] display_rd_data;
// red_o grn_o blu_o
always @ (*) begin
    if(rst_i == 1'b1) begin
        red_o = 0;
        grn_o = 0;
        blu_o = 0;
    end else begin
        red_o = display_rd_data[3:0];
        grn_o = display_rd_data[7:4];
        blu_o = display_rd_data[11:8];
    end
end
// display_rd_data
always @ (*) begin
    if(rst_i == 1'b1) begin
        display_rd_data = 0;
    end else begin 
        if(display_en == 1'b1) begin
            display_rd_data = display_rd_data_i;
        end else begin
            display_rd_data = 0;
        end
    end
end
// display_rd_addr_o
always @ (posedge clk_i) begin
    if(rst_i == 1'b1) begin
        display_rd_addr_o <= 0;
    end else begin
        if(display_en == 1'b1) begin
            display_rd_addr_o <= display_rd_addr_o + 1;
        end else begin
            display_rd_addr_o <= display_rd_addr_o;
        end
    end
end

vga_dirver vga_dirver_inst(
.clk_i(clk_i),
.rst_i(rst_i),

.hor_sync_o(hor_sync_o),
.ver_sync_o(ver_sync_o),

.display_en_o(display_en)
);

endmodule

测试文件

在显存中随机写入数据,比较显示时序行同步场同步时序。

module testbench();

reg clk;
reg rst;
reg vga_rom_wr_en;
reg [11:0] vga_rom_wr_data;
reg [9:0] vga_rom_wr_addr;
wire [11:0] vga_rom_rd_data;
wire [9:0] vga_rom_rd_addr;
wire [3:0] red;
wire [3:0] grn;
wire [3:0] blu;
wire hor_sync;
wire ver_sync;

initial begin
    clk = 1;
    rst = 1;
    vga_rom_wr_en = 1;
    #4000
    rst = 0;
    vga_rom_wr_en = 0;
end
// 20 MHz时钟
always begin
    #(40 / 2) clk = ~clk;
end
// 初始化显存
initial begin
    vga_rom_wr_addr = 0;
    vga_rom_wr_data = $random;
    repeat(50) begin
        # 40
        if(vga_rom_wr_en == 1'b1) begin
            vga_rom_wr_addr <= vga_rom_wr_addr + 1;
            vga_rom_wr_data <= $random;
        end
    end
end

vga_top vga_top_inst(
.clk_i(clk),
.rst_i(rst),

.display_rd_data_i(vga_rom_rd_data),

.display_rd_addr_o(vga_rom_rd_addr),

.red_o(red),
.grn_o(grn),
.blu_o(blu),

.hor_sync_o(hor_sync),
.ver_sync_o(ver_sync)
);

vga_rom vga_rom_inst(
.clk_i(clk),

.wr_en_i(vga_rom_wr_en),
.wr_addr_i(vga_rom_wr_addr),
.wr_data_i(vga_rom_wr_data),

.rd_addr_i(vga_rom_rd_addr),

.rd_data_o(vga_rom_rd_data)
);

endmodule
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值