VHDL coding tips and tricks: September 2017

Tuesday, September 5, 2017

Pushbutton DeBounce circuit in VHDL

Lets start with some basic definitions,

What is Bouncing?

Bouncing is the tendency of any two metal contacts in an electronic device to generate multiple signals as the contacts close or open.

What is DeBouncing?

Debouncing is any kind of hardware device or software that ensures that only a single signal will be acted upon for a single opening or closing of a contact.

In this post, I want to explain how this is done and even have shared a code in VHDL. When you want to test your piece of code on a FPGA board, you might need to use the push-buttons for taking input from the user. 

Some boards have an integrated debouncer which takes care of the bouncing problem of pushbuttons. But if its not already there, its up to you to implement it in HDL. 

When a push-button is pressed, this is how the signal, it generates might look like,

Image result for debounce vhdl

Our aim here, is to process this signal and get a single pulse for each push button press. 

There are many debouncer codes available online. Here I have implemented, my own method, so use it after going through it carefully.

I created the FSM shown below and implemented it using VHDL.

What I am trying to do here is, every time I detect an activity on the button, I start a counter. When the counter reaches the maximum count, I check again, if the button is still active. If yes, I take it as a valid button input, otherwise I ignore it and wait for another activity on the button.

VHDL code for DeBouncer circuit:

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

entity DeBounce is
    port(   Clock : in std_logic;
                Reset : in std_logic;
            button_in : in std_logic;
            pulse_out : out std_logic
        );
end DeBounce;

architecture behav of DeBounce is

--the below constants decide the working parameters.
--the higher this is, the more longer time the user has to press the button.
constant COUNT_MAX : integer := 20; 
--set it '1' if the button creates a high pulse when its pressed, otherwise '0'.
constant BTN_ACTIVE : std_logic := '1';

signal count : integer := 0;
type state_type is (idle,wait_time); --state machine
signal state : state_type := idle;

begin
  
process(Reset,Clock)
begin
    if(Reset = '1') then
        state <= idle;
        pulse_out <= '0';
   elsif(rising_edge(Clock)) then
        case (state) is
            when idle =>
                if(button_in = BTN_ACTIVE) then  
                    state <= wait_time;
                else
                    state <= idle; --wait until button is pressed.
                end if;
                pulse_out <= '0';
            when wait_time =>
                if(count = COUNT_MAX) then
                    count <= 0;
                    if(button_in = BTN_ACTIVE) then
                        pulse_out <= '1';
                    end if;
                    state <= idle;  
                else
                    count <= count + 1;
                end if; 
        end case;       
    end if;        
end process;                  
                                                                                
end architecture behav;

Testbench code for DeBouncer circuit:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
 
ENTITY tb_alu IS
END tb_alu;
 
ARCHITECTURE behavior OF tb_alu IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT DeBounce
    PORT(
         Clock : IN  std_logic;
         Reset : IN  std_logic;
         button_in : IN  std_logic;
         pulse_out : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal Clock : std_logic := '0';
   signal Reset : std_logic := '0';
   signal button_in : std_logic := '0';

    --Outputs
   signal pulse_out : std_logic;

   -- Clock period definitions
   constant Clock_period : time := 10 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: DeBounce PORT MAP (
          Clock => Clock,
          Reset => Reset,
          button_in => button_in,
          pulse_out => pulse_out
        );

   -- Clock process definitions
   Clock_process :process
   begin
        Clock <= '0';
        wait for Clock_period/2;
        Clock <= '1';
        wait for Clock_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin        
        button_in <= '0';
        reset <= '1';
      -- hold reset state for 100 ns.
      wait for 100 ns;
        reset <= '0';
      wait for Clock_period*10;
        --first activity
        button_in <= '1';   wait for Clock_period*2;
        button_in <= '0';   wait for Clock_period*1;
        button_in <= '1';   wait for Clock_period*1;
        button_in <= '0';   wait for Clock_period*20;
        --second activity
        button_in <= '1';   wait for Clock_period*1;
        button_in <= '0';   wait for Clock_period*1;
        button_in <= '1';   wait for Clock_period*1;
        button_in <= '0';   wait for Clock_period*2;
        button_in <= '1';   wait for Clock_period*20;
        button_in <= '0';   
      wait;
   end process;

END;

Simulation waveform from Xilinx ISE:



The design was synthesised successfully using Xilinx ISE 14.6.  Before you use the code in your design, make sure you choose the correct values for COUNT_MAX and  BTN_ACTIVE.