DEV Community

Hedy
Hedy

Posted on

What is Debouncing in FPGA?

What is Debouncing?
Debouncing is the process of filtering out the rapid, unintended mechanical openings and closings (called "bounces") of an electrical switch or button to ensure a single, clean digital signal transition is registered by the logic circuit.

When you press a physical button or flip a switch, the metal contacts don't make a perfect, instantaneous connection. Instead, they physically vibrate or "bounce" against each other for a few milliseconds before settling into a stable state.

Without debouncing, the FPGA (which operates in nanoseconds) sees this bouncing as a rapid series of high-low transitions and interprets it as multiple button presses instead of one.

The Problem: Raw Button Signal
This is what the voltage from a bouncing button looks like from the perspective of the FPGA:

text

Logic High (1)
  ^
  |   |\ |\ |\ |\      _________
  |   | \| \| \| \    |         |
  |   |  |  |  |  |   |         |
  |___|  |__|  |__|___|         |_______
  |                                     
  |                                     
  +------------------------------------------> Time
      Pressed ->       <--Bouncing-->  <--Stable-->
Enter fullscreen mode Exit fullscreen mode

The FPGA would read this as: 0 -> 1 -> 0 -> 1 -> 0 -> 1 -> 0 -> 1 (and so on).

The Goal: Debounced Signal
After debouncing, the signal sent to the FPGA's internal logic should look like this:

text

Logic High (1)
  ^
  |   _________________________
  |  |                         |
  |  |                         |
  |  |                         |
  |__|                         |___________________
  |                                     
  |                                     
  +------------------------------------------> Time
      Pressed ->                           Released
Enter fullscreen mode Exit fullscreen mode

A single, clean transition from 0 to 1 that lasts for the entire time the button is held down.

Why is Debouncing Crucial in FPGAs?

  1. Speed Disparity: The mechanical world operates on a millisecond scale. The FPGA's clock operates on a nanosecond scale. A 1 ms bounce is an eternity to an FPGA, allowing it to sample the unstable signal thousands of times.
  2. Deterministic Behavior: FPGA design is based on synchronous logic. Uncontrolled, asynchronous inputs like a bouncing switch violate the principles of synchronous design and lead to unpredictable and faulty behavior (e.g., a counter incrementing 10 times instead of once).
  3. Reliability: Debouncing is essential for creating reliable human-machine interfaces (buttons, switches) and for reading any mechanical sensor.

How to Debounce in an FPGA (The Solution)
Unlike microcontrollers that often use simple software delays in a while loop, debouncing in an FPGA is implemented in hardware, using the FPGA's own logic resources. The most common and robust method is a Debounce Finite State Machine (FSM) with a timer.

Here’s a step-by-step breakdown of how it works:

1. Synchronize the Asynchronous Input
First, the raw button signal (which is asynchronous to the FPGA's clock) is passed through a chain of two or three D-flip-flops. This prevents metastability and synchronizes the input to the FPGA's clock domain.

verilog

always @(posedge clk) begin
    button_ff1 <= raw_button_in;
    button_ff2 <= button_ff1;
    button_sync <= button_ff2;
end
Enter fullscreen mode Exit fullscreen mode

2. Implement a State Machine and Timer
The core debounce logic is a state machine, typically with two states:

  • STATE_IDLE: The button is in its stable, unpressed state.
  • STATE_PRESSED: The button has been pressed and is in its stable, pressed state.

The transitions between these states are guarded by a timer that measures if the input has been stable for a sufficient amount of time (e.g., 5-20 ms).

Operation:

  • The FSM starts in STATE_IDLE (output 0).
  • It continuously samples the synchronized button signal.
  • When it detects a change (e.g., button_sync becomes 1), it does not immediately change state. Instead, it resets and starts a timer (or down-counter).
  • The FSM keeps checking the input. If the input changes again before the timer expires (i.e., it's bouncing), the timer is reset.
  • Only if the input remains stable for the entire debounce period (e.g., 20 ms) does the timer finally expire. This signals that the bouncing has stopped.
  • Upon timer expiry, the FSM transitions to the new state (STATE_PRESSED) and outputs a stable 1.
  • The same process happens when the button is released to transition back to STATE_IDLE.

Example Code Snippet (Conceptual Verilog)

verilog

module debouncer (
    input wire clk,       // System clock (e.g., 50 MHz)
    input wire button_in, // Raw, bouncing button input
    output reg button_db  // Debounced, clean output
);

    parameter DEBOUNCE_TIME_MS = 20;
    parameter CLK_FREQ_HZ = 50_000_000; // 50 MHz

    // Calculate counter value to wait 20 ms
    parameter COUNTER_MAX = (DEBOUNCE_TIME_MS * CLK_FREQ_HZ) / 1000;

    reg [31:0] count;
    reg button_sync, button_prev;
    reg state;

    // Synchronizer flip-flops
    always @(posedge clk) begin
        button_sync <= button_in;
        button_prev <= button_sync; // button_prev is now the synchronized signal
    end

    // Debounce FSM
    always @(posedge clk) begin
        case (state)
            0: begin // STATE_IDLE
                button_db <= 1'b0;
                if (button_prev == 1'b1) begin // Input changed!
                    state <= 1; // Move to checking state
                    count <= 0; // Reset counter
                end
            end
            1: begin // STATE_COUNTING (wait for stability)
                if (button_prev == 1'b1) begin // Input is still high
                    if (count == COUNTER_MAX) begin // Timer expired -> stable
                        state <= 2; // Move to PRESSED state
                        button_db <= 1'b1;
                    end else begin
                        count <= count + 1; // Keep counting
                    end
                end else begin // Input changed back to low before timer expired (it was a bounce!)
                    state <= 0; // Go back to IDLE
                end
            end
            2: begin // STATE_PRESSED
                button_db <= 1'b1;
                if (button_prev == 1'b0) begin // Input changed (release)
                    state <= 3; // Move to release-checking state
                    count <= 0;
                end
            end
            3: begin // STATE_COUNTING_RELEASE
                // ... Logic identical to STATE_COUNTING but for release ...
                // Wait for stable low before going back to STATE_IDLE
            end
        endcase
    end
endmodule
Enter fullscreen mode Exit fullscreen mode

Summary

In essence, debouncing in an FPGA is the process of using a hardware-based state machine to ignore transient mechanical vibrations and only respond to stable, intentional state changes in a switch. It is a fundamental requirement for reliable input handling.

Top comments (0)