System Architecture Overview
The system implements a complete image processing pipeline for edge detection using a FPGA. The design captures video from a CMOS camera, processes the frames through multiple image transformation stages, stores processed data in SDRAM, and outputs the result via VGA display.
Core Processing Modules
Camera Configuration Module
This module handles camera initialization using I2C protocol. After power-up, it waits 20ms before configuring 252 camera registers. The configuration completion signal enables the capture module.
Frame Capture Module
Receives 8-bit camera data and combines consecutive bytes into 16-bit RGB565 pixels. Generates start-of-packet (SOP) and end-of-packet (EOP) signals for frame boundary detection.
Image Processing Pipeline
- RGB to Grayscale Conversion: Converts RGB565 to 8-bit grayscale for computational efficiency
- Gaussian Filter: Applies linear smoothing to reduce Gaussian noise
- Binarization: Converts grayscale to binary (0/1) to simplify edge detection
- Sobel Operator: Performs edge detection using discrete differentiation
Memory Controller
Manages SDRAM storage with ping-pong buffering technique. Uses asynchronous FIFOs to handle clock domain crossing between camera capture (slower clock) and display output (faster clock).
Display Interface
VGA controller that reads processed frames from SDRAM and generates appropriate timing signals for display output.
Top-Level Implementation
module edge_detection_system(
input system_clock,
input reset_n,
// Camera interface
input cam_vertical_sync,
input cam_pixel_clock,
input cam_horizontal_ref,
input [7:0] cam_data_in,
output cam_external_clock,
output cam_power_down,
output cam_reset,
output cam_i2c_clock,
inout cam_i2c_data,
// SDRAM interface
output memory_clock,
output memory_clock_enable,
output memory_chip_select,
output memory_row_select,
output memory_column_select,
output memory_write_enable,
output [1:0] memory_bank,
output [12:0] memory_address,
inout [15:0] memory_data,
output [1:0] memory_data_mask,
// VGA output
output [15:0] display_rgb,
output display_hsync,
output display_vsync
);
// Internal signal declarations
wire configuration_complete;
wire cam_clock;
wire [15:0] raw_pixel;
wire pixel_valid;
wire frame_start;
wire frame_end;
wire mem_input_start;
wire mem_input_end;
wire mem_input_valid;
wire [15:0] mem_input_data;
wire clock_100mhz;
wire clock_100mhz_shifted;
wire vga_clock;
wire pixel_clk;
wire read_request;
wire [15:0] output_data;
wire output_valid;
wire system_reset_n;
assign system_reset_n = reset_n & configuration_complete;
assign cam_external_clock = cam_clock;
assign memory_clock = clock_100mhz_shifted;
// Clock generation
clock_generation u_clock_gen(
.reset (~reset_n),
.source_clock (system_clock),
.cam_clock (cam_clock),
.vga_clock (vga_clock)
);
sdram_clock_gen u_sdram_clocks(
.reset (~reset_n),
.source_clock (system_clock),
.mem_clock (clock_100mhz),
.mem_clock_shift (clock_100mhz_shifted)
);
// Camera configuration
camera_configuration u_cam_config(
.clock (system_clock),
.reset_n (reset_n),
.i2c_clock (cam_i2c_clock),
.i2c_data (cam_i2c_data),
.power_down (cam_power_down),
.cam_reset (cam_reset),
.config_done (configuration_complete)
);
// Frame capture
frame_capture u_capture(
.pixel_clock (pixel_clk),
.reset_n (reset_n),
.vsync (cam_vertical_sync),
.href (cam_horizontal_ref),
.pixel_data (cam_data_in),
.enable (configuration_complete),
.output_pixel (raw_pixel),
.pixel_valid (pixel_valid),
.frame_start (frame_start),
.frame_end (frame_end)
);
// Image processing (conditional compilation)
`ifdef IMAGE_PROCESSING_ENABLED
wire processed_start;
wire processed_end;
wire processed_valid;
wire [15:0] processed_data;
image_processor u_processor(
.clock (pixel_clk),
.reset_n (reset_n),
.input_start (frame_start),
.input_end (frame_end),
.input_valid (pixel_valid),
.input_pixel (raw_pixel),
.output_start (processed_start),
.output_end (processed_end),
.output_valid (processed_valid),
.output_pixel (processed_data)
);
assign mem_input_data = processed_data;
assign mem_input_valid = processed_valid;
assign mem_input_start = processed_start;
assign mem_input_end = processed_end;
`else
assign mem_input_data = raw_pixel;
assign mem_input_valid = pixel_valid;
assign mem_input_start = frame_start;
assign mem_input_end = frame_end;
`endif
// SDRAM controller
sdram_controller u_memory_ctrl(
.controller_clock (clock_100mhz),
.input_clock (pixel_clk),
.output_clock (vga_clock),
.reset_n (reset_n),
.data_in (mem_input_data),
.input_valid (mem_input_valid),
.input_start (mem_input_start),
.input_end (mem_input_end),
.read_request (read_request),
.data_out (output_data),
.output_valid (output_valid),
.mem_clock_enable (memory_clock_enable),
.mem_chip_select (memory_chip_select),
.mem_row_select (memory_row_select),
.mem_col_select (memory_column_select),
.mem_write_enable (memory_write_enable),
.mem_bank (memory_bank),
.mem_address (memory_address),
.mem_data (memory_data),
.mem_data_mask (memory_data_mask)
);
// VGA display
vga_display u_vga(
.vga_clock (vga_clock),
.reset_n (system_reset_n),
.pixel_input (output_data),
.input_valid (output_valid),
.ready (read_request),
.vga_rgb (display_rgb),
.hsync (display_hsync),
.vsync (display_vsync)
);
endmodule
Image Processing Implementation
module image_processor(
input processing_clock,
input reset_n,
input input_frame_start,
input input_frame_end,
input input_valid,
input [15:0] input_pixel, // RGB565 format
output output_frame_start,
output output_frame_end,
output output_valid,
output [15:0] output_pixel
);
// Internal signals
wire gray_start;
wire gray_end;
wire gray_valid;
wire [7:0] gray_value;
wire filter_start;
wire filter_end;
wire filter_valid;
wire [7:0] filtered_value;
wire binary_start;
wire binary_end;
wire binary_valid;
wire binary_output;
wire edge_start;
wire edge_end;
wire edge_valid;
wire edge_detected;
// Grayscale conversion
rgb_to_grayscale u_grayscale(
.clock (processing_clock),
.reset_n (reset_n),
.input_start (input_frame_start),
.input_end (input_frame_end),
.input_valid (input_valid),
.rgb_input (input_pixel),
.output_start (gray_start),
.output_end (gray_end),
.output_valid (gray_valid),
.gray_output (gray_value)
);
// Gaussian filter (optional)
`ifdef GAUSSIAN_FILTER_ENABLED
wire gauss_start;
wire gauss_end;
wire gauss_valid;
wire [7:0] gauss_output;
gaussian_filter u_gauss(
.clock (processing_clock),
.reset_n (reset_n),
.input_start (gray_start),
.input_end (gray_end),
.input_valid (gray_valid),
.gray_input (gray_value),
.output_start (gauss_start),
.output_end (gauss_end),
.output_valid (gauss_valid),
.filtered_output (gauss_output)
);
assign filter_start = gauss_start;
assign filter_end = gauss_end;
assign filter_valid = gauss_valid;
assign filtered_value = gauss_output;
`else
assign filter_start = gray_start;
assign filter_end = gray_end;
assign filter_valid = gray_valid;
assign filtered_value = gray_value;
`endif
// Binarization
grayscale_to_binary u_binarize(
.clock (processing_clock),
.reset_n (reset_n),
.input_start (filter_start),
.input_end (filter_end),
.input_valid (filter_valid),
.gray_input (filtered_value),
.output_start (binary_start),
.output_end (binary_end),
.output_valid (binary_valid),
.binary_output (binary_output)
);
// Edge detection
sobel_detector u_sobel(
.clock (processing_clock),
.reset_n (reset_n),
.binary_input (binary_output),
.input_start (binary_start),
.input_end (binary_end),
.input_valid (binary_valid),
.edge_output (edge_detected),
.output_start (edge_start),
.output_end (edge_end),
.output_valid (edge_valid)
);
// Output assignment
assign output_frame_start = edge_start;
assign output_frame_end = edge_end;
assign output_valid = edge_valid;
assign output_pixel = {16{edge_detected}};
endmodule
Memory Management Strategy
The SDRAM controller implements a sophisticated memory managemant system with the following features:
- Ping-pong buffering between two memory banks
- Asynchronous FIFOs for clock domain crossing
- Priority-based arbitration for read/write operations
- Burst transfer optimization
- Frame completion detection and bank switching
The controller ensures seamless frame transitions by maintaining separate read and write banks, preventing data corruption during simultaneous access operations.
Display Interface Implementation
module vga_display(
input vga_clock, // 75MHz
input reset_n,
input [15:0] pixel_input,
input input_valid,
output ready,
output [15:0] vga_rgb,
output horizontal_sync,
output vertical_sync
);
// Timing counters
reg [10:0] horizontal_counter;
reg [9:0] vertical_counter;
// Control signals
reg horizontal_valid;
reg vertical_valid;
reg h_sync;
reg v_sync;
reg read_enable;
// FIFO interface
wire read_request;
wire write_request;
wire fifo_empty;
wire fifo_full;
wire [15:0] fifo_output;
wire [3:0] fifo_usage;
// Horizontal counter
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
horizontal_counter <= 0;
end else begin
if (horizontal_counter == H_TOTAL - 1)
horizontal_counter <= 0;
else
horizontal_counter <= horizontal_counter + 1;
end
end
// Vertical counter
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
vertical_counter <= 0;
end else if (horizontal_counter == H_TOTAL - 1) begin
if (vertical_counter == V_TOTAL - 1)
vertical_counter <= 0;
else
vertical_counter <= vertical_counter + 1;
end
end
// Valid region detection
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
horizontal_valid <= 0;
end else begin
if (horizontal_counter == H_START - 1)
horizontal_valid <= 1;
else if (horizontal_counter == H_END - 1)
horizontal_valid <= 0;
end
end
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
vertical_valid <= 0;
end else if (horizontal_counter == H_TOTAL - 1) begin
if (vertical_counter == V_START)
vertical_valid <= 1;
else if (vertical_counter == V_END)
vertical_valid <= 0;
end
end
// Sync generation
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
h_sync <= 0;
end else begin
if (horizontal_counter == H_SYNC - 1)
h_sync <= 1;
else if (horizontal_counter == H_TOTAL - 1)
h_sync <= 0;
end
end
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
v_sync <= 0;
end else if (horizontal_counter == H_TOTAL - 1) begin
if (vertical_counter == V_SYNC - 1)
v_sync <= 1;
else if (vertical_counter == V_TOTAL - 1)
v_sync <= 0;
end
end
// FIFO control
always @(posedge vga_clock or negedge reset_n) begin
if (!reset_n) begin
read_enable <= 0;
end else begin
if (fifo_usage <= 4)
read_enable <= 1;
else if (fifo_usage >= 12)
read_enable <= 0;
end
end
// FIFO instantiation
display_buffer u_buffer(
.reset (~reset_n),
.clock (vga_clock),
.data_in (pixel_input),
.read_req (read_request),
.write_req (write_request),
.empty (fifo_empty),
.full (fifo_full),
.data_out (fifo_output),
.usage (fifo_usage)
);
assign write_request = ~fifo_full && input_valid;
assign read_request = ~fifo_empty && horizontal_valid && vertical_valid;
assign ready = read_enable;
assign vga_rgb = (horizontal_valid & vertical_valid) ? fifo_output : 0;
assign horizontal_sync = h_sync;
assign vertical_sync = v_sync;
endmodule