113 lines
4.2 KiB
VHDL
113 lines
4.2 KiB
VHDL
-- filename: debounced.vhd
|
|
-- kind: vhdl file
|
|
-- first created: 11.01.2024
|
|
-- created by: boy
|
|
--------------------------------------------------------------------------------
|
|
-- History:
|
|
-- v0.1 : boy 11.01.2024 -- Initial Version
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Description:
|
|
-- debounceds a button on both edges.
|
|
-- _ _ ____________________ _ _
|
|
-- input ____/ \_/ \_/ \_/ \_/ \______
|
|
-- _____________________________
|
|
-- output __________________/ \____________
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
-- Generics:
|
|
-- g_debounceTime (time) : parameter to fix the debounce time.
|
|
-- g_minConsecutiveStateCount (integer) : The number of consecutive readings of the same state required to change the output.
|
|
-- g_clockFrequency (real) : Clock frequency of the system
|
|
-- g_activeState (std_ulogic) : The output will be reset in "inactive" state.
|
|
--------------------------------------------------------------------------------
|
|
-- Input is read each g_debounceTime, and a constant value must appear for
|
|
-- g_minConsecutiveStateCount to be forwarded on the output.
|
|
-- To update the output, x consecutive samples needs to have
|
|
-- the exact same value. x is given with the "g_minConsecutiveStateCount" parameter
|
|
--------------------------------------------------------------------------------
|
|
LIBRARY ieee;
|
|
USE ieee.math_real.all;
|
|
LIBRARY Common;
|
|
USE Common.CommonLib.all;
|
|
|
|
|
|
ARCHITECTURE rtl OF debounce IS
|
|
|
|
-- Creates a vector of alternating 1's and 0's (0b...1010)
|
|
pure function alternating_ones_and_zeros(length : integer) return std_ulogic_vector is
|
|
variable ret_val : std_ulogic_vector(length - 1 downto 0);
|
|
BEGIN
|
|
for i in 0 to length - 1 loop
|
|
if i mod 2 = 1 then
|
|
ret_val(i) := '1';
|
|
else
|
|
ret_val(i) := '0';
|
|
end if;
|
|
end loop;
|
|
|
|
return ret_val;
|
|
end function alternating_ones_and_zeros;
|
|
|
|
-- To check if all bits are '1'
|
|
constant c_LOGICAL_HIGH_VALID: std_ulogic_vector((g_minConsecutiveStateCount-1) downto 0) := (others=>'1');
|
|
-- To check if all bits are '0'
|
|
constant c_LOGICAL_LOW_VALID: std_ulogic_vector((g_minConsecutiveStateCount-1) downto 0) := (others=>'0');
|
|
-- Alternating 1's and 0's for reset value
|
|
constant c_INIT_SAMPLE: std_ulogic_vector((g_minConsecutiveStateCount-1) downto 0) := alternating_ones_and_zeros(g_minConsecutiveStateCount);
|
|
-- Delay between two samplings
|
|
-- delay = (g_debounceTime * g_clockFrequency) / g_minConsecutiveStateCount - 1
|
|
constant DELAY: positive := integer(ceil(((real(g_debounceTime / 1 ps) / 1.0e12) * g_clockFrequency) / real(g_minConsecutiveStateCount))) - 1;
|
|
|
|
-- Holds the state of registered consecutive inputs
|
|
signal lvec_sample: std_ulogic_vector((g_minConsecutiveStateCount-1) downto 0);
|
|
-- Defines when we will sample (based on given DELAY)
|
|
signal lsig_samplePulse: std_ulogic := '0';
|
|
-- Counter for the delay
|
|
signal lvec_count : unsigned(requiredBitNb(DELAY)-1 downto 0);
|
|
|
|
BEGIN
|
|
|
|
clockDivider: process(reset, clock) --Clock Divider
|
|
begin
|
|
if reset = '1' then
|
|
lvec_count <= (others => '0');
|
|
lsig_samplePulse <= '0';
|
|
elsif rising_edge(clock) then
|
|
if (lvec_count < DELAY) then
|
|
lvec_count <= lvec_count + 1;
|
|
lsig_samplePulse <= '0';
|
|
else
|
|
lvec_count <= (others => '0');
|
|
lsig_samplePulse <= '1';
|
|
end if;
|
|
end if;
|
|
end process clockDivider;
|
|
|
|
sampling: process(reset, clock) --Sampling Process
|
|
begin
|
|
if reset = '1' then
|
|
lvec_sample <= c_INIT_SAMPLE;
|
|
elsif rising_edge(clock) then
|
|
if lsig_samplePulse = '1' then
|
|
lvec_sample((g_minConsecutiveStateCount - 1) downto 1) <= lvec_sample((g_minConsecutiveStateCount - 2) downto 0); -- Left Shift
|
|
lvec_sample(0) <= input;
|
|
end if;
|
|
end if;
|
|
end process sampling;
|
|
|
|
inputDebouncing: process(reset, clock) --Input Debouncing
|
|
begin
|
|
if reset = '1' then
|
|
debounced <= not g_activeState;
|
|
elsif rising_edge(clock) then
|
|
if lvec_sample = c_LOGICAL_HIGH_VALID then --Active High Constant Out
|
|
debounced <= '1';
|
|
elsif lvec_sample = c_LOGICAL_LOW_VALID then
|
|
debounced <= '0';
|
|
end if;
|
|
end if;
|
|
end process inputDebouncing;
|
|
END ARCHITECTURE rtl;
|
|
|