一、設計思路
行同步計數器
場同步計數器
圖像幀數計數器
攝像頭輸出3*3像素圖像的輸入信號圖解
場信號vsync脈沖,表示一幀圖像的開始
行信號hsync有效(高有效),攝像頭輸出數據
一個像素是16位數據,傳入一次是8位數據,所有一個像素傳了6次數據
二、代碼實現
module dvp_capture(
rst_n ,
clk ,
vsync ,
hsync ,
data ,
pix_data ,
image_state ,
haddr ,
vaddr ,
data_vld
);
parameter IMAGE_WIDTH = 800;
parameter IMAGE_HEIGHT = 480;
localparam DATA_W = 8;
localparam DATA_PIX = 16;
localparam HADDR_W = 12;
localparam VADDR_W = 12;
input rst_n;
input clk;
input vsync; //場同步信號
input hsync; //行同步信號
input [DATA_W-1:0] data;
output [DATA_PIX-1:0] pix_data; //攝像頭輸出的565像素數據
output image_state; //攝像頭初始化完成開始輸出數據標志信號
output [HADDR_W-1:0] haddr; //行地址
output [VADDR_W-1:0] vaddr; //場地址
output data_vld; //輸出數據有效信號
reg [DATA_PIX-1:0] pix_data; //攝像頭輸出的565像素數據
reg image_state; //攝像頭初始化完成開始輸出數據標志信號
reg [HADDR_W-1:0] haddr; //行地址
reg [VADDR_W-1:0] vaddr; //場地址
reg data_vld; //輸出數據有效信號
//中間變量
reg pre_vsync;
reg pre_hsync;
reg [DATA_W-1:0] pre_data;
//計數器變量
reg [HADDR_W-1:0] cnt_hsync;
wire add_cnt_hsync;
wire end_cnt_hsync;
reg [VADDR_W-1:0] cnt_vsync;
wire add_cnt_vsync;
wire end_cnt_vsync;
reg [4-1:0] cnt_frame;
wire add_cnt_frame;
wire end_cnt_frame;
reg output_frame;
//打一拍,快速IO,優化時序,邊沿檢測
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
pre_vsync <= 0;
pre_hsync <= 0;
pre_data <= 0;
end
else begin
pre_vsync <= vsync;
pre_hsync <= hsync;
pre_data <= data;
end
end
//行同步計數器,行同步有效時加1,行同步信號失效時結束
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_hsync <= 0;
else if(add_cnt_hsync)begin
if(end_cnt_hsync)
cnt_hsync <= 0;
else
cnt_hsync <= cnt_hsync + 1'b1;
end
end
assign add_cnt_hsync = pre_hsync;
assign end_cnt_hsync = add_cnt_hsync && {pre_hsync,hsync} == 2'b10;
//場同步信號計數器,行同步計數完成時加1,場同步達到要求的像素值結束,當輸出圖像不穩定在場同步拉高時清0,
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_vsync <= 0;
else if(add_cnt_vsync)begin
if(end_cnt_vsync)
cnt_vsync <= 0;
else
cnt_vsync <= cnt_vsync + 1'b1;
end
else if({pre_vsync,vsync} == 2'b01)
cnt_vsync <= 0;
end
assign add_cnt_vsync = end_cnt_hsync;
assign end_cnt_vsync = add_cnt_vsync && cnt_vsync == IMAGE_HEIGHT - 1;
//圖像幀數計數器,出現場同步信號脈沖時加一,數到十幀圖像結束
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_frame <= 0;
else if(add_cnt_frame)begin
if(end_cnt_frame)
cnt_frame <= 0;
else
cnt_frame <= cnt_frame + 1'b1;
end
end
assign add_cnt_frame = {pre_vsync,vsync} == 2'b10 && !output_frame;
assign end_cnt_frame = add_cnt_frame && cnt_frame == 10 - 1;
//舍棄每次系統開始運行后的前 10 幀圖像的數據,以確保輸出圖像穩定
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
output_frame <= 0;
else if(end_cnt_frame)
output_frame <= 1;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
pix_data <= 0;
else
pix_data <= {pix_data[7:0],pre_data};
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
data_vld <= 0;
else if(cnt_hsync[0] == 1 && add_cnt_hsync && output_frame)
data_vld <= 1;
else
data_vld <= 0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
image_state <= 0;
else if(pre_vsync)
image_state <= 1;
else if(end_cnt_vsync)
image_state <= 0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
vaddr <= 0;
else
vaddr <= cnt_vsync;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
haddr <= 0;
else
haddr = cnt_hsync[7:1];
end
endmodule
三、仿真驗證
`timescale 1ns/1ns
module dvp_capture_tb();
//時鍾周期,單位ns,在這里修改時鍾周期
parameter CYCLE = 80;
//復位時間,此時表示復位3個時鍾周期的時間
parameter RST_TIME = 3;
parameter WIDTH = 3;
parameter HIGHT = 3;
localparam DATA_W = 8;
localparam DATA_PIX = 16;
localparam HADDR_W = 12;
localparam VADDR_W = 12;
reg rst_n;
reg clk;
reg vsync; //場同步信號
reg hsync; //行同步信號
reg [DATA_W-1:0] data;
wire [DATA_PIX-1:0] pix_data; //攝像頭輸出的565像素數據
wire image_state; //攝像頭初始化完成開始輸出數據標志信號
wire [HADDR_W-1:0] haddr; //行地址
wire [VADDR_W-1:0] vaddr; //場地址
wire data_vld; //輸出數據有效信
dvp_capture #(
.IMAGE_WIDTH(WIDTH) ,
.IMAGE_HEIGHT(HIGHT)
)
dvp_capture(
.rst_n (rst_n),
.clk (clk),
.vsync (vsync),
.hsync (hsync),
.data (data),
.pix_data (pix_data),
.image_state (image_state),
.haddr (haddr),
.vaddr (vaddr),
.data_vld (data_vld)
);
//生成本地時鍾50M
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
//產生復位信號
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE * RST_TIME);
rst_n = 1;
end
integer i = 0;
integer j = 0;
//輸入信號din0賦值方式
initial begin
#1;
data = 8'hff;
vsync = 0;
hsync = 0;
#(10*CYCLE);
//開始賦值
repeat(15)begin
vsync = 1;
#(10*CYCLE)
vsync = 0;
#(20*CYCLE)
for(i = 0;i < HIGHT;i = i + 1)begin
for(j = 0;j < (WIDTH<<1);j = j + 1)begin
hsync = 1;
data = data - 1;
#80;
end
hsync = 0;
#(20*CYCLE);
end
end
#1000
$stop;
end
endmodule