一、VGA协议
VGA(Video Graphics Array)视频图形阵列是 IBM 于1987年提出的一个使用模拟信号的电脑显示标准。VGA具有分辨率高、显示速率快、颜色丰富等优点。VGA 接口不但是CRT 显示设备的标准接口,同样也是 LCD 液晶显示设备的标准接口,具有广泛的应用范围。
使用原理:显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,完成一屏后在返回来扫描剩下的线,隔行扫描的显示器闪烁的厉害,会让使用者的眼睛疲劳。在此我们选择逐行扫描的方式。
二、使用设备
设备为DE2-115
TIPS:
具体实现方式请根据开发板来,就比如DE2-115这块板子,需要传输rgb三原色的数据和行场同步信号,也需要传输时钟、和消隐信号,且RBG是888位宽的,其他板子可能不一样,需要更改
三、模块设计
模块分为时钟模块、数据产生模块、和vga控制模块,时钟模块产生所需时钟,但这里并不是根据分辨率自动设置,而是写死在了640*480 @ 60HZ,所以为25M,如果要写其他的,自行更改
数据产生模块是根据vga控制模块传出来的位置来控制所显示的输出,再把所显示的数据输出回传到vga控制模块
vga控制模块就是输出vga协议的一些控制信号
四、代码
若显示彩条,可以直接复制下面代码,把数据生成模块厉的rom实例化和图片输出注释就行,再把彩条输出的输出取消注释
若是显示图片,需要调用rom核,并且需要将图片转成bmp文件,再把bmp转为mif文件,然后在调用rom的时候将图片转为的mif文件设为初始化文件,这样就可以通过地址来读取rom里存储的图片数据,当判断条件成立时,就可以把图片显示到显示屏上了。
top
module vga_top(
input wire clk ,
input wire rst_n ,
output wire hsync ,
output wire vsync ,
output wire [7:0] vga_r ,
output wire [7:0] vga_g ,
output wire [7:0] vga_b ,
output wire vga_clk ,
output wire vga_blk
);
wire [23:0] data_dis;
wire [10:0] h_addr;
wire [10:0] v_addr;
vga_ctrl vga_ctrl(
/*input wire */ .clk (clk ) ,
/*input wire */ .rst_n (rst_n ) ,
/*input wire [23:0] */ .data_dis (data_dis) ,
/**/
/*output reg [10:0] */ .h_addr (h_addr ) ,
/*output reg [10:0] */ .v_addr (v_addr ) ,
/*output reg */ .hsync (hsync ) ,
/*output reg */ .vsync (vsync ) ,
/*output reg [7:0] */ .vga_r (vga_r ) ,
/*output reg [7:0] */ .vga_g (vga_g ) ,
/*output reg [7:0] */ .vga_b (vga_b ) ,
.vga_blk (vga_blk ) ,
/*output wire */ .vga_clk (vga_clk )
);
data_gen data_gen(
/*input wire */ .vga_clk (vga_clk ) ,
/*input wire */ .rst_n (rst_n ) ,
/*input reg [10:0] */ .h_addr (h_addr ) ,
/*input reg [10:0] */ .v_addr (v_addr ) ,
/**/
/*output reg [23:0] */ .data_dis (data_dis)
);
data_gen
module data_gen(
input wire vga_clk ,
input wire rst_n ,
input wire [10:0] h_addr ,
input wire [10:0] v_addr ,
output reg [23:0] data_dis
);
wire [23:00] q_sig;
reg [399:00] Memery [31:0];
parameter
BLACK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BLUE = 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
parameter
H_VLD = 640,
V_VLD = 480,
PIC_W = 400,
PIC_H = 32,
X_START = (H_VLD - PIC_W >> 1) - 1,
Y_START = (V_VLD - PIC_H >> 1) - 1;
reg [10:00] pix_x,pix_y;
always @(posedge vga_clk)begin
Memery[0] = 400'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
Memery[1] = 400'h000000000000000000000004000000000000000000000000000000000000000000000007000000000004000000000000;
Memery[2] = 400'h000000000000000000000007E00000000007000000180000000000000000000000000007800000000007C000001E0000;
Memery[3] = 400'h000000000000000000000007800000000007C00000180000000000000000080000000007800008000007800000180000;
Memery[4] = 400'h0000000000001C000000000780001C0000078000001800000000000000003E000000000780003E000007800000080000;
Memery[5] = 400'h01FFFFFFFFFFFF000FFFFFFFFFFFFF0000078000200C000000FFFFFFFFFFFF8007FFFFFFFFFFFF8000078000380C0000;
Memery[6] = 400'h00400003C00000000200000780000000000780007E0C000000000003C00000000000000780000000000780007E060000;
Memery[7] = 400'h00000003C00000000000000780000000000780007806000000000003C0000000000000078000C0000007800078060000;
Memery[8] = 400'h00000003C0000000000000078001E00000078300F007000000000003C0000000007FFFFFFFFFF00000078780F0030000;
Memery[9] = 400'h00000003C0000000003FFFFFFFFFF8001FFFFFC0E003800000000003C000000000180007800000000FFFFFE0E0038000;
Memery[10] = 400'h00000003C00000000000000780000000000F8001C001C00000000003C00000000000000780000000000F8001C001C000;
Memery[11] = 400'h00000003C00000000000000780000180000F8003C001E00000000003C000000000000007800003C0000F80038000F000;
Memery[12] = 400'h00000003C000000000000007800007E0000F80030000F80000000003C00000003FFFFFFFFFFFFFF0001F800700007800;
Memery[13] = 400'h00000003C00000001FFFFFFFFFFFFFF8001F800600007C0000000003C00000000C00000000000000001FC00E00003E00;
Memery[14] = 400'h00000003C00000000000000000000000001FF00C00001F8000000003C00000000001000000000000003FBC1800001FC0;
Memery[15] = 400'h00000003C00060000000C00000060000003F9E1803800FF800000003C000F0000000FFFFFFFF8000003F9F3003C007C0;
Memery[16] = 400'h003FFFFFFFFFF8000000FFFFFFFF8000007F8F2003F00300001FFFFFFFFFFC000000E000000F000000778FC003E00000;
Memery[17] = 400'h000C0003C00000000000E000000F00000077878007C0000000000003C00000000000E000000F000000E7870007800000;
Memery[18] = 400'h00000003C00000000000E000000F000000E783000700000000000003C00000000000E000000F000000C780000F000000;
Memery[19] = 400'h00000003C00000000000FFFFFFFF000001C780000E00000000000003C00000000000FFFFFFFF0000018780001E000000;
Memery[20] = 400'h00000003C00000000000E000000F0000038780001C00000000000003C00000000000E000000F0000030780001C000000;
Memery[21] = 400'h00000003C00000000000E000000F0000070780003800000000000003C00000000000E000000F000006078000380C0000;
Memery[22] = 400'h00000003C00000000000E000000F00000C0780007006000000000003C00000000000E000000F00000807800070030000;
Memery[23] = 400'h00000003C00000000000FFFFFFFF000018078000E003800000000003C00000000000FFFFFFFF000010078000E001C000;
Memery[24] = 400'h00000003C00000000000E000000F000000078000C001E00000000003C00000000000E000000F0000000780018000F000;
Memery[25] = 400'h00000003C00000000000E000000F0000000780018000F00000000003C00000000000E000000F00000007800300007800;
Memery[26] = 400'h00000003C00001000000E000000F00000007800700007C0000000003C00003800000E000000F00000007800E00007C00;
Memery[27] = 400'h00000003C00007C00000E000000F00000007801E7FFFFE001FFFFFFFFFFFFFE00000E0001E0F00000007803FFFFF3E00;
Memery[28] = 400'h0FFFFFFFFFFFFFF00000E0000FFF00000007801FFE003E0004000000000000000000E00001FF00000007800FC0001E00;
Memery[29] = 400'h00000000000000000000E000007E00000007800E00001C0000000000000000000000E000003C00000007800000001800;
Memery[30] = 400'h00000000000000000000E000003800000007800000000000000000000000000000008000002000000004000000000000;
Memery[31] = 400'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
end
always @(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
pix_x <= 11'd0;
pix_y <= 11'd0;
end
else if((h_addr >= X_START && h_addr < X_START + PIC_W)&&(v_addr >= Y_START && v_addr < Y_START + PIC_W))begin
pix_x <= h_addr - X_START;
pix_y <= v_addr - Y_START;
end
else begin
pix_x <= 11'h7FF;
pix_y <= 11'h7FF;
end
end
always @(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
data_dis <= WHITE;
end
else begin
case(h_addr)
0 : data_dis <= BLACK ;
80 : data_dis <= RED ;
160: data_dis <= GREEN ;
240: data_dis <= BLUE ;
320: data_dis <= YELLOW ;
400: data_dis <= SKY_BLUE;
480: data_dis <= PURPLE ;
560: data_dis <= GRAY ;
default: data_dis <= data_dis;
endcase
end
end
endmodule ctrl
`define vga_640_480
`include "vga_param.v"
module vga_ctrl(
input wire clk ,
input wire rst_n ,
input wire [23:0] data_dis ,
output reg [10:0] h_addr ,//数据有效显示区域行地址
output reg [10:0] v_addr ,//数据有效显示区域场地址
output reg hsync ,
output reg vsync ,
output reg [7:0] vga_r ,
output reg [7:0] vga_g ,
output reg [7:0] vga_b ,
output reg vga_blk ,
output wire vga_clk
);
parameter H_SYNC_STA = 1,
H_SYNC_STO = `H_Sync_Time,
H_DATA_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border,
H_DATA_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time;
parameter V_SYNC_STA = 1,
V_SYNC_STO = `V_Sync_Time,
V_DATA_STA = `V_Sync_Time + `V_Back_Porch + `V_Top_Border,
V_DATA_STO = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;
reg [11:0] cnt_h_addr;//行地址计数器
wire add_h_addr ;
wire end_h_addr ;
reg [11:0] cnt_v_addr;//列地址计数器
wire add_v_addr ;
wire end_v_addr ;
wire clk_25 ;
pll pll_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( clk_25 )
);
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
cnt_h_addr <= 12'd0;
end
else if(add_h_addr)begin
if(end_h_addr)begin
cnt_h_addr <= 12'd0;
end
else begin
cnt_h_addr <= cnt_h_addr + 12'd1;
end
end
else begin
cnt_h_addr <= 12'd0;
end
end
assign add_h_addr = 1'b1;
assign end_h_addr = add_h_addr && cnt_h_addr >= `H_Total_Time - 1;
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
cnt_v_addr <= 12'd0;
end
else if(add_v_addr)begin
if(end_v_addr)begin
cnt_v_addr <= 12'd0;
end
else begin
cnt_v_addr <= cnt_v_addr + 12'd1;
end
end
else begin
cnt_v_addr <= cnt_v_addr;
end
end
assign add_v_addr = end_h_addr;
assign end_v_addr = add_v_addr && cnt_v_addr >= `V_Total_Time - 1;
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
hsync <= 1'b1;
end
else if(cnt_h_addr == H_SYNC_STA- 1)begin
hsync <= 1'b0;
end
else if(cnt_h_addr == H_SYNC_STO - 1)begin
hsync <= 1'b1;
end
else begin
hsync <= hsync;
end
end
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
vsync <= 1'b1;
end
else if(cnt_v_addr == V_SYNC_STA - 1)begin
vsync <= 1'b0;
end
else if(cnt_v_addr == V_SYNC_STO - 1)begin
vsync <= 1'b1;
end
else begin
vsync <= vsync;
end
end
assign vga_clk = ~clk_25;
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
h_addr <= 11'd0;
end
else if((cnt_h_addr >= H_DATA_STA - 1) && (cnt_h_addr <= H_DATA_STO -1) )begin
h_addr <= cnt_h_addr - H_DATA_STA - 1;
end
else begin
h_addr <= 11'd0;
end
end
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
v_addr <= 11'd0;
end
else if((cnt_v_addr >= V_DATA_STA - 1) && (cnt_v_addr <= V_DATA_STO -1) )begin
v_addr <= cnt_v_addr - V_DATA_STA - 1;
end
else begin
v_addr <= 11'd0;
end
end
always@(posedge vga_clk or negedge rst_n)begin
if(!rst_n)begin
vga_r <= 8'b0;
vga_g <= 8'b0;
vga_b <= 8'b0;
vga_blk <= 1'b0;
end
else if((cnt_h_addr >= H_DATA_STA - 1) && (cnt_h_addr <= H_DATA_STO -1) &&
(cnt_v_addr >= V_DATA_STA - 1) && (cnt_v_addr <= V_DATA_STO -1) )begin
vga_r <= data_dis[23:16];
vga_g <= data_dis[15:8];
vga_b <= data_dis[7:0];
vga_blk <= 1'b1;
end
else begin
vga_r <= 8'b0;
vga_g <= 8'b0;
vga_b <= 8'b0;
vga_blk <= 1'b0;
end
end
endmodule


五、总结
毕竟是初学vga协议,还是有很多迷迷糊糊的地方。但结果一段时间的沉淀,之后应该会有所理解。