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)