-
Notifications
You must be signed in to change notification settings - Fork 383
/
debounce_v2.sv
126 lines (100 loc) · 3.05 KB
/
debounce_v2.sv
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
//------------------------------------------------------------------------------
// debounce_v2.sv
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// Button debounce v2, SystemVerilog version
//
// - sampling inputs using configurable divided clock (this is the
// simplest form of low-pass filter)
//
// - in contrast with debounce_v1.v this implementation is switching output only
// when input had stable level IN ALL CLOCK CYCLES within the sample window
// (this gives some form of hysteresis in case we sample unstable data)
//
/* --- INSTANTIATION TEMPLATE BEGIN ---
debounce_v2 #(
.WIDTH( 4 ),
.SAMPLING_FACTOR( 16 )
) DB1 (
.clk( clk ),
.nrst( 1'b1 ),
.ena( 1'b1 ),
.in( btn[3:0] ),
.out( btn_db[3:0] )
);
--- INSTANTIATION TEMPLATE END ---*/
module debounce_v2 #( parameter
WIDTH = 1,
SAMPLING_FACTOR = 16, // 0 - sampling every clk
// 1 - sampling on clk/2
// 2 - sampling on clk/4 etc....
// only one or none should be enabled
TREAT_UNSTABLE_AS_HIGH = 0,
TREAT_UNSTABLE_AS_LOW = 0
)(
input clk,
input nrst,
input ena,
input [WIDTH-1:0] in,
output logic [WIDTH-1:0] out = '0
);
localparam SAMPLING_RANGE = 32;
logic [SAMPLING_RANGE-1:0] s_clk;
clk_divider #(
.WIDTH( SAMPLING_RANGE )
) clk_div (
.clk( clk ),
.nrst( nrst ),
.ena( 1'b1 ),
.out( s_clk[SAMPLING_RANGE-1:0] )
);
logic [SAMPLING_RANGE-1:0] s_clk_rise;
edge_detect #(
.WIDTH( SAMPLING_RANGE )
) clk_div_ed (
.clk( clk ),
.anrst( nrst ),
.in( s_clk[SAMPLING_RANGE-1:0] ),
.rising( s_clk_rise[SAMPLING_RANGE-1:0] )
);
wire do_sample;
assign do_sample = s_clk_rise[SAMPLING_FACTOR];
logic [WIDTH-1:0] in_is_high = '0;
logic [WIDTH-1:0] in_is_low = '0;
always_ff @(posedge clk) begin
if (~nrst) begin
out[WIDTH-1:0] <= '0;
in_is_high[WIDTH-1:0] <= '0;
in_is_low[WIDTH-1:0] <= '0;
end else if (ena && do_sample) begin
// making decisions for outputs
for (integer i = 0; i < WIDTH; i++) begin
case ( {in_is_high[i],in_is_low[i]} )
2'b01: out[i] <= 1'b0;
2'b10: out[i] <= 1'b1;
default: begin
if (TREAT_UNSTABLE_AS_HIGH) begin
out[i] <= 1'b1;
end else if (TREAT_UNSTABLE_AS_LOW) begin
out[i] <= 1'b0;
end
end
endcase
end // for
// resetting flags to initialize new sample window
in_is_high[WIDTH-1:0] <= '0;
in_is_low[WIDTH-1:0] <= '0;
end else begin
// collecting data
for (integer i = 0; i < WIDTH; i++) begin
if ( in[i] ) begin
in_is_high[i] <= 1'b1;
end else begin
in_is_low[i] <= 1'b1;
end
end // for
end // if
end
endmodule