FPGA-Based Edge Detection with CMOS Camera Interface

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

Tags: FPGA CMOS-Camera Edge-Detection SDRAM VGA-Interface

Posted on Wed, 08 Jul 2026 16:04:20 +0000 by Arl8