表2 VGA参考时序设计
VGA工业标准所要求的频率: 时钟频率(Clock frequency):25.175MHz(像素输出的频率); 行频(Line frequency):31469Hz; 场频(Field frequency):59.94Hz(每秒图像刷新频率)。
五、FPGA的设计实现
设计VGA图像显示控制需要注意两个问题:一个是时序的驱动,这是完成设计的关键,时序稍有偏差,显示必然不正常,甚至会损坏彩色显示器;另一个是VGA信号的电平驱动。
显示控制器设计提示:显示器的技术规格提供的行频一般都满足在30-45KHz(保守数据),场频一般满足在50-75Hz(保守数据),针对以上保守数据,我们以30KHz的行频进行扫描时所需时钟频率为:30KHz×800(行周期)=24MHz,则场频为:30KHz÷525(场周期)=57.14Hz,针对实验箱的条件,可以用12MHz的信号经过倍频(EP1K30QC208-2芯片特有的功能,在MaxPlusII软件中调用参数可设置兆功能元件库mega_lpm的CLKLOCK元件来倍频)来产生24MHz的时钟频率,参考设计的顶层文件如下图所示:
图6.VGA接口实现顶视图
VGACORE模块包含了扫描时序产生模块、图像描述模块。时序产生模块的设计可参考图5所示来设计,图像描述模块主要通过640×480个像素点来描述图像。如本项设计的彩条信号发生器可通过图像描述模块产生如下表所示的3种显示模式,共6种显示变化的图像。
表3 VGA图形编码
行彩条 1:白黄青绿品红蓝黑 2:黑蓝红品绿青黄白 竖彩条 1:白黄青绿品红蓝黑 2:黑蓝红品绿青黄白 棋盘格 1:棋盘格显示模式1 2:棋盘格显示模式2 上表颜色对应的编码为: 表4 VGA颜色编码 颜 色 黑 蓝 红 品 绿 青 黄 白 G 0 0 0 0 1 1 1 1 R 0 0 1 1 0 0 1 1 B 0 1 0 1 0 1 0 1 在设计完彩条信号发生器的基础上很容易完成汉字/图像的设计。由于本设计是对视频数据进行处理,用普通的设计方法(不使用专用芯片),在单芯片上实现是不可思议的,而在此用FPGA设计,轻松地达到了面积和速度上的要求。
1 2 3 六、程序及仿真
(一)、管脚分配
本设计采用主板上的VGA接口 实验模式:模式5 时钟及控制
clk----->pin_29 clock9 实验要求采用12M的时钟 rst----->pin_240 键8,低电平有效,作为使能信号 MD ----->pin_233 键1,模式选择信号,共有6种模式 显示器输出
R ----->pin_180 PIO29 G ----->pin_181 PIO30 B ----->pin_182 PIO31 HS ----->pin_183 PIO32 VS ----->pin_185 PIO34
(二)、彩条发生器程序实现及仿真
1、主程序
module vga( clk_25m,rst_n, //系统控制 hsync,vsync,vga_rgb,MD // VGA控制 );
input clk_25m; // 25MHz input rst_n; //低电平复位 input MD;
// FPGA与VGA接口信号 output hsync; //行同步信号 output vsync; //场同步信号 output[2:0] vga_rgb;
//-------------------------------------------------- // 坐标计数 reg[9:0] x_cnt; //行坐标 reg[9:0] y_cnt; //列坐标
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) x_cnt <= 10'd0;
else if(x_cnt == 10'd799) x_cnt <= 10'd0; else x_cnt <= x_cnt+1'b1;
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) y_cnt <= 10'd0;
else if(y_cnt == 10'd524) y_cnt <= 10'd0;
else if(x_cnt == 10'd799) y_cnt <= y_cnt+1'b1;
//-------------------------------------------------- // 产生VGA场同步,行同步信号 reg hsync_r,vsync_r;
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) hsync_r <= 1'b1; else if(x_cnt == 10'd0) hsync_r <= 1'b0; //产生hsync信号 else if(x_cnt == 10'd96) hsync_r <= 1'b1;
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) vsync_r <= 1'b1; else if(y_cnt == 10'd0) vsync_r <= 1'b0; //产生vsync信号 else if(y_cnt == 10'd2) vsync_r <= 1'b1;
assign hsync = hsync_r; assign vsync = vsync_r;
//-------------------------------------------------- //有效显示标志位产生
reg valid_yr; //行显示有效信号
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) valid_yr <= 1'b0;
else if(y_cnt == 10'd32) valid_yr <= 1'b1; else if(y_cnt == 10'd512) valid_yr <= 1'b0;
wire valid_y = valid_yr;
reg valid_r; // VGA有效显示区标志位
always @ (posedge clk_25m or negedge rst_n) if(!rst_n) valid_r <= 1'b0;
else if((x_cnt == 10'd141) && valid_y) valid_r <= 1'b1; else if((x_cnt == 10'd781) && valid_y) valid_r <= 1'b0;
wire valid = valid_r;
wire[9:0] x_dis; //横坐标显示有效区域相对坐标值0-639 wire[9:0] y_dis; //竖坐标显示有效区域相对坐标值0-479
assign x_dis = x_cnt - 10'd142; assign y_dis = y_cnt - 10'd33;
//-------------------------------------------------- //--------------------------------------------- reg[2:0] cnt;
always @ (posedge MD or negedge rst_n) begin if(!rst_n) cnt <= 3'd0;
else if(cnt==3'd5) cnt<=3'd0; else
cnt<=cnt+3'd1; end
//-------------------------------------------------- // VGA色彩信号产生 /*
RGB = 000 黑色 RGB = 100 红色 = 001 蓝色 = 101 紫色 = 010 绿色 = 110 黄色 = 011 青色 = 111 白色 */
//---------------------------------------------------- reg[2:0] vga_rgb;
always@( posedge clk_25m)begin if(!valid) vga_rgb <= 3'd0; else begin
if (cnt==3'd0)begin //竖彩条模式
if(x_dis >= 10'd0 && x_dis < 10'd80) vga_rgb <= 3'd0;
else if(x_dis >= 10'd80 && x_dis < 10'd160) vga_rgb <= 3'd1; else if(x_dis >= 10'd160 && x_dis < 10'd240) vga_rgb <= 3'd2; else if(x_dis >= 10'd240 && x_dis < 10'd320) vga_rgb <= 3'd3; else if(x_dis >= 10'd320 && x_dis < 10'd400) vga_rgb <= 3'd4; else if(x_dis >= 10'd400 && x_dis < 10'd480) vga_rgb <=3'd5; else if(x_dis >= 10'd480 && x_dis < 10'd560) vga_rgb <= 3'd6; else if(x_dis >= 10'd560 && x_dis < 10'd640) vga_rgb <= 3'd7; end
if (cnt==3'd1)begin //竖彩条模式
if(x_dis >= 10'd0 && x_dis < 10'd80) vga_rgb <= 3'd7;
else if(x_dis >= 10'd80 && x_dis < 10'd160) vga_rgb <= 3'd6;
else if(x_dis >= 10'd160 && x_dis < 10'd240) vga_rgb <= 3'd5; else if(x_dis >= 10'd240 && x_dis < 10'd320) vga_rgb <= 3'd4; else if(x_dis >= 10'd320 && x_dis < 10'd400) vga_rgb <= 3'd3; else if(x_dis >= 10'd400 && x_dis < 10'd480) vga_rgb <=3'd2; else if(x_dis >= 10'd480 && x_dis < 10'd560) vga_rgb <= 3'd1; else if(x_dis >= 10'd560 && x_dis < 10'd640) vga_rgb <= 3'd0; end
if(cnt==3'd2)begin //横彩条模式
if(y_dis >= 10'd0 && y_dis < 10'd60) vga_rgb <= 3'd0;
else if(y_dis >= 10'd60 && y_dis < 10'd120) vga_rgb <= 3'd1; else if(y_dis >= 10'd120 && y_dis < 10'd180) vga_rgb <= 3'd2; else if(y_dis >= 10'd180 && y_dis < 10'd240) vga_rgb <= 3'd3; else if(y_dis >= 10'd240 && y_dis < 10'd300) vga_rgb <= 3'd4; else if(y_dis >= 10'd300 && y_dis < 10'd360) vga_rgb <= 3'd5; else if(y_dis >= 10'd360 && y_dis < 10'd420) vga_rgb <= 3'd6; else if(y_dis >= 10'd420 && y_dis < 10'd480) vga_rgb <=3'd7; end
if(cnt==3'd3)begin //横彩条模式
if(y_dis >= 10'd0 && y_dis < 10'd60) vga_rgb <= 3'd7;
else if(y_dis >= 10'd60 && y_dis < 10'd120) vga_rgb <= 3'd6; else if(y_dis >= 10'd120 && y_dis < 10'd180) vga_rgb <= 3'd5; else if(y_dis >= 10'd180 && y_dis < 10'd240) vga_rgb <= 3'd4; else if(y_dis >= 10'd240 && y_dis < 10'd300) vga_rgb <= 3'd3; else if(y_dis >= 10'd300 && y_dis < 10'd360) vga_rgb <= 3'd2; else if(y_dis >= 10'd360 && y_dis < 10'd420) vga_rgb <= 3'd1; else if(y_dis >= 10'd420 && y_dis < 10'd480) vga_rgb <=3'd0; end
if(cnt==3'd4)begin //棋盘格模式 case(x_dis) 10'd0: begin
if(y_dis >= 10'd0 && y_dis < 10'd60) vga_rgb <= 3'd0;
else if(y_dis >= 10'd60 && y_dis < 10'd120) vga_rgb <= 3'd1; else if(y_dis >= 10'd120 && y_dis < 10'd180) vga_rgb <= 3'd2; else if(y_dis >= 10'd180 && y_dis < 10'd240) vga_rgb <= 3'd3; else if(y_dis >= 10'd240 && y_dis < 10'd300) vga_rgb <= 3'd4; else if(y_dis >= 10'd300 && y_dis < 10'd360) vga_rgb <= 3'd5; else if(y_dis >= 10'd360 && y_dis < 10'd420) vga_rgb <= 3'd6; else if(y_dis >= 10'd420 && y_dis < 10'd480) vga_rgb <= 3'd7; end
10'd80,10'd160,10'd240,10'd320,10'd400,10'd480,10'd560,10'd640:
vga_rgb <= vga_rgb+3'd1; //每80个横坐标像素点后显示色彩数据增1变化 default: ; endcase