debounce

Aug 17, 2026 Last reply: 13 minutes ago 7 Replies

We are making a 4-channel tachometer module. After a bunch of analog stuff, four logic signals run into an FPGA to be processed. The fpga will use a 50 MHz clock for the tach logic.



I used OPA197 opamps as the comparators. Their outputs run through a short ribbon cable from the analog board to the FPGA board. The edges are kinda slow, > 1 us, and might pick up noise, so I figure we should debounce them digitally in the FPGA.



Suggestions?



One could push the signal into a long shift register clocked at 50 MHz. All 1's could set a flop and all 0's could clear it. Maybe 32 flops long? Clumsy.



Or some sort of up/down counter?


Courtesy of Google AI. Carefull it doesn't burn your house down and run away with your wife.

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL;

entity debouncer is generic ( -- For a 50 MHz clock, 1,000,000 cycles = 20 ms BOUNCE_LIMIT : integer := 1000000 ); port ( clk : in std_logic; rst : in std_logic; raw_in : in std_logic; clean_out: out std_logic ); end entity debouncer;

architecture rtl of debouncer is -- Synchronizer stages signal sync_0 : std_logic := '0'; signal sync_1 : std_logic := '0'; -- Debounce counter and internal state signal count : integer range 0 to BOUNCE_LIMIT := 0; signal stable_state: std_logic := '0'; begin

-- Output assignment clean_out <= stable_state;

process(clk, rst) begin if rst = '1' then sync_0 <= '0'; sync_1 <= '0'; count <= 0; stable_state <= '0'; elsif rising_edge(clk) then -- 2-stage synchronizer to prevent metastability sync_0 <= raw_in; sync_1 <= sync_0; -- Debounce logic if sync_1 /= stable_state then -- Input changed, start/continue counting if count < BOUNCE_LIMIT then count <= count + 1; else -- Input remained stable long enough stable_state <= sync_1; count <= 0; end if; else -- Input matches current stable state, reset counter count <= 0; end if; end if; Process;

end architecture rtl;

The "Not Too Shifty!" section of

formatting link
similar to what you propose.

Or use an up/down counter on the 50 MHz with the analog input controlling up/down. On state 0, reset the output, and on state N-1, set it.

Load the counter appropriately if it tries to wrap. I could uncoil my rusty Verilog, but it’s a pretty simple gizmo, and probably saves space vs a long register.

Cheers

Phil Hobbs

8-stage is sufficient. Just don't forget to poison it on startup. Trivial to implement in an FPGA.

If it is news, the shift register thing is a digital LPF.

Here is a many decades old classic, still in production and readily available:

formatting link

Naw, I think it's got a crush on Claude...

A smarter move is usually to signal the change and THEN debounce. I.e., ignore bouncing AFTER the initial transition

Otherwise, your signal transitions are delayed by the debounce interval.

Read the state of the contact and log, wait a debounce time, say

20mS, then read again to verify, Play with time delay and > 1 verification cycles to make more robust.

In software, like this, many projects:

Interrupt handler fragment, from system clock tick isr.

Sorry, cut and paste, lost the formatting.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required