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
posted @ 2021-02-20 11:52  AdriftCore  阅读(1584)  评论(0编辑  收藏  举报