-01-摄像头DVP输入IP核设计【OV5640】

在之前设计的OV5640输入接口逻辑上完善了一下代码,暂时出一版IP来用。

DVP Timing

首先看看OV5640的DVP信号时序:
这里写图片描述

先不考虑每个信号的具体时序,大致看一看他的波形,可以发现,这是一个很标准的时序。VSYNC是场同步信号,在图像数据发送之前会有一个高电平脉冲;HREF是数据有效信号,高电平时时代表D[9:0]的数据信号有效,可以理解为DE或者Data_valid;HSYNC是行同步信号,我们有了HREF就不需要这个信号了;D[9:0]是并口数据;以上四个信号都同步于摄像头的PCLK信号。

因为DVP这个并口的时序十分标准,其实是可以直接接入fpga内,并借用Xilinx的Video In to AXI4-Stream IP核实现并口到AXI4S总线的转换的。

RGB565

OV5640支持 RawRGB、 RGB(RGB565/RGB555/RGB444)、 CCIR656、 YUV(422/420)、 YCbCr( 422)和压缩图像( JPEG)输出格式。我们今后可能用到的格式包括:RawRGB、RGB565、YUV422、JPEG四种格式。
为了快速验证摄像头功能,选择了RGB565格式,因为Raw格式需要插值、YUV需要色彩空间转换、JPEG需要解码··总之都麻烦。而RGB565一个像素有16位数据,想要通过8位数据线将像素信号发送出来,只能通过两个PCLK时钟发送出来,每 2 个字节组成一个像素的颜色(低字节在前,高字节在后)。

图像尺寸测量

当通过I2C初始化摄像头后,DVP时序就能够正常输出了,但是为了确保输出的信号是稳定的,我们从接口中捕获10帧的图像,并测试输入图像的尺寸大小。
一来可以用来检测图像数据是否稳定和正常(尺寸大小是否发生了变化),二来测量出了输入图像的尺寸可以方便后面的缓存管理、图像边界识别。

以上的两个部分的功能写出RTL代码后,再结合Video In to AXI4-Stream IP核,即完成了DVP输入IP核的设计。Video In to AXI4-Stream IP的功能实现可以在vivado中看它的源码,还是很好理解的,可以选择直接使用它或者参照它的实现方法自行设计。

Custom IP的使用

生成的dvp_2_axi4s IP核按下图连接:
这里写图片描述

视频数据流按如下方式进入DDR缓存
DVP接口 -> dvp_2_axi4s -> axi vdma -> axi interconnect -> zynq -> DDR3

总结

代码可以从这里下载: https://coding.net/u/vacajk/p/zybo_ov5640_stereo_camera/git

也可以直接下载我整理好的:稍后上传>>

附:RTL代码

dvp_capture.v

