1
+ -- This Source Code Form is subject to the terms of the Mozilla Public
2
+ -- License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ -- file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ --
5
+ -- Copyright 2024 Oxide Computer Company
6
+
7
+ -- Simple i2c glitch filtering for targets I2C spec
8
+ -- This block incurs a delay of 1 sync cycle and n filter cycles
9
+ -- on both of these lines.
10
+ -- This filter is implemented as a pipeline of n register stages
11
+ -- with the output registers only being toggled when all n register
12
+ -- outputs are the same.
13
+ -- we also provide some edge detection signals since we already
14
+ -- have the last value of each of the lines.
15
+
16
+ library ieee;
17
+ use ieee.std_logic_1164.all ;
18
+ use ieee.numeric_std.all ;
19
+ use ieee.numeric_std_unsigned.all ;
20
+
21
+ entity i2c_glitch_filter is
22
+ generic (
23
+ -- number of register stages the n filter pipeline
24
+ filter_cycles : integer := 5
25
+ );
26
+ port (
27
+ clk : in std_logic ;
28
+ reset : in std_logic ;
29
+ -- raw i2c signals needing to be filtered
30
+ raw_scl : in std_logic ;
31
+ raw_sda : in std_logic ;
32
+ -- scl outputs post-filtering
33
+ filtered_scl : out std_logic ;
34
+ scl_fedge : out std_logic ;
35
+ scl_redge : out std_logic ;
36
+ -- sda outputs post-filtering
37
+ filtered_sda : out std_logic ;
38
+ sda_fedge : out std_logic ;
39
+ sda_redge : out std_logic
40
+ );
41
+ end entity i2c_glitch_filter ;
42
+
43
+ architecture rtl of i2c_glitch_filter is
44
+ constant ones : std_logic_vector (filter_cycles - 1 downto 0 ) := (others => '1' );
45
+ constant zeros : std_logic_vector (filter_cycles - 1 downto 0 ) := (others => '0' );
46
+ signal sda_syncd : std_logic ;
47
+ signal scl_syncd : std_logic ;
48
+ signal scl_pipe : std_logic_vector (filter_cycles - 1 downto 0 );
49
+ signal sda_pipe : std_logic_vector (filter_cycles - 1 downto 0 );
50
+ signal last_scl : std_logic ;
51
+ signal last_sda : std_logic ;
52
+ begin
53
+
54
+ scl_meta :entity work .meta_sync
55
+ generic map (
56
+ stages => 1
57
+ )
58
+ port map (
59
+ async_input => raw_scl,
60
+ clk => clk,
61
+ sycnd_output => scl_syncd
62
+ );
63
+ sda_meta :entity work .meta_sync
64
+ generic map (
65
+ stages => 1
66
+ )
67
+ port map (
68
+ async_input => raw_sda,
69
+ clk => clk,
70
+ sycnd_output => sda_syncd
71
+ );
72
+
73
+ process (clk, reset)
74
+ variable nxt_scl_pipe : std_logic_vector (filter_cycles - 1 downto 0 );
75
+ variable nxt_sda_pipe : std_logic_vector (filter_cycles - 1 downto 0 );
76
+ begin
77
+ if reset = '1' then
78
+ scl_pipe <= (others => '1' );
79
+ sda_pipe <= (others => '1' );
80
+ filtered_scl <= '1' ;
81
+ filtered_sda <= '1' ;
82
+ last_scl <= '1' ;
83
+ last_sda <= '1' ;
84
+ elsif rising_edge (clk) then
85
+ last_scl <= filtered_scl;
86
+ last_sda <= filtered_sda;
87
+ -- Using variables here to make the filtered outputs
88
+ -- simultaneous more easily
89
+ nxt_scl_pipe := shift_left (scl_pipe, 1 );
90
+ nxt_scl_pipe(0 ) := scl_syncd;
91
+ scl_pipe <= nxt_scl_pipe; -- do the register assignment
92
+ nxt_sda_pipe := shift_left (sda_pipe, 1 );
93
+ nxt_sda_pipe(0 ) := sda_syncd;
94
+ sda_pipe <= nxt_sda_pipe; -- do the register assignment
95
+
96
+ -- we use the variables set above here to make the filtered outputs
97
+ -- toggle simultaneously with the pipe filling and not incur
98
+ -- an additional cycle of delay;
99
+ filtered_scl <= '1' when nxt_scl_pipe = ones else
100
+ '0' when nxt_scl_pipe = zeros else
101
+ filtered_scl;
102
+ filtered_sda <= '1' when nxt_sda_pipe = ones else
103
+ '0' when nxt_sda_pipe = zeros else
104
+ filtered_sda;
105
+ end if ;
106
+
107
+ end process ;
108
+ sda_fedge <= not filtered_sda and last_sda;
109
+ sda_redge <= filtered_sda and not last_sda;
110
+
111
+ scl_fedge <= not filtered_scl and last_scl;
112
+ scl_redge <= filtered_scl and not last_scl;
113
+
114
+ end architecture rtl ;
0 commit comments