A Color Vision System for Embedded Robotics Applications

Click here to return to article

Verilog FPGA Video Capture Code:

////////////////////////////////////////////////////
//
//  Module Video Capture Written By: Kenneth Maxon
//    On or about... March-2004 ...
//
////////////////////////////////////////////////////

module video_capture(
			input wire sys_clock,
			input wire force_reset,

			input wire begin_capture,

			output reg [17:0] video1_addr,
			output wire [14:0] video1_data_filtered,
			output reg video1_store_strb,

			input wire video1_llc,
			input wire video1_hsync,
			input wire video1_vsync,
			input wire [14:0] video1_raw,

			output wire [23:0] blob1_x_out,
			output wire [23:0] blob1_y_out,
			output wire blob_capture_done,

			input wire data_valid,

			output reg [3:0] debug_state
			);

reg video1_llc_reg;
reg video1_llc2_reg;
wire llc_edge_found;

reg video1_hsync_reg;
reg video1_hsync2_reg;
wire hsync_edge_found;

reg video1_vsync_reg;
reg video1_vsync2_reg;
wire vsync_edge_found;

reg [9:0] vid_cap_state_var;
reg [17:0] addr_index_count;
reg [14:0] video1_data;
reg [8:0] pixel_count;
reg [7:0] line_count;
reg end_of_screen_capture;
reg beginning_of_screen_capture;

always@(posedge sys_clock)	// always double buffer across clock domains.
begin
	video1_llc_reg <= #1 video1_llc;
	video1_hsync_reg <= #1 video1_hsync;
	video1_vsync_reg <= #1 video1_vsync;
	video1_llc2_reg <= #1 video1_llc_reg;
	video1_hsync2_reg <= #1 video1_hsync_reg;
	video1_vsync2_reg <= #1 video1_vsync_reg;
end

assign #1 llc_edge_found = (~video1_llc2_reg & video1_llc_reg);
assign #1 hsync_edge_found = (~video1_hsync2_reg & video1_hsync_reg);
assign #1 vsync_edge_found = (~video1_vsync2_reg & video1_vsync_reg);

parameter[9:0]
			DISPATCH_STATE	= 10'b0000000001, 
			VID_CAP1_STATE	= 10'b0000000010,
			VID_CAP2_STATE	= 10'b0000000100,
			VID_CAP3_STATE	= 10'b0000001000,
			VID_CAP4_STATE	= 10'b0000010000,
			VID_CAP45_STATE	= 10'b0000100000,
			VID_CAP5_STATE	= 10'b0001000000,
			VID_CAP6_STATE	= 10'b0010000000,
			VID_CAP7_STATE	= 10'b0100000000,
			VID_CAP8_STATE	= 10'b1000000000;

parameter[9:0]
			DISPATCH_CASE	= 10'bxxxxxxxxx1,
			VID_CAP1_CASE	= 10'bxxxxxxxx1x,
			VID_CAP2_CASE	= 10'bxxxxxxx1xx,
			VID_CAP3_CASE	= 10'bxxxxxx1xxx,
			VID_CAP4_CASE	= 10'bxxxxx1xxxx,
			VID_CAP45_CASE	= 10'bxxxx1xxxxx,
			VID_CAP5_CASE	= 10'bxxx1xxxxxx,
			VID_CAP6_CASE	= 10'bxx1xxxxxxx,
			VID_CAP7_CASE	= 10'bx1xxxxxxxx,
			VID_CAP8_CASE	= 10'b1xxxxxxxxx;

