首先感谢所有开源分享资源的博主或者机构个人,这篇主要参考开拓者FPGA开发指南。通过分析代码,理清思路。
主要分为四个模块,顶层模块,时钟分频模块,VGA显示模块,VGA驱动模块。前三个模块在任何时候都是不变的,只有最后一个模块,显示需要显示的内容。代码设计真的很巧,这里讲驱动模块单独写出来,不仅方便控制,同时仿真也很方便的可以看到结果。具体代码的理解讲在代码中展现,同时后面的字符显示,基于ROM的静态图片显示,都是基于此的。只是有一点,网上现有资源很多不是ISE的,而笔者现在还用的ISE.....;因此在调用IP的时候就很少有教程了。后面再说,这些模块可以在任何板子开发环境下运行编译成bit文件。
实验目标:实现彩条的显示,实现方框移动的显示(从第一行还是移动,一直到最后一行的最后一个,重新回到开始的位置重复),实现部分主要是在display模块显示改变的,这也是这个比较优势的地方。
模块介绍_div_clk
分频模块,生成要用的时钟周期,前面一节里边有时钟周期计算方法,可以调用pll,也可以自己写一个分频都可以。此模块主要提供显示所需要的时钟周期。因为我这里还是用的640*480@60hz,所以还是大概系统时钟的一半。
module div_clk(clk,rst_n,div_clk
);
input clk;
inout rst_n;
output reg div_clk;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
div_clk <= 1'b0;
else
div_clk <= ~div_clk;
end
endmodule
模块介绍_vga_diver
此模块主要两个功能,每一个功能由两个输出组成。
功能一:输出vga_hs,vga_vs这两个时序信号,用来点亮屏幕,时序的控制由厂家提供的文档为基准。
功能二:输出颜色控制,这个主要是将x,y分别输出到下一个模块,即vga_display模块,可以控制每一行每一个像素,然后给颜色。
module vga_driver(
vga_clk,rst_n,pixel_data,
vga_hs,vga_vs,
vga_rgb,x_pixel,y_pixel
);
//---------------------------------
input vga_clk ;
input rst_n ;
input [15:0] pixel_data ;
//---------------------------------
output vga_hs ;
output vga_vs ;
output [15:0] vga_rgb ;
output [ 9:0] y_pixel ;//y像素坐标
output [ 9:0] x_pixel ;//x像素坐标
//---------------------------------
parameter Hor_Total_Time = 10'd800 ; //行显示帧长
parameter Hor_Sync = 10'd96 ; //行同步脉冲
parameter Hor_Back_Porch = 10'd48 ; //行显示后沿(同显示前沿,这里由两个时段合成)
parameter Hor_Addr_Time = 10'd640 ; //行显示区域
parameter Hor_Front_Porch = 10'd16 ; //行显示前沿
//---------------------------------
parameter Ver_Total_Time = 10'd525 ; //列显示帧长
parameter Ver_Sync = 10'd2 ; //列同步脉冲
parameter Ver_Back_Porch = 10'd33 ; //列显示后沿(同显示前沿,这里由两个时段合成)
parameter Ver_Addr_Time = 10'd480 ; //列显示区域
parameter Ver_Front_Porch = 10'd10 ; //列显示前沿
//---------------------------------
//两个计数器
//行计数器
reg [9:0] x_cnt;
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
x_cnt <= 10'd1;
else
if(x_cnt == Hor_Total_Time)
x_cnt <= 10'd1;
else
x_cnt <= x_cnt + 1'b1;
end
//列计数器
reg [9:0] y_cnt;
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
y_cnt <= 10'd1;
else
if(y_cnt == Ver_Total_Time && x_cnt == Hor_Total_Time)
y_cnt <= 10'd1;
else
if(x_cnt == Hor_Total_Time)
y_cnt <= y_cnt + 1'b1;
end
//VGA行场同步信号
assign vga_hs = (x_cnt < Hor_Sync) ? 1'b1 : 1'b0;
assign vga_vs = (y_cnt < Ver_Sync) ? 1'b1 : 1'b0;
//VGA输出
reg vga_en;
always@(*)
begin
vga_en <= (x_cnt > (Hor_Sync + Hor_Back_Porch) && x_cnt <= (Hor_Sync + Hor_Back_Porch + Hor_Addr_Time) && y_cnt > (Ver_Sync + Ver_Back_Porch) && y_cnt <= (Ver_Sync + Ver_Back_Porch + Ver_Addr_Time));
end
assign vga_rgb = (vga_en) ? pixel_data : 16'd0;
assign x_pixel = (vga_en) ? (x_cnt - (Hor_Sync + Hor_Back_Porch) ) : 10'd0;
assign y_pixel = (vga_en) ? (y_cnt - (Ver_Sync + Ver_Back_Porch) ) : 10'd0;
endmodule
模块介绍_vga_display
控制每一行,每一列的像素点作为输入,输出位像素数据。display1为方框移动
module vga_display1(vga_clk,rst_n,
x_pixel,y_pixel,pixel_data
);
//---------------------------------
input vga_clk ;
input rst_n ;
input [9:0] x_pixel ;
input [9:0] y_pixel ;
//---------------------------------
output reg [15:0] pixel_data;
//---------------------------------
parameter side = 10'd40 ; //边框
parameter block = 10'd40 ; //方格
//---------------------------------
//---------------------------------
parameter Hor_Total_Time = 10'd800 ; //行显示帧长
parameter Hor_Sync = 10'd96 ; //行同步脉冲
parameter Hor_Back_Porch = 10'd48 ; //行显示后沿(同显示前沿,这里由两个时段合成)
parameter Hor_Addr_Time = 10'd640 ; //行显示区域
parameter Hor_Front_Porch = 10'd16 ; //行显示前沿
//---------------------------------
parameter Ver_Total_Time = 10'd525 ; //列显示帧长
parameter Ver_Sync = 10'd2 ; //列同步脉冲
parameter Ver_Back_Porch = 10'd33 ; //列显示后沿(同显示前沿,这里由两个时段合成)
parameter Ver_Addr_Time = 10'd480 ; //列显示区域
parameter Ver_Front_Porch = 10'd10 ; //列显示前沿
//---------------------------------
parameter white = 16'b11111_111111_11111 ;
parameter black = 16'b00000_000000_00000 ;
parameter red = 16'b11111_000000_00000 ;
parameter green = 16'b00000_111111_00000 ;
parameter bule = 16'b00000_000000_11111 ;
//---------------------------------
reg [24:0] cnt_1s; //25_000_000 12_500_000
reg move_en;
always@(posedge vga_clk or negedge rst_n )
begin
if(!rst_n)
begin
cnt_1s <= 25'd1;
move_en <= 1'b0;
end
else
if(cnt_1s == 25'd25_000_000)
begin
cnt_1s <= 25'd1;
move_en <= 1'b1;
end
else
begin
cnt_1s <= cnt_1s + 1'b1;
move_en <= 1'b0;
end
end
reg [9:0] block_x;
reg [9:0] block_y;
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
begin
block_x <= 10'd40;
block_y <= 10'd40;
end
else
if(move_en)
begin
if(block_x == 10'd520 && block_y == 10'd360 )
begin
block_x <= 10'd40;
block_y <= 10'd40;
end
else
if(block_x == 10'd520)
begin
block_y <= block_y + 10'd80;
block_x <= 10'd40;
end
else
block_x <= block_x + 10'd80;
end
end
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
pixel_data <= black;
else
if(x_pixel <= ( side - 1'b1 ) || x_pixel >= (560 + side - 1'b1) || y_pixel <= side - 1'b1 || y_pixel >= (400 + side - 1'b1) )
pixel_data <= bule;
else
if(x_pixel >= ( block_x - 1'b1 ) && (block_x + 10'd80) >= x_pixel && y_pixel >= ( block_y - 1'b1 ) && y_pixel <= (block_y + 10'd80) )
pixel_data <= black;
else
pixel_data <= white;
end
endmodule
display为彩条显示
module vga_display(
vga_clk,rst_n,
x_pixel,y_pixel,pixel_data
);
//---------------------------------
input vga_clk ;
input rst_n ;
input [9:0] x_pixel ;
input [9:0] y_pixel ;
//---------------------------------
output reg [15:0] pixel_data;
//---------------------------------
parameter Hor_Addr_Time = 10'd640 ; //行显示区域
parameter Ver_Addr_Time = 10'd480 ; //列显示区域
//---------------------------------
parameter white = 16'b11111_111111_11111 ;
parameter black = 16'b00000_000000_00000 ;
parameter red = 16'b11111_000000_00000 ;
parameter green = 16'b00000_111111_00000 ;
parameter bule = 16'b00000_000000_11111 ;
//---------------------------------
//判断行和场的像素位置输出控制颜色
always@(posedge vga_clk or negedge rst_n)
begin
if(!rst_n)
pixel_data <= 16'd0;
else
if(x_pixel <= (Hor_Addr_Time / 5 - 1'b1 ) * 1 )
pixel_data <= white;
else
if(x_pixel <= (Hor_Addr_Time / 5 - 1'b1 ) * 2 )
pixel_data <= black;
else
if(x_pixel <= (Hor_Addr_Time / 5 - 1'b1 ) * 3 )
pixel_data <= red;
else
if(x_pixel <= (Hor_Addr_Time / 5 - 1'b1 ) * 4 )
pixel_data <= green;
else
pixel_data <= bule;
end
endmodule
模块介绍_vga_top
module top_vga(clk,rst_n,
vga_hs,vga_vs,
vga_rgb
);
input clk ;
input rst_n;
output vga_hs;
output vga_vs;
output [15:0] vga_rgb;
wire [9:0] w_x_pixel;
wire [9:0] w_y_pixel;
wire w_clk;
wire [15:0] pixel_data;
div_clk A(
.clk (clk ),
.rst_n (rst_n ),
.div_clk (w_clk )
);
vga_driver B(
.vga_clk (w_clk ),
.rst_n (rst_n ),
.pixel_data (pixel_data ),
.vga_hs (vga_hs ),
.vga_vs (vga_vs ),
.vga_rgb (vga_rgb ),
.x_pixel (w_x_pixel ),
.y_pixel (w_y_pixel )
);
vga_display1 C(
.vga_clk (w_clk ),
.rst_n (rst_n ),
.x_pixel (w_x_pixel ),
.y_pixel (w_y_pixel ),
.pixel_data (pixel_data )
);
endmodule