FPGA——OV5640攝像頭DVP接口實現及仿真


一、設計思路

行同步計數器
場同步計數器
圖像幀數計數器
攝像頭輸出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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM