forked from open-logic/open-logic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
olo_intf_debounce.vhd
187 lines (159 loc) · 6.19 KB
/
olo_intf_debounce.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
------------------------------------------------------------------------------
-- Copyright (c) 2024 by Oliver Bründler
-- All rights reserved.
-- Authors: Oliver Bruendler
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Description
------------------------------------------------------------------------------
-- This is a debouncer for button and switch inputs. It contains a
-- double stage synchronizer to synchronize those inputs to the clock.
------------------------------------------------------------------------------
-- Libraries
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library work;
use work.olo_base_pkg_array.all;
------------------------------------------------------------------------------
-- Entity
------------------------------------------------------------------------------
entity olo_intf_debounce is
generic (
ClkFrequency_g : real;
DebounceTime_g : real := 20.0e-3;
Width_g : positive := 1;
IdleLevel_g : std_logic := '0';
Mode_g : string := "LOW_LATENCY" -- LOW_LATENCY or GLITCH_FILTER
);
port (
-- control signals
Clk : in std_logic;
Rst : in std_logic;
-- Input clock domain
DataAsync : in std_logic_vector(Width_g - 1 downto 0);
DataOut : out std_logic_vector(Width_g - 1 downto 0)
);
end entity;
------------------------------------------------------------------------------
-- Architecture
------------------------------------------------------------------------------
architecture struct of olo_intf_debounce is
-- Time Constants
-- Idea is to have a counter in the range 15-31 for each bit
constant TargetTickFrequency_c : real := 1.0/(DebounceTime_g/31.0);
constant TickCycles_c : real := ceil(ClkFrequency_g/TargetTickFrequency_c);
constant ActualTickFrequency_c : real := ClkFrequency_g/TickCycles_c;
constant DebounceTicks_c : integer := integer(ceil(DebounceTime_g*ActualTickFrequency_c));
constant UseStrobeDiv_c : boolean := integer(TickCycles_c) >= 2;
-- Other Constants
constant Bits_c : integer := DataAsync'length;
-- Instantiation Signals
signal DataSync : std_logic_vector(DataAsync'range);
signal Tick : std_logic;
-- Two Process Signals
subtype Cnt_t is integer range 0 to DebounceTicks_c;
type Cnt_a is array (0 to Bits_c-1) of Cnt_t;
type two_process_r is record
StableCnt : Cnt_a;
LastState : std_logic_vector(Bits_c-1 downto 0);
IsStable : std_logic_vector(Bits_c-1 downto 0);
DataOut : std_logic_vector(Bits_c-1 downto 0);
end record;
signal r, r_next : two_process_r;
begin
assert Mode_g = "GLITCH_FILTER" or Mode_g = "LOW_LATENCY"
report "olo_intf_debounce: Illegal Mode_g - " & Mode_g
severity failure;
assert DebounceTicks_c >= 10
report "olo_intf_debounce: DebounceTime too short (must be >= 10 clock cycles) - " &
"DebounceTime_g=" & real'image(DebounceTime_g) & " ClkFrequency_g=" & real'image(ClkFrequency_g)
severity failure;
-- *** Combinatorial Process ***
i_comb : process(r, DataSync, Tick)
variable v : two_process_r;
begin
-- Hold variables stable
v := r;
for i in 0 to DataAsync'length-1 loop
-- Counter Update & Stablity Detection
if Tick = '1' then
if r.StableCnt(i) = DebounceTicks_c then
v.IsStable(i) := '1';
else
v.StableCnt(i) := r.Stablecnt(i) + 1;
end if;
end if;
-- Reset counters on state change
if DataSync(i) /= r.LastState(i) then
v.StableCnt(i) := 0;
v.IsStable(i) := '0';
end if;
-- GLITCH_FILTER mode
if Mode_g = "GLITCH_FILTER" then
-- Only forward signal once stable
if r.IsStable(i) = '1' then
v.DataOut(i) := r.LastState(i);
end if;
end if;
-- LOW_LATENCY mode
if Mode_g = "LOW_LATENCY" then
-- Forward new state whenever signal is stable (including first edge)
if r.IsStable(i) = '1' then
v.DataOut(i) := DataSync(i);
end if;
end if;
end loop;
v.LastState := DataSync;
-- Outputs
DataOut <= r.DataOut;
-- Assign to signal
r_next <= v;
end process;
-- *** Sequential Process ***
i_seq : process(Clk)
begin
if rising_edge(Clk) then
-- normal operation
r <= r_next;
-- reset
if Rst = '1' then
r.StableCnt <= (others => DebounceTicks_c);
r.LastState <= (others => IdleLevel_g);
r.IsStable <= (others => '1');
r.DataOut <= (others => IdleLevel_g);
end if;
end if;
end process;
-- *** Component Instantiations ***
-- Synchronizer
i_sync : entity work.olo_intf_sync
generic map (
Width_g => Width_g,
RstLevel_g => IdleLevel_g
)
port map (
Clk => Clk,
Rst => Rst,
DataAsync => DataAsync,
DataSync => DataSync
);
-- Tick Generator
g_use_strobe : if UseStrobeDiv_c generate
i_tickgen : entity work.olo_base_strobe_gen
generic map (
FreqClkHz_g => ClkFrequency_g,
FreqStrobeHz_g => ActualTickFrequency_c
)
port map (
Clk => Clk,
Rst => Rst,
Out_Valid => Tick
);
end generate;
g_no_strobe : if not UseStrobeDiv_c generate
Tick <= '1';
end generate;
end architecture;