`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Engineer: David Carne // // Create Date: 18:57:01 04/11/2006 // Design Name: // Module Name: capture_block // Project Name: // Target Devices: // Tool versions: // Description: Capture block for the sparkfun camera // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module capture_block(clk, capture_trigger, capture_done, mem_take, mem_write_strobe, mem_data, mem_addr, vclk, hsync, vsync, pixel_data, hsync_line_length,hsync_count); input clk; // Capture triggering input capture_trigger; output reg capture_done = 0; // Memory bus output output mem_take; output reg mem_write_strobe = 0; output reg [31:0] mem_data = 0; output reg [17:0] mem_addr = 0; // We currently seize the memory bus whenever we're being asked to trigger assign mem_take = capture_trigger; // Capture statistics output [11:0] hsync_line_length; output [9:0] hsync_count; // Data inputs input vclk; input hsync; input vsync; input [7:0] pixel_data; // First we convert all external async signals into our own domain reg hs_sync_1; reg hs_sync_2; reg vs_sync_1; reg vs_sync_2; reg vclk_sync_1; reg vclk_sync_2; reg [7:0] pixdata_sync_1; reg [7:0] pixdata_sync_2; always @(posedge clk) begin hs_sync_1 <= hsync; hs_sync_2 <= hs_sync_1; vs_sync_1 <= vsync; vs_sync_2 <= vs_sync_1; vclk_sync_1 <= vclk; vclk_sync_2 <= vclk_sync_1; pixdata_sync_1 <= pixel_data; pixdata_sync_2 <= pixdata_sync_1; end // Now that we're in the right domain, we need to do the sampling // First we need an edge detect vclk reg vclk_old; always @(posedge clk) begin vclk_old <= vclk_sync_2; end wire vclk_posedge = (vclk_old == 0) && (vclk_sync_2 == 1); reg sample_new; reg sample_hsync; reg sample_vsync; reg [7:0] sample_pixel; always @(posedge clk) begin sample_new <= vclk_posedge; if (vclk_posedge) begin sample_hsync <= hs_sync_2; sample_vsync <= vs_sync_2; sample_pixel <= pixdata_sync_2; end end // VSync Triggering module // Look for a negative edge reg last_vsync_sample = 0; reg P2_vsync_triggered = 0; reg P2_vsync_end_triggered = 0; reg P2_sample_vsync; reg P2_sample_new; reg P2_sample_hsync; reg [7:0] P2_sample_pixel; always @(posedge clk) begin if (sample_new) begin // Probably don't need this - it just ensure that a capture will not start for a frame // already partially through vsync - but actually this would only hit affect the last // sample, so I can probably remove the && capture_trigger. Do this after testing the // stats to ensure it doesn't break. last_vsync_sample <= sample_vsync && capture_trigger; // We only step this on new data so it hangs around P2_sample_pixel <= sample_pixel; P2_sample_hsync <= sample_hsync; P2_sample_vsync <= sample_vsync; end // Pipeline Step P2_sample_new <= sample_new; if (capture_trigger) begin if ((last_vsync_sample == 1) && (sample_vsync == 0)) P2_vsync_triggered <= 1; if (P2_vsync_triggered && sample_vsync) P2_vsync_end_triggered <= 1; end else begin P2_vsync_end_triggered <= 0; P2_vsync_triggered <= 0; end end // Capture statistics module reg [11:0] hsync_line_length; reg [9:0] hsync_count; // temp registers for storing the internal counts // they get clocked to the output registers on clock completion reg [11:0] _hsync_line_length; reg [9:0] _hsync_count; reg hsync_old; reg vsync_old; always @(posedge clk) begin if (P2_sample_new) begin hsync_old <= P2_sample_hsync; vsync_old <= P2_sample_vsync; // at vsync edges we clear + update the counts if (P2_sample_vsync == 1 && vsync_old == 0) begin hsync_count <= _hsync_count; _hsync_count <= 0; end // but at hsync edges we inc the counter else if (P2_sample_hsync == 1 && hsync_old == 0) _hsync_count <= _hsync_count + 1; // We're counting only during the hsync area if (P2_sample_hsync == 1) begin // if its an upgoing hsync edge if (hsync_old == 0) begin hsync_line_length <= _hsync_line_length; _hsync_line_length <= 1; end else _hsync_line_length <= _hsync_line_length +1; end end end // 4 -> 1 Sample combiner + hsync triggering reg [31:0] P3_sample_combined; reg [31:0] P3_sample_new; // this needs to carry through because it terminates the memory writer reg P3_vsync_end_triggered; reg [1:0] sample_combiner_index; always @(posedge clk) begin if (capture_trigger) begin if (P2_sample_new && P2_sample_hsync && P2_vsync_triggered) begin if (sample_combiner_index == 0) P3_sample_combined[7:0] <= P2_sample_pixel; else if (sample_combiner_index == 1) P3_sample_combined[15:8] <= P2_sample_pixel; else if (sample_combiner_index == 2) P3_sample_combined[23:16] <= P2_sample_pixel; else if (sample_combiner_index == 3) P3_sample_combined[31:24] <= P2_sample_pixel; // we can quickly promote the last pixel to the output - if its not already there if (sample_combiner_index == 3) P3_sample_new <= 1; else P3_sample_new <= 0; P3_vsync_end_triggered <= P2_vsync_end_triggered; sample_combiner_index <= sample_combiner_index + 1; end else begin P3_vsync_end_triggered <= P2_vsync_end_triggered; P3_sample_new <= 0; end end else begin sample_combiner_index <= 0; P3_sample_combined <=0; P3_sample_new <= 0; P3_vsync_end_triggered <= P2_vsync_end_triggered; end end ////////////////////////////////////////////////////////////////// reg P4_mem_write_pulse = 0; // Data output writer always @(posedge clk) begin if (capture_trigger) begin if (P3_sample_new) begin // now we do our memory manipulation mem_data <= P3_sample_combined; // If we hit the end memory address, or if we see an end trigger if (mem_addr != 18'h3FFFE && !P3_vsync_end_triggered) begin mem_addr <= mem_addr + 1; P4_mem_write_pulse <= 1; end else begin P4_mem_write_pulse <= 0; capture_done <= 1; end end else P4_mem_write_pulse <= 0; end else begin P4_mem_write_pulse <= 0; mem_addr <= 18'h3FFFF; capture_done <= 0; end end // Mem pulser always @(posedge clk) begin mem_write_strobe <= P4_mem_write_pulse; end endmodule