FPGA零基础学习:VGA协议驱动设计
设备为DE2-115
具体实现方式请根据开发板来,就比如DE2-115这块板子,需要传输rgb三原色的数据和行场同步信号,也需要传输时钟、和消隐信号,且RBG是888位宽的,其他板子可能不一样,需要更改
若显示彩条,可以直接复制下面代码,把数据生成模块厉的rom实例化和图片输出注释就行,再把彩条输出的输出取消注释
若是显示图片,需要调用rom核,并且需要将图片转成bmp文件,再把bmp转为mif文件,然后在调用rom的时候将图片转为的mif文件设为初始化文件,这样就可以通过地址来读取rom里存储的图片数据,当判断条件成立时,就可以把图片显示到显示屏上了。
module counter25M(
input wire clk , //VGA时
input wire rst_n , //复位
output reg clk_25M
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
clk_25M <= 1'b0 ;
end else begin
clk_25M <= ~clk_25M;
end
end
endmodule
module data_generate(
input wire clk , //VGA时钟,640*480 60hz 25.2MHz
input wire rst_n , //复位
input wire [10:0] h_addr , //数据有效显示区域,行地址
input wire [10:0] v_addr , //数据有效显示区域,列地址
output reg [23:0] data_display //显示数据
);
wire [23:0] q_sig;//从ip核里取出的图片数据
reg [15:0] address_sig;//取图片的地址
wire pic_area;//是否在图片显示的区域
parameter PIC_WIDTH = 9'd200;//图片长
parameter PIC_HEIGH = 9'd200;//图片宽
parameter BALCK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BULE = 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
//调用ip核,取数据
//存入的图片为512*512,640*480
rom rom_inst (
.address ( address_sig ),
.clock ( clk ),
.q ( q_sig )
);
assign pic_area = h_addr <= PIC_WIDTH && v_addr <= PIC_HEIGH;
//位置变化
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
address_sig <= 16'd0;
end else if ( address_sig == 40000 ) begin
address_sig <= 16'd0;
end else if ( pic_area ) begin//在显示区域里随着地址变化自动变换
address_sig <= h_addr + v_addr * 200 ;
end
else begin //大于图片显示区域,将保持地址
address_sig <= address_sig ;
end
end
//状态输出,图片输出
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_display <= WHITE ;
end else begin
case (pic_area)
0 : data_display <= RED ;
1 : data_display <= q_sig ;
default: data_display <= data_display ;
endcase
end
end
/* //状态输出,彩条输出
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_display <= WHITE ;
end else begin
case (h_addr)
0 : data_display <= BALCK ;
80 : data_display <= RED ;
160 : data_display <= GREEN ;
240 : data_display <= BLUE ;
320 : data_display <= YELLOW ;
400 : data_display <= SKY_BULE ;
480 : data_display <= PURPLE ;
560 : data_display <= GRAY ;
default: data_display <= data_display ;
endcase
end
end */
endmodule
`define vga_640_480
`include "vga_param.v"
module vga_contro(
input wire clk , //VGA时钟,640*480 60hz 25.2MHz
input wire rst_n , //复位
input wire [23:0] data_display , //显示数据
output reg [10:0] h_addr , //数据有效显示区域,行地址,只有当有效的时候,
output reg [10:0] v_addr , //数据有效显示区域,列地址
output reg disp_vld , //表示输入的是否是有效数据,即为显示区域内的数据
output wire v_sync , //场同步信号,有效数据的条件之一
output wire h_sync , //行同步信号,有效数据的条件之一,只有当行和场的同步信号都有效之后,后面输入的才是有效数据
output reg [7:0] vga_r , //红色输出
output reg [7:0] vga_g , //绿色输出
output reg [7:0] vga_b , //蓝色输出
output wire vga_clk //显示时钟,
);
parameter H_SYNC_STA = 1;//行同步开始
parameter H_SYNC_END = `H_Sync_Time;//行同步结束
parameter H_DATA_STA = `H_Sync_Time+`H_Right_Border + `H_Front_Porch;//行数据开始
parameter H_DATA_END = `H_Sync_Time+`H_Right_Border + `H_Front_Porch + `H_Data_Time;//行数据结束
parameter V_SYNC_STA = 1;//场同步开始
parameter V_SYNC_END = `V_Sync_Time;//场同步结束
parameter V_DATA_STA = `V_Sync_Time +`V_Bottom_Border + `V_Front_Porch;//场数据开始
parameter V_DATA_END = `V_Sync_Time +`V_Bottom_Border + `V_Front_Porch+ `V_Data_Time;//场数据结束
reg [(12-1):0] cnt_h; //行地址的计数
wire add_cnt_h ; //行地址开始标志
wire end_cnt_h ; //行地址结束标志
reg [(12-1):0] cnt_v ; //场地址的计数
wire add_cnt_v ; //场地址开始标志
wire end_cnt_v ; //场地址结束标志
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_h <= 12'b0;
end else if(add_cnt_h) begin
if (end_cnt_h) begin
cnt_h <= 12'b0;
end else begin
cnt_h <= cnt_h + 12'b1;
end
end
end
assign add_cnt_h = 1'd1;
assign end_cnt_h = add_cnt_h && cnt_h == `H_Total_Time - 1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_v <= 12'b0;
end else if(add_cnt_v) begin
if (end_cnt_v) begin
cnt_v <= 12'b0;
end else begin
cnt_v <= cnt_v + 12'b1;
end
end
end
assign add_cnt_v = end_cnt_h;
assign end_cnt_v = add_cnt_v && cnt_v == `V_Total_Time - 1;
//同步信号
assign h_sync = (cnt_h > ( H_SYNC_STA - 1) && cnt_h < (H_SYNC_END - 1) );
assign v_sync = (cnt_v >= ( V_SYNC_STA - 1) && cnt_v <= (V_SYNC_END - 1) );
assign vga_clk = ~clk;
//定义有效显示区域
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
h_addr <= 11'd0;
end else if(cnt_h >= (H_DATA_STA - 1) && cnt_h <= (H_DATA_END - 1)) begin
h_addr <= cnt_h - (H_DATA_STA - 1);
end else begin
h_addr <= 11'd0;
end
end
//定义有效显示区域
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
v_addr <= 11'd0;
end else if(cnt_v >= (V_DATA_STA - 1) && cnt_v <= (V_DATA_END - 1)) begin
v_addr <= cnt_v - (V_DATA_STA - 1);
end else begin
v_addr <= 11'd0;
end
end
//有效区域输出
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
vga_r <= 8'd0 ;
vga_g <= 8'd0 ;
vga_b <= 8'd0 ;
disp_vld <= 1'b0;
//数据有效时输出
end else if(cnt_h >= (H_DATA_STA - 1) && cnt_h <= (H_DATA_END - 1) && cnt_v >= (V_DATA_STA - 1) && cnt_v <= (V_DATA_END - 1)) begin
vga_r <= data_display[23-:8] ;
vga_g <= data_display[15-:8] ;
vga_b <= data_display[07-:8] ;
disp_vld <= 1'b1 ;
end else begin
vga_r <= 8'd0 ;
vga_r <= 8'd0 ;
vga_r <= 8'd0 ;
disp_vld <= 1'b0 ;
end
end
endmodule
//`define vga_480_272
`define vga_640_480
//`define vga_800_480
//`define vga_800_600
//`define vga_1024_600
//`define vga_1024_768
//`define vga_1280_720
//`define vga_1920_1080
`ifdef vga_480_272
`define H_Right_Border 0
`define H_Front_Porch 2
`define H_Sync_Time 41
`define H_Back_Porch 2
`define H_Left_Border 0
`define H_Data_Time 480
`define H_Total_Time 525
`define V_Bottom_Border 0
`define V_Front_Porch 2
`define V_Sync_Time 10
`define V_Back_Porch 2
`define V_Top_Border 0
`define V_Data_Time 272
`define V_Total_Time 286
`elsif vga_640_480
`define H_Right_Border 8
`define H_Front_Porch 8
`define H_Sync_Time 96
`define H_Back_Porch 40
`define H_Left_Border 8
`define H_Data_Time 640
`define H_Total_Time 800
`define V_Bottom_Border 8
`define V_Front_Porch 2
`define V_Sync_Time 2
`define V_Back_Porch 25
`define V_Top_Border 8
`define V_Data_Time 480
`define V_Total_Time 525
`elsif vga_800_480
`define H_Right_Border 0
`define H_Front_Porch 40
`define H_Sync_Time 128
`define H_Back_Porch 88
`define H_Left_Border 0
`define H_Data_Time 800
`define H_Total_Time 1056
`define V_Bottom_Border 8
`define V_Front_Porch 2
`define V_Sync_Time 2
`define V_Back_Porch 25
`define V_Top_Border 8
`define V_Data_Time 480
`define V_Total_Time 525
`elsif vga_800_600
`define H_Right_Border 0
`define H_Front_Porch 40
`define H_Sync_Time 128
`define H_Back_Porch 88
`define H_Left_Border 0
`define H_Data_Time 800
`define H_Total_Time 1056
`define V_Bottom_Border 0
`define V_Front_Porch 1
`define V_Sync_Time 4
`define V_Back_Porch 23
`define V_Top_Border 0
`define V_Data_Time 600
`define V_Total_Time 628
`elsif vga_1024_600
`define H_Right_Border 0
`define H_Front_Porch 24
`define H_Sync_Time 136
`define H_Back_Porch 160
`define H_Left_Border 0
`define H_Data_Time 1024
`define H_Total_Time 1344
`define V_Bottom_Border 0
`define V_Front_Porch 1
`define V_Sync_Time 4
`define V_Back_Porch 23
`define V_Top_Border 0
`define V_Data_Time 600
`define V_Total_Time 628
`elsif vga_1024_768
`define H_Right_Border 0
`define H_Front_Porch 24
`define H_Sync_Time 136
`define H_Back_Porch 160
`define H_Left_Border 0
`define H_Data_Time 1024
`define H_Total_Time 1344
`define V_Bottom_Border 0
`define V_Front_Porch 3
`define V_Sync_Time 6
`define V_Back_Porch 29
`define V_Top_Border 0
`define V_Data_Time 768
`define V_Total_Time 806
`elsif vga_1280_720
`define H_Right_Border 0
`define H_Front_Porch 110
`define H_Sync_Time 40
`define H_Back_Porch 220
`define H_Left_Border 0
`define H_Data_Time 1280
`define H_Total_Time 1650
`define V_Bottom_Border 0
`define V_Front_Porch 5
`define V_Sync_Time 5
`define V_Back_Porch 20
`define V_Top_Border 0
`define V_Data_Time 720
`define V_Total_Time 750
`elsif vga_1920_1080
`define H_Right_Border 0
`define H_Front_Porch 88
`define H_Sync_Time 44
`define H_Back_Porch 148
`define H_Left_Border 0
`define H_Data_Time 1920
`define H_Total_Time 2200
`define V_Bottom_Border 0
`define V_Front_Porch 4
`define V_Sync_Time 5
`define V_Back_Porch 36
`define V_Top_Border 0
`define V_Data_Time 1080
`define V_Total_Time 1125
`endif
module vga_protocol_top(
input wire clk , //VGA时钟,640*480 60hz 25.2MHz
input wire rst_n , //复位
output wire v_sync , //场同步信号
output wire h_sync , //行同步信号
output wire [7:0] vga_r , //红色输出
output wire disp_vld , //是否是显示的时候
output wire [7:0] vga_g , //绿色输出
output wire [7:0] vga_b , //蓝色输出
output wire vga_clk //显示时钟,
);
wire [23:0] data_display;
wire [10:0] h_addr ;
wire [10:0] v_addr ;
counter25M u_counter25M(
.clk ( clk ),
.rst_n ( rst_n ),
.clk_25M ( clk_25M )
);
vga_contro u_vga_contro(
.clk ( clk_25M ),
.rst_n ( rst_n ),
.data_display ( data_display ),
.h_addr ( h_addr ),
.v_addr ( v_addr ),
.disp_vld (disp_vld ),
.v_sync ( v_sync ),
.h_sync ( h_sync ),
.vga_r ( vga_r ),
.vga_g ( vga_g ),
.vga_b ( vga_b ),
.vga_clk ( vga_clk )
);
data_generate u_data_generate(
.clk ( clk_25M ),
.rst_n ( rst_n ),
.h_addr ( h_addr ),
.v_addr ( v_addr ),
.data_display ( data_display )
);
endmodule