always @(posedge sys_clock or posedge force_reset)begin :  vid_gen_state_fsm
	if (force_reset)
		vid_cap_state_var[9:0] <= #1 DISPATCH_STATE;
	else begin
		casex (vid_cap_state_var[9:0]) // synopsys parallel_case full_case
			
			DISPATCH_CASE:	// wait for processor to tell us to start
			begin
				if(begin_capture)
					vid_cap_state_var[9:0] <= #1 VID_CAP1_STATE;
				else
					vid_cap_state_var[9:0] <= #1 DISPATCH_STATE;
			end
			
			VID_CAP1_CASE:	// wait for vsync
			begin
				addr_index_count[17:0] <= #1 18'd01605;
				line_count[7:0] <= #1 8'h00;
				if(vsync_edge_found)
					vid_cap_state_var[9:0] <= #1 VID_CAP2_STATE;
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP1_STATE;
			end

			VID_CAP2_CASE:	// wait for hsync
			begin	
				pixel_count[8:0] <= #1 9'h000;
				if(hsync_edge_found)
					vid_cap_state_var[9:0] <= #1 VID_CAP3_STATE;
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP2_STATE;
			end

			VID_CAP3_CASE:	// wait for llc2 & latch in same state
			begin
				if(llc_edge_found)
				begin
					video1_addr[17:0] <= #1 addr_index_count[17:0];
					video1_data[14:0] <= #1 video1_raw[14:0];
					vid_cap_state_var[9:0] <= #1 VID_CAP4_STATE;
				end
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP3_STATE;
			end

			VID_CAP4_CASE:  // send out data strobe to the RAM scheduler
			begin
				addr_index_count[17:0] <= addr_index_count[17:0] + 18'h00001;
				pixel_count[8:0] <= #1 pixel_count[8:0] + 9'h001;
				vid_cap_state_var[9:0] <= #1 VID_CAP45_STATE;
			end

			VID_CAP45_CASE:  // skip every other pixel
			begin
				if(llc_edge_found)
					vid_cap_state_var[9:0] <= #1 VID_CAP5_STATE;
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP45_STATE;
			end

			VID_CAP5_CASE:	// check to see if we are at the end of the line pixel wise
			begin
				if(pixel_count[8:0] < 9'd310)
					vid_cap_state_var[9:0] <= #1 VID_CAP3_STATE;
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP6_STATE;
			end

			VID_CAP6_CASE:	// add the rest of the address to the address counter to make up for rest of the line
			begin
				addr_index_count[17:0] <= addr_index_count[17:0] + 18'd010;
				line_count[7:0] <= line_count[7:0] + 8'd01;
				vid_cap_state_var[9:0] <= #1 VID_CAP7_STATE;
			end

			VID_CAP7_CASE:	// check to see if we're at the end of the screen
			begin
				if(line_count[7:0] < 8'd230)
					vid_cap_state_var[9:0] <= #1 VID_CAP2_STATE;
				else
					vid_cap_state_var[9:0] <= #1 VID_CAP8_STATE;
			end

			VID_CAP8_CASE:	// done
			begin
				vid_cap_state_var[9:0] <= #1 DISPATCH_STATE;
			end

		endcase
	end
end // video_gen_state_fsm

always @(vid_cap_state_var[9:0])begin : vid_gen_state_assn
	casex (vid_cap_state_var[9:0]) // synopsys parallel_case full_case
		DISPATCH_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'ha;
			beginning_of_screen_capture = 1'h1;
			end_of_screen_capture = 1'b0;
		end
		
		VID_CAP1_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h2;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP2_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h3;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP3_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h4;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP4_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h5;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP45_CASE:
		begin
			video1_store_strb = 1'b1;
			debug_state[3:0] = 4'h6;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP5_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h7;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP6_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h8;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP7_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'h9;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b0;
		end

		VID_CAP8_CASE:
		begin
			video1_store_strb = 1'b0;
			debug_state[3:0] = 4'ha;
			beginning_of_screen_capture = 1'h0;
			end_of_screen_capture = 1'b1;	// used to trigger blob calculation
		end

	endcase
end //video_gen_state_assn


assign #1 video1_data_filtered[14:0] = data_valid ?
			video1_data[14:0] :
			15'h0000;

blob_detection my_blob_detector(
			.sys_clock(sys_clock),
			.force_reset(force_reset),

			.line_count(line_count[7:0]),
			.pixel_count(pixel_count[8:0]),
			.video1_out_strb(video1_store_strb),
			
			.video_filter_data_valid(data_valid),
			.end_of_screen_capture(end_of_screen_capture),
			.beginning_of_screen_capture(beginning_of_screen_capture),
			
			.x_output(blob1_x_out[23:0]),
			.y_output(blob1_y_out[23:0]),
			
			.blob_capture_done(blob_capture_done)
			);

endmodule

Click here to return to article