在之前设计的OV5640输入接口逻辑上完善了一下代码,暂时出一版IP来用。
先不考虑每个信号的具体时序,大致看一看他的波形,可以发现,这是一个很标准的时序。VSYNC是场同步信号,在图像数据发送之前会有一个高电平脉冲;HREF是数据有效信号,高电平时时代表D[9:0]的数据信号有效,可以理解为DE或者Data_valid;HSYNC是行同步信号,我们有了HREF就不需要这个信号了;D[9:0]是并口数据;以上四个信号都同步于摄像头的PCLK信号。
因为DVP这个并口的时序十分标准,其实是可以直接接入fpga内,并借用Xilinx的Video In to AXI4-Stream IP核实现并口到AXI4S总线的转换的。
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中看它的源码,还是很好理解的,可以选择直接使用它或者参照它的实现方法自行设计。
视频数据流按如下方式进入DDR缓存
DVP接口 -> dvp_2_axi4s -> axi vdma -> axi interconnect -> zynq -> DDR3
代码可以从这里下载: https://coding.net/u/vacajk/p/zybo_ov5640_stereo_camera/git
也可以直接下载我整理好的:稍后上传>>
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}