`timescale 1ns / 1ps
//
// Company:
// Engineer: vacajk
//
// Create Date: 2017/03/15 23:48:18
// Design Name:
// Module Name: dvp_capture
// Project Name:
// Target Devices:
// Tool Versions: vivado 2016.3
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//


module dvp_capture #(
  parameter FPGA_FAMILY         = "zynq7000",
  parameter DVP_DATA_FORMAT     = "RGB565",
  parameter DVP_TIMING_ADJ_EN   = "ENABLE",
  parameter DVP_TIMING_ADJ_CNT  = 4'd10,
  parameter DVP_FRAME_WAIT_CNT  = 4'd10,
  parameter DVP_XVCLK_OUT_EN    = "ENABLE"
  ) (
  //_____________________________________________ system clock
  input iCLK,
  input iRST_n,
  //_____________________________________________ module control
  input capture_en,
  output capture_stable,
  output capture_failure,
  output [11:0] capture_h_size,
  output [11:0] capture_v_size,
  //_____________________________________________ DVP interface
  output CAM_XVCLK,
  input CAM_PCLK,
  input CAM_HREF,
  input CAM_VSYNC,
  input [7:0] CAM_D,
  //_____________________________________________ parallel signals
  output rx_pclk,
  output rx_href,
  output rx_vsync,
  output [23:0] rx_data
  );

/**********************************************
 * DVP timing diagram
 *        _
 * VS____| |__________________________________
 *               ______         ______
 * HS___________|      |__...__|      |_______
 *
 *
 **********************************************/

//_____________________________________________ external DVP interface, use IBUF and OBUF
wire cam_xvclk_o;
assign cam_xvclk_o = 1'b0;
wire cam_pclk_i;
wire cam_href_i;
wire cam_vsync_i;
wire [7:0] cam_d_i;

//_____________________________________________ camera input interface IBUF
generate    //FPGA_FAMILY
if (FPGA_FAMILY == "zynq7000")      //FPGA_FAMILY
    begin
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),    // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
          .IOSTANDARD("DEFAULT")    // Specify the input I/O standard
        ) CAM_PCLK__IBUF_inst (
          .O(cam_pclk_i),           // Buffer output
          .I(CAM_PCLK)              // Buffer input (connect directly to top-level port)
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_HREF_IBUF_inst (
          .O(cam_href_i),
          .I(CAM_HREF)
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_VSYNC_IBUF_inst (
          .O(cam_vsync_i),
          .I(CAM_VSYNC)
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D0_IBUF_inst (
          .O(cam_d_i[0]),
          .I(CAM_D[0])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D1_IBUF_inst (
          .O(cam_d_i[1]),
          .I(CAM_D[1])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D2_IBUF_inst (
          .O(cam_d_i[2]),
          .I(CAM_D[2])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D3_IBUF_inst (
          .O(cam_d_i[3]),
          .I(CAM_D[3])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D4_IBUF_inst (
          .O(cam_d_i[4]),
          .I(CAM_D[4])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D5_IBUF_inst (
          .O(cam_d_i[5]),
          .I(CAM_D[5])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D6_IBUF_inst (
          .O(cam_d_i[6]),
          .I(CAM_D[6])
        );
        IBUF #(
          .IBUF_LOW_PWR("TRUE"),
          .IOSTANDARD("DEFAULT")
        ) CAM_D7_IBUF_inst (
          .O(cam_d_i[7]),
          .I(CAM_D[7])
        );
    end
else    //FPGA_FAMILY
    begin
        assign cam_pclk_i   = CAM_PCLK;
        assign cam_href_i   = CAM_HREF;
        assign cam_vsync_i  = CAM_VSYNC;
        assign cam_d_i      = CAM_D;
    end
endgenerate //FPGA_FAMILY

//_____________________________________________ camera output xvclk OBUF
generate
if((FPGA_FAMILY == "zynq7000") && (DVP_XVCLK_OUT_EN == "ENABLE"))   //FPGA_FAMILY
    OBUF #(
        .DRIVE(12),             // Specify the output drive strength
        .IOSTANDARD("DEFAULT"), // Specify the output I/O standard
        .SLEW("SLOW")           // Specify the output slew rate
    ) CAM_XVCLK_OBUF_inst (
        .O(CAM_XVCLK),          // Buffer output (connect directly to top-level port)
        .I(cam_xvclk_o)         // Buffer input
    );
else if(DVP_XVCLK_OUT_EN == "ENABLE")
    assign CAM_XVCLK = cam_xvclk_o;
else
    assign CAM_XVCLK = 1'b0;
endgenerate


wire cam_rst_n;
assign cam_rst_n = iRST_n;

reg capture_en_1 = 1'b0;
reg capture_en_2 = 1'b0;
//_____________________________ capture_en shift -> _r
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) capture_en_1 <= 1'b0;
    else                        capture_en_1 <= capture_en;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) capture_en_2 <= 1'b0;
    else                        capture_en_2 <= capture_en_1;

//_____________________________________________ camera sync signals edge
reg cam_href_1 = 1'b0;
reg cam_href_2 = 1'b0;
reg cam_href_3 = 1'b0;
reg cam_vsync_1 = 1'b0;
reg cam_vsync_2 = 1'b0;
reg cam_vsync_3 = 1'b0;
reg [7:0] cam_d_1 = 8'b0;
reg [7:0] cam_d_2 = 8'b0;
reg [7:0] cam_d_3 = 8'b0;
wire [1:0] cam_href_edge;
wire [1:0] cam_vsync_edge;
wire cam_href_rising;
wire cam_href_falling;
wire cam_vsync_rising;
wire cam_vsync_falling;
//_____________________________ cam_href_i shift -> _1
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_href_1 <= 1'b0;
    else                        cam_href_1 <= cam_href_i;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_href_2 <= 1'b0;
    else                        cam_href_2 <= cam_href_1;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_href_3 <= 1'b0;
    else                        cam_href_3 <= cam_href_2;
//_____________________________ cam_vsync_i shift -> _1
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_vsync_1 <= 1'b0;
    else                        cam_vsync_1 <= cam_vsync_i;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_vsync_2 <= 1'b0;
    else                        cam_vsync_2 <= cam_vsync_1;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_vsync_3 <= 1'b0;
    else                        cam_vsync_3 <= cam_vsync_2;
//_____________________________ cam_d_i shift -> _1
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_d_1 <= 8'b0;
    else                        cam_d_1 <= cam_d_i;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_d_2 <= 8'b0;
    else                        cam_d_2 <= cam_d_1;
always@(posedge cam_pclk_i, negedge cam_rst_n)
    if(~cam_rst_n) cam_d_3 <= 8'b0;
    else                        cam_d_3 <= cam_d_2;

//_____________________________ cam_href_i cam_vsync_i edge
assign cam_href_edge            = {cam_href_2, cam_href_1};
assign cam_vsync_edge           = {cam_vsync_2, cam_vsync_1};
assign cam_href_rising      = ((capture_en_2 == 1'b1) && (cam_href_edge     == 2'b01))? 1'b1: 1'b0;
assign cam_href_falling     = ((capture_en_2 == 1'b1) && (cam_href_edge     == 2'b10))? 1'b1: 1'b0;
assign cam_vsync_rising     = ((capture_en_2 == 1'b1) && (cam_vsync_edge    == 2'b01))? 1'b1: 1'b0;
assign cam_vsync_falling    = ((capture_en_2 == 1'b1) && (cam_vsync_edge    == 2'b10))? 1'b1: 1'b0;



reg rx_href_o = 1'b0;
reg rx_vsync_o = 1'b0;
reg [23:0] rx_data_o = 24'b0;

reg pixel_odd_even_flag_1 = 1'b0;
reg pixel_odd_even_flag_2 = 1'b0;
reg cam_pclk_div2_stable = 1'b0;
wire cam_pclk_div2;
generate    //DVP_DATA_FORMAT
if(DVP_DATA_FORMAT == "RGB565") //DVP_DATA_FORMAT
    begin
        //_____________________________________________ pixel_odd_even_flag
        //change ov5640 rgb565 two clock per pixel to rgb888 parallel data
        always@(posedge cam_pclk_i)
            if(~capture_stable)
                pixel_odd_even_flag_1 <= 1'b0;
            else if(cam_href_1)
                pixel_odd_even_flag_1 <= ~pixel_odd_even_flag_1;
            else
                pixel_odd_even_flag_1 <= 1'b0;

        //_____________________________________________ pixel_odd_even_flag_2
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            if(~cam_rst_n) pixel_odd_even_flag_2 <= 1'b0;
            else                        pixel_odd_even_flag_2 <= pixel_odd_even_flag_1;

        //ov5640 rgb565 data from dvp: {r[4:0], g[5:3]} {g[2:0], b[4:0]}
        reg [4:0] rx_data_red = 5'b0;
        reg [5:0] rx_data_green = 6'b0;
        reg [4:0] rx_data_blue = 5'b0;
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            if(cam_rst_n & ~capture_stable)
                begin
              rx_data_red <= 5'b0;
              rx_data_green <= 6'b0;
              rx_data_blue <= 5'b0;
                end
          else if(cam_href_1)
                if(~pixel_odd_even_flag_1)
                    begin
                        rx_data_blue <= cam_d_1[4:0];
                        rx_data_green[2:0] <= cam_d_1[7:5];
                    end
                else
                    begin
                        rx_data_green[5:3] <= cam_d_1[2:0];
                        rx_data_red <= cam_d_1[7:3];
                    end
          else
            begin
              rx_data_red <= 5'b0;
              rx_data_green <= 6'b0;
              rx_data_blue <= 5'b0;
            end

        //RGB Data Encoding referenced by m_axis_video_tdata of v_vid IP {R[7:0], B[7:0], G[7:0]}
        always@(posedge cam_pclk_div2, negedge cam_rst_n)
            if(cam_rst_n & ~capture_stable)
                rx_data_o <= 24'b0;
            else if(cam_href_2)
                rx_data_o <= {rx_data_red, 3'b000, rx_data_blue, 3'b000, rx_data_green, 2'b00};
            else
                rx_data_o <= 24'b0;

        always@(posedge cam_pclk_div2, negedge cam_rst_n)
            if(cam_rst_n & ~capture_stable)
                begin
                    rx_href_o <= 1'b0;
                    rx_vsync_o <= 1'b0;
                end
            else
                begin
                rx_href_o <= cam_href_3;
                rx_vsync_o <= cam_vsync_3;
                end

        assign rx_pclk = cam_pclk_div2;
    end
else //raw data
    begin
        always@(posedge cam_pclk_i)
            if(cam_rst_n & ~capture_stable)
                begin
                    rx_href_o <= 1'b0;
                    rx_vsync_o <= 1'b0;
                    rx_data_o <= 24'b0;
                end
            else
                begin
                    rx_href_o <= cam_href_3;
                    rx_vsync_o <= cam_vsync_3;
                    rx_data_o <= {16'b0, cam_d_3};
                end

        assign rx_pclk = cam_pclk_i;
    end
endgenerate

generate    //FPGA_FAMILY
if((DVP_DATA_FORMAT == "RGB565") && (FPGA_FAMILY == "zynq7000"))
    begin
        reg cam_pclk_div2_clr = 1'b1;
        BUFR #(
            .BUFR_DIVIDE("2"),          // Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8"
            .SIM_DEVICE("7SERIES")  // Must be set to "7SERIES"
        ) CAM_PCLK_DIV2_BUFR_inst (
            .O(cam_pclk_div2),              // 1-bit output: Clock output port
            .CE(1'b1),                              // 1-bit input: Active high, clock enable (Divided modes only)
            .CLR(cam_pclk_div2_clr),    // 1-bit input: Active high, asynchronous clear (Divided modes only)
            .I(cam_pclk_i)                      // 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
        );

        always@(posedge cam_pclk_i, negedge cam_rst_n)
            if(cam_rst_n & ~capture_stable)
                begin
                    cam_pclk_div2_clr <= 1'b1;
                    cam_pclk_div2_stable <= 1'b0;
                end
            else if (cam_pclk_div2_stable == 1'b0)
                begin
                    cam_pclk_div2_clr <= 1'b1;
                    if(pixel_odd_even_flag_1 == 1'b1)
                        begin
                            cam_pclk_div2_clr <= 1'b0;
                            cam_pclk_div2_stable <= 1'b1;
                        end
                end
            else
                begin
                    cam_pclk_div2_clr <= 1'b0;
                    cam_pclk_div2_stable <= 1'b1;
                end
    end
else    //DVP_DATA_FORMAT RAW
    begin
        reg cam_pclk_div2_r = 1'b0;
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            if(cam_rst_n & ~capture_stable)
                begin
                    cam_pclk_div2_r <= 1'b0;
                    cam_pclk_div2_stable <= 1'b0;
                end
            else if (cam_pclk_div2_stable == 1'b0)
                begin
                    cam_pclk_div2_r <= 1'b0;
                    if(pixel_odd_even_flag_1 == 1'b1)
                            cam_pclk_div2_stable <= 1'b1;
                end
            else
                    cam_pclk_div2_r <= ~cam_pclk_div2_r;
        assign cam_pclk_div2 = cam_pclk_div2_r;
    end
endgenerate

assign rx_href = rx_href_o;
assign rx_vsync = rx_vsync_o;
assign rx_data = rx_data_o;


reg pre_cap_stable = 1'b0;
reg [3:0] pre_f_pix_cnt = 4'b0;
generate    //DVP_TIMING_ADJ_EN
if(DVP_TIMING_ADJ_EN == "ENABLE")   //DVP_TIMING_ADJ_EN
    begin
        //_____________________________________________ camera sync signals edge
        //dvp pre capture, caculate the h and v size of video.
        reg sta_dvp_pre_waitv_jump                  = 1'b0;
        reg sta_dvp_pre_waitstable_hv_jump  = 1'b0;
        reg sta_dvp_pre_waitstable_f_jump       = 1'b0;
        reg sta_dvp_pre_done_jump                       = 1'b0;
        localparam STA_DVP_PRE_IDLE                         = 8'b00000001;
        localparam STA_DVP_PRE_WAITV                        = 8'b00000010;
        localparam STA_DVP_PRE_WAITSTABLE_HV        = 8'b00000100;
        localparam STA_DVP_PRE_WAITSTABLE_F         = 8'b00001000;
        localparam STA_DVP_PRE_DONE                         = 8'b00010000;
        localparam DVP_PRE_CNT_FAULT                        = 4'd10;
        reg [7:0] dvp_pre_current_state = STA_DVP_PRE_IDLE;
        reg [7:0] dvp_pre_next_state        = STA_DVP_PRE_IDLE;
        reg [11:0] pre_h_pix_cnt    = 12'b0;
        reg [11:0] pre_v_pix_cnt    = 12'b0;
        reg [11:0] pre_h_pix_size = 12'b0;
        reg [11:0] pre_v_pix_size = 12'b0;
        reg pre_cnt_fault   = 1'b0;
        reg [3:0] pre_hv_pix_size_diff  = 4'b0;
        //_____________________________________________ state machine
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            begin
                if(~cam_rst_n) dvp_pre_current_state <= STA_DVP_PRE_IDLE;
                else                        dvp_pre_current_state <= dvp_pre_next_state;
            end

        always@(*)
            begin
                dvp_pre_next_state = STA_DVP_PRE_IDLE;
                case(dvp_pre_current_state)
                    STA_DVP_PRE_IDLE:
                        if(sta_dvp_pre_waitv_jump)                  dvp_pre_next_state = STA_DVP_PRE_WAITV;
                        else                                                                dvp_pre_next_state = STA_DVP_PRE_IDLE;
                    STA_DVP_PRE_WAITV:
                        if(sta_dvp_pre_waitstable_hv_jump)  dvp_pre_next_state = STA_DVP_PRE_WAITSTABLE_HV;
                        else                                                                dvp_pre_next_state = STA_DVP_PRE_WAITV;
                    STA_DVP_PRE_WAITSTABLE_HV:
                        if(sta_dvp_pre_waitstable_f_jump)       dvp_pre_next_state = STA_DVP_PRE_WAITSTABLE_F;
                        else                                                                dvp_pre_next_state = STA_DVP_PRE_WAITSTABLE_HV;
                    STA_DVP_PRE_WAITSTABLE_F:
                        if(sta_dvp_pre_waitstable_hv_jump)  dvp_pre_next_state = STA_DVP_PRE_WAITSTABLE_HV;
                        else if(sta_dvp_pre_done_jump)          dvp_pre_next_state = STA_DVP_PRE_DONE;
                        else                                                                dvp_pre_next_state = STA_DVP_PRE_WAITSTABLE_F;
                    STA_DVP_PRE_DONE:
                        if(~capture_en_1)                                      dvp_pre_next_state = STA_DVP_PRE_IDLE;
                        else                                                                dvp_pre_next_state = STA_DVP_PRE_DONE;
                    default:
                        dvp_pre_next_state = STA_DVP_PRE_IDLE;
                endcase
            end
        //_____________________________ jump
        always@(posedge cam_pclk_i, negedge cam_rst_n) begin
            if(~cam_rst_n)
                begin
                    sta_dvp_pre_waitv_jump                  <= 1'b0;
                    sta_dvp_pre_waitstable_hv_jump  <= 1'b0;
                    sta_dvp_pre_waitstable_f_jump       <= 1'b0;
                    sta_dvp_pre_done_jump                       <= 1'b0;
                end
            else
                begin
                    sta_dvp_pre_waitv_jump                  <= 1'b0;
                    sta_dvp_pre_waitstable_hv_jump  <= 1'b0;
                    sta_dvp_pre_waitstable_f_jump       <= 1'b0;
                    sta_dvp_pre_done_jump                       <= 1'b0;
                    case(dvp_pre_next_state)
                        STA_DVP_PRE_IDLE:
                            if(capture_en_1)                                                    sta_dvp_pre_waitv_jump <= 1'b1;
                        STA_DVP_PRE_WAITV:
                            if(cam_vsync_falling)                                           sta_dvp_pre_waitstable_hv_jump <= 1'b1;
                        STA_DVP_PRE_WAITSTABLE_HV:
                            if(cam_vsync_rising)                                            sta_dvp_pre_waitstable_f_jump <= 1'b1;
                        STA_DVP_PRE_WAITSTABLE_F:
                            if(pre_f_pix_cnt >= DVP_TIMING_ADJ_CNT)     sta_dvp_pre_done_jump <= 1'b1;
                            else if(cam_vsync_falling)                              sta_dvp_pre_waitstable_hv_jump <= 1'b1;
                        STA_DVP_PRE_DONE:
                            begin
                                sta_dvp_pre_waitv_jump                  <= 1'b0;
                                sta_dvp_pre_waitstable_hv_jump  <= 1'b0;
                                sta_dvp_pre_waitstable_f_jump       <= 1'b0;
                                sta_dvp_pre_done_jump                       <= 1'b0;
                            end
                    default:
                        begin
                            sta_dvp_pre_waitv_jump                  <= 1'b0;
                            sta_dvp_pre_waitstable_hv_jump  <= 1'b0;
                            sta_dvp_pre_waitstable_f_jump       <= 1'b0;
                            sta_dvp_pre_done_jump                       <= 1'b0;
                        end
                    endcase
                end
        end

        //_____________________________
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            begin
                if(~cam_rst_n) begin
                    pre_cap_stable  <= 1'b0;
                    pre_h_pix_cnt       <= 12'd0;
                    pre_v_pix_cnt       <= 12'd0;
                    pre_h_pix_size  <= 12'd0;
                    pre_v_pix_size  <= 12'd0;
                    pre_f_pix_cnt       <= 4'd0;
                    pre_cnt_fault       <= 1'b0;
                    pre_hv_pix_size_diff        <= 4'd0;
                end
                else begin
                    if(pre_hv_pix_size_diff >= DVP_PRE_CNT_FAULT) pre_cnt_fault <= 1'b1;
                    case(dvp_pre_next_state)
                        STA_DVP_PRE_IDLE:
                            begin
                                pre_cap_stable  <= 1'b0;
                                pre_h_pix_cnt       <= 12'd0;
                                pre_v_pix_cnt       <= 12'd0;
                                pre_h_pix_size  <= 12'd0;
                                pre_v_pix_size  <= 12'd0;
                                pre_f_pix_cnt       <= 4'd0;
                                pre_cnt_fault       <= 1'b0;
                                pre_hv_pix_size_diff <= 4'd0;
                            end
                        STA_DVP_PRE_WAITV:
                            begin
                                pre_cap_stable  <= 1'b0;
                                pre_h_pix_cnt       <= 12'd0;
                                pre_v_pix_cnt       <= 12'd0;
                                pre_h_pix_size  <= 12'd0;
                                pre_v_pix_size  <= 12'd0;
                                pre_f_pix_cnt       <= 4'd0;
                                pre_cnt_fault       <= 1'b0;
                                pre_hv_pix_size_diff <= 4'd0;
                            end
                        STA_DVP_PRE_WAITSTABLE_HV:
                            begin
                                pre_h_pix_cnt       <= 12'd0;
                                if(cam_vsync_rising)
                                    begin
                                        pre_v_pix_cnt       <= 12'd0;
                                        pre_v_pix_size  <= pre_v_pix_cnt;
                                        pre_f_pix_cnt   <= pre_f_pix_cnt + 4'd1;
                                        if(pre_v_pix_size != pre_v_pix_cnt) pre_hv_pix_size_diff <= pre_hv_pix_size_diff + 4'd1;
                                    end
                                else if(cam_href_falling)
                                    begin
                                        pre_v_pix_cnt       <= pre_v_pix_cnt + 12'd1;
                                        pre_h_pix_size  <= pre_h_pix_cnt;
                                        if(pre_h_pix_size != pre_h_pix_cnt) pre_hv_pix_size_diff <= pre_hv_pix_size_diff + 4'd1;
                                    end
                                else if(cam_href_1) pre_h_pix_cnt <= pre_h_pix_cnt + 12'd1;
                            end
                        STA_DVP_PRE_WAITSTABLE_F:
                            if(cam_vsync_falling)
                                begin
                                    pre_h_pix_cnt <= 12'd0;
                                    pre_v_pix_cnt <= 12'd0;
                                end
                        STA_DVP_PRE_DONE:
                            pre_cap_stable <= 1'b1;
                    default:
                        begin
                            pre_cap_stable  <= 1'b0;
                            pre_h_pix_cnt       <= 12'd0;
                            pre_v_pix_cnt       <= 12'd0;
                            pre_h_pix_size  <= 12'd0;
                            pre_v_pix_size  <= 12'd0;
                            pre_f_pix_cnt       <= 4'd0;
                            pre_cnt_fault       <= 1'b0;
                            pre_hv_pix_size_diff        <= 4'd0;
                        end
                    endcase
                end
            end

        assign capture_failure  = pre_cnt_fault;
        assign capture_stable       = pre_cap_stable;
        assign capture_h_size       = pre_h_pix_size;
        assign capture_v_size       = pre_v_pix_size;
    end
else    //DVP_TIMING_ADJ_EN
    begin
        always@(posedge cam_pclk_i, negedge cam_rst_n)
            begin
                if(~cam_rst_n)
                    begin
                        pre_cap_stable <= 1'b0;
                        pre_f_pix_cnt <= 4'd0;
                    end
                else if(~pre_cap_stable & cam_vsync_rising)
                    begin
                        pre_f_pix_cnt <= pre_f_pix_cnt + 4'd1;
                        if(pre_f_pix_cnt >= DVP_FRAME_WAIT_CNT)
                            pre_cap_stable <= 1'b1;
                    end
                else
                    pre_cap_stable <= pre_cap_stable;
            end

        assign capture_failure  = 1'b0;
        assign capture_stable       = pre_cap_stable;
        assign capture_h_size       = 12'b0;
        assign capture_v_size       = 12'b0;
    end
endgenerate

endmodule

dvp_2_axi4s.v

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2017/04/15 01:13:12
// Design Name: 
// Module Name: dvp_2_axi4s
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module dvp_2_axi4s(
  //_____________________________________________ axi4s clock
    input axis_aclk,
    input axis_aresetn,
  //_____________________________________________ axi4s signals
    output [23:0] m_axis_video_tdata,
    output m_axis_video_tlast,
    input m_axis_video_tready,
    output m_axis_video_tuser,
    output m_axis_video_tvalid,
  //_____________________________________________ DVP interface
  output CAM_XVCLK,
  input CAM_PCLK,
  input CAM_HREF,
  input CAM_VSYNC,
  input [7:0] CAM_D,
  //_____________________________________________ module control
  input capture_en,
  output capture_stable,
  output capture_failure,
  output [11:0] capture_h_size,
  output [11:0] capture_v_size
    );

wire iCLK       = axis_aclk;
wire iRST_n = axis_aresetn;

wire rx_pclk;
wire rx_href;
wire rx_vsync;
wire [23:0] rx_data;

dvp_capture tb_dvp_capture_inst(
    //_____________________________________________ system clock
    .iCLK(iCLK),
    .iRST_n(iRST_n),
      //_____________________________________________ module control
    .capture_en(capture_en),
    .capture_stable(capture_stable),
    .capture_failure(capture_failure),
    .capture_h_size(capture_h_size),
    .capture_v_size(capture_v_size),
      //_____________________________________________ DVP interface
    .CAM_XVCLK(CAM_XVCLK),
    .CAM_PCLK(CAM_PCLK),
    .CAM_HREF(CAM_HREF),
    .CAM_VSYNC(CAM_VSYNC),
    .CAM_D(CAM_D),
      //_____________________________________________ parallel signals
    .rx_pclk(rx_pclk),
    .rx_href(rx_href),
    .rx_vsync(rx_vsync),
    .rx_data(rx_data)
    );

wire vid_io_in_ce           = capture_stable;

wire vid_io_in_clk      = rx_pclk;
wire vid_active_video   = rx_href;
wire vid_vsync              = rx_vsync;
wire [23:0] vid_data    =   rx_data;

wire aclk                   =   axis_aclk;
wire aresetn            = axis_aresetn;
wire axis_enable    = capture_stable;

v_vid_in_axi4s_0 vid_in_inst (
  .vid_io_in_clk(vid_io_in_clk),              // input wire vid_io_in_clk
  .vid_io_in_ce(vid_io_in_ce),                // input wire vid_io_in_ce
  .vid_io_in_reset(1'b0),                               // input wire vid_io_in_reset
  .vid_active_video(rx_href),                           // input wire vid_active_video
  .vid_vblank(1'b0),                                // input wire vid_vblank
  .vid_hblank(1'b0),                                // input wire vid_hblank
  .vid_vsync(vid_vsync),                      // input wire vid_vsync
  .vid_hsync(1'b0),                                 // input wire vid_hsync
  .vid_field_id(1'b0),                              // input wire vid_field_id
  .vid_data(vid_data),                        // input wire [23 : 0] vid_data
  .aclk(aclk),                                // input wire aclk
  .aclken(1'b1),                                // input wire aclken
  .aresetn(aresetn),                          // input wire aresetn
  .m_axis_video_tdata(m_axis_video_tdata),    // output wire [23 : 0] m_axis_video_tdata
  .m_axis_video_tvalid(m_axis_video_tvalid),  // output wire m_axis_video_tvalid
  .m_axis_video_tready(m_axis_video_tready),  // input wire m_axis_video_tready
  .m_axis_video_tuser(m_axis_video_tuser),    // output wire m_axis_video_tuser
  .m_axis_video_tlast(m_axis_video_tlast),    // output wire m_axis_video_tlast
  .fid(),                                       // output wire fid
  .vtd_active_video(),                                      // output wire vtd_active_video
  .vtd_vblank(),                                        // output wire vtd_vblank
  .vtd_hblank(),                                        // output wire vtd_hblank
  .vtd_vsync(),                                         // output wire vtd_vsync
  .vtd_hsync(),                                         // output wire vtd_hsync
  .vtd_field_id(),                                      // output wire vtd_field_id
  .overflow(),                                      // output wire overflow
  .underflow(),                                         // output wire underflow
  .axis_enable(capture_stable)                // input wire axis_enable
);

endmodule

生成Video In to AXI4-Stream IP核的tcl脚本

# this is a collection of useful project utilities

# implement touch - opens a file updating the time stamp,
# creating it if it does not exist
proc touch {f} {
   set FILEIN [open $f w]
   close $FILEIN
}


# get the directory where this script resides
set thisDir [file dirname [info script]]
# source common utilities
source -notrace $thisDir/utils.tcl

set ipDir ./ip

create_project -force managed_ip_project_v_vid_in_axi4s $ipDir/managed_ip_project_v_vid_in_axi4s -part xc7z010clg400-1 -ip
# Set project properties
set obj [get_projects]
set_property "board_part" "digilentinc.com:zybo:part0:1.0" $obj
set_property "simulator_language" "Mixed" $obj
set_property "target_language" "Verilog" $obj
#set_property coreContainer.enable 1 $obj

set_property target_simulator XSim [current_project]
create_ip -name v_vid_in_axi4s -vendor xilinx.com -library ip -module_name v_vid_in_axi4s_0 -dir $ipDir
set_property -dict [list CONFIG.C_HAS_ASYNC_CLK {1}] [get_ips v_vid_in_axi4s_0]
set_property -dict [list CONFIG.C_ADDR_WIDTH {11}] [get_ips v_vid_in_axi4s_0]
generate_target all [get_files  v_vid_in_axi4s_0.xci]

export_ip_user_files -of_objects [get_files v_vid_in_axi4s_0.xci] -no_script -ip_user_files_dir $ipDir -force -quiet 

create_ip_run [get_files -of_objects [get_fileset sources_1] [get_files */v_vid_in_axi4s_0.xci]]
launch_run  v_vid_in_axi4s_0_synth_1
wait_on_run v_vid_in_axi4s_0_synth_1

export_simulation -of_objects [get_files v_vid_in_axi4s_0.xci] -force -quiet

# If successful, "touch" a file so the make utility will know it's done
touch {.ip.done}
  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值