sequential component

Majority-Vote Debouncer

Open in playground

A button or sensor line bounces: each press flickers before it settles. This debouncer votes instead of waiting. Five flip-flops hold the last five raw samples, and the output follows the majority. Three or more high samples drive clean high; three or more low samples drive it low.

The vote makes the filter symmetric and fast. A clean edge ripples through in three cycles, because the third matching sample tips the majority. An isolated one-cycle spike never wins the vote, so it never reaches clean. A two-sample dropout inside a held press loses the vote the same way, and clean rides straight through it.

The common alternative counts consecutive identical samples and restarts the count on every flip. The majority window never restarts, so single flips cost it nothing. The price is fixed: five flip-flops, whatever the bounce looks like.

In the waveform: just after 125 ns the third consecutive high sample tips the vote and clean rises. Around 175 ns a two-sample dropout hits taps_r and clean never blinks.

In the netlist: a five-stage shift chain feeds a small adder-and-compare cone, the 3-of-5 vote spelled out in gates.

The course builds the counter-based debouncer and the other input-conditioning workhorses from first principles in Sequential Design Patterns.

-- Majority-vote debouncer: five-sample window, output follows the 3-of-5 vote
library ieee;
use ieee.std_logic_1164.all;

entity majority_debouncer is
  port (
    clk   : in  std_logic;
    rst   : in  std_logic;
    raw   : in  std_logic;
    clean : out std_logic
  );
end entity majority_debouncer;

architecture rtl of majority_debouncer is

  signal taps_r    : std_logic_vector(4 downto 0);
  signal taps_next : std_logic_vector(4 downto 0);
  signal clean_r   : std_logic;

  -- 3-of-5 vote: count the ones, compare against the majority threshold
  function majority(v : std_logic_vector(4 downto 0)) return std_logic is
    variable ones : natural := 0;
  begin
    for i in v'range loop
      if v(i) = '1' then
        ones := ones + 1;
      end if;
    end loop;
    if ones >= 3 then
      return '1';
    else
      return '0';
    end if;
  end function;

begin

  -- The window including the sample captured at this edge
  taps_next <= taps_r(3 downto 0) & raw;

  vote_p : process(clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        taps_r  <= (others => '0');
        clean_r <= '0';
      else
        taps_r  <= taps_next;
        clean_r <= majority(taps_next);
      end if;
    end if;
  end process vote_p;

  clean <= clean_r;

end architecture rtl;
Waveform loading...