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-->
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
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?
- 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.
- 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).
- 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
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
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)