module vga_ctrl(
input wire vga_clk ,
input wire vga_rst_n ,
input wire [15:00] pix_data ,
output wire hsync ,
output wire vsync ,
output wire [ 9: 0] pix_x ,
output wire [ 9: 0] pix_y ,
output wire [15:00] rgb
);
parameter H_SYNC = 10'd96 ,
H_BACK = 10'd40 ,
H_LEFT = 10'd8 ,
H_VALID = 10'd640 ,
H_RIGHT = 10'd8 ,
H_FORNT = 10'd8 ,
H_TOTAL = 10'd800 ;
parameter V_SYNC = 10'd2 ,
V_BACK = 10'd25 ,
V_TOP = 10'd8 ,
V_VALID = 10'd480 ,
V_BOTTOM= 10'd8 ,
V_FRONT = 10'd2 ,
V_TOTAL = 10'd525 ;
// reg define signal
reg [9:0] cnt_h ;
reg [9:0] cnt_v ;
wire rgb_valid ;
wire rgb_valid_req ;
// [9:0] cnt_h : period counter for line signal ,0 ~ 799
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
cnt_h <= 10'd0 ;
end else begin
if(cnt_h == H_TOTAL - 1'b1) begin
cnt_h <= 10'd0 ;
end else begin
cnt_h <= cnt_h + 1'b1 ;
end
end
end
// [9:0] cnt_v ; period counter field scan 0 ~ 524. “行”计数1次,“场”计数+1。
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
cnt_v <= 10'd0 ;
end else begin
if((cnt_h == H_TOTAL - 1'b1) && (cnt_v == V_TOTAL - 1'b1)) begin
cnt_v <= 10'd0 ;
end else begin
if(cnt_h == H_TOTAL - 1'b1) begin
cnt_v <= cnt_v + 1'b1 ;
end else begin
cnt_v <= cnt_v ;
end
end
end
end
// rgb_valid 两个周期计数器,都计数到“有效图像周期”内,rgb_valid 拉高。
assign rgb_valid = (cnt_h <= H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1)
&& (cnt_h >= H_SYNC + H_BACK + H_LEFT)
&& (cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v <= V_SYNC + V_BACK + V_TOP + V_VALID - 1'b1) ? 1'b1 : 1'b0 ;
assign rgb_valid_req = (cnt_h <= H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1)
&& (cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1 )
&& (cnt_v >= V_SYNC + V_BACK + V_TOP)
&& (cnt_v <= V_SYNC + V_BACK + V_TOP + V_VALID - 1'b1) ? 1'b1 : 1'b0 ;
// out_signal_describe
// hsync , 行同步信号,只有在“行同步周期”内才拉高
assign hsync = ((cnt_h <= H_SYNC - 1'b1) && (cnt_h >= 10'd0)) ? 1'b1 : 1'b0 ;
// vsync , 场同步信号, 只有在“场同步周期”内才拉高
assign vsync = ((cnt_v <= V_SYNC - 1'b1) && (cnt_v >= 10'd0)) ? 1'b1 : 1'b0 ;
// pix_x , 像素横坐标, 只有在rgb_valid_req 拉高才进行扫描。0 ~ 639。 等于行计数器(144 ~ 783) - 前面三个阶段的计数 (144).
assign pix_x = (rgb_valid_req == 1'b1) ? cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1) : 10'h3ff ;
// pix_y , 像素纵坐标, 只有在rgb_valid_req 拉高才进行扫描。0 ~ 479。 等于场计数器(35 ~ 514 ) - 前面三个阶段的计数 (35) .
assign pix_y = (rgb_valid_req == 1'b1) ? cnt_v - (V_SYNC + V_BACK + V_TOP) : 10'h3ff ;
// [15:00] rgb 只有在valid == 1 时,进行像素赋值
assign rgb = (rgb_valid_req == 1'b1) ? pix_data : 10'd0 ;
endmodule
`timescale 1ns/1ns
module test_vga_ctrl ();
reg sys_clk_50m ;
reg sys_rst_n ;
reg [15:00] pix_data ;
wire vga_clk ;
wire locked ;
wire vga_rst_n ;
assign vga_rst_n = sys_rst_n && locked;
wire hsync ;
wire vsync ;
wire [ 9: 0] pix_x ;
wire [ 9: 0] pix_y ;
wire [15:00] rgb ;
pll_25m pll_25m_inst (
.areset ( ~sys_rst_n ),
.inclk0 ( sys_clk_50m ),
.c0 ( vga_clk ),
.locked ( locked )
);
vga_ctrl vga_ctrl_insert(
.vga_clk ( vga_clk ) ,
.vga_rst_n ( vga_rst_n) ,
.pix_data ( pix_data ) ,
.hsync ( hsync ) ,
.vsync ( vsync ) ,
.pix_x ( pix_x ) ,
.pix_y ( pix_y ) ,
.rgb ( rgb )
); // 640X480@60
parameter CYCLE = 20 ;
initial begin
sys_clk_50m = 1'b1 ;
sys_rst_n <= 1'b0 ;
pix_data <= 16'd0 ;
#(CYCLE * 2) ;
sys_rst_n <= 1'b1 ;
#(CYCLE * 10000) ;
end
always #(CYCLE / 2) sys_clk_50m = ~sys_clk_50m ;
// pix_data
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
pix_data <= 16'd0 ;
end else begin
if(pix_x >= 10'd0 && pix_x <= 10'd639 && pix_y >= 10'd0 && pix_y <= 10'd479) begin
pix_data <= 16'hffff ;
end else begin
pix_data <= 16'd0 ;
end
end
end
// assign pix_data = (pix_x >= 10'd0 && pix_x <= 10'd639 && pix_y >= 10'd0 && pix_y <= 10'd479) ? 16'hffff : 16'd0 ;
endmodule
坐标不重要。要让vga_rgb 和vga_valid时序对齐。
虽然横坐标看上去多了一个,但是vga_valid 和cnt_h (144 ~ 783)对齐了,那就是对的。
还差一个模块,明天写。
数据产生模块:
module vga_pix (
input wire vga_clk ,
input wire vga_rst_n ,
input wire [9:0] pix_x ,
input wire [9:0] pix_y ,
output reg [15:0] pix_data
);
// parameter H_VALID = 10'd640 ,
// V_VALID = 10'd480 ;
parameter RED = 16'hF800 ,
ORANGE = 16'hFC00 ,
YELLOW = 16'hFFe0 ,
GREEN = 16'h07e0 ,
QING = 16'h07FF ,
BLUE = 16'h001F ,
PURPLE = 16'hF81F ,
BLACK = 16'h0000 ,
WHITE = 16'hFFFF ,
GRAY = 16'hD69A ;
// output signal
always @(posedge vga_clk or negedge vga_rst_n) begin
if(~vga_rst_n) begin
pix_data <= 10'h3ff ;
end else begin // 有简便写法 ( H_VALID / 10 ) * n
if((pix_x >= 10'd0) && (pix_x <= 10'd63))
pix_data <= RED ;
else
if((pix_x >= 10'd64) && (pix_x <= 10'd127))
pix_data <= ORANGE ;
else
if((pix_x >= 10'd128) && (pix_x <= 10'd191))
pix_data <= YELLOW ;
else
if((pix_x >= 10'd192) && (pix_x <= 10'd255))
pix_data <= GREEN ;
else
if((pix_x >= 10'd256) && (pix_x <= 10'd319))
pix_data <= QING ;
else
if((pix_x >= 10'd320) && (pix_x <= 10'd383))
pix_data <= BLUE ;
else
if((pix_x >= 10'd384) && (pix_x <= 10'd447))
pix_data <= PURPLE ;
else
if((pix_x >= 10'd448) && (pix_x <= 10'd511))
pix_data <= BLACK ;
else
if((pix_x >= 10'd512) && (pix_x <= 10'd575))
pix_data <= WHITE ;
else
if((pix_x >= 10'd576) && (pix_x <= 10'd639))
pix_data <= GRAY ;
else
pix_data <= BLACK ;
end
end
endmodule
`timescale 1ns/1ns
module test_top ();
reg sys_clk ;
reg sys_rst_n ;
wire [15:00] rgb ;
wire hsync ;
wire vsync ;
top_vga top_vga_insert(
.sys_clk ( sys_clk ) ,
.sys_rst_n ( sys_rst_n ) ,
.rgb ( rgb ) ,
.hsync ( hsync ) ,
.vsync ( vsync )
);
parameter CYCLE = 20 ;
initial begin
sys_clk = 1'b1 ;
sys_rst_n <= 1'b0 ;
#(CYCLE * 2) ;
sys_rst_n <= 1'b1 ;
#(CYCLE * 10000) ;
end
always #(CYCLE / 2) sys_clk = ~sys_clk ;
endmodule
修改一下,虽然从仿真结果上看,rgb赋值用这两个valid信号都是一样的。
但是从逻辑上看,确实要用 rgb_valid 赋值才是正确的。