Skip to content

Commit 93106db

Browse files
Add glitch filter to common I2C blocks
1 parent 6e2c16a commit 93106db

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

hdl/ip/vhd/i2c/common/BUCK

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ vhdl_unit(
1212
visibility = ['PUBLIC']
1313
)
1414

15+
vhdl_unit(
16+
name = "i2c_glitch_filter",
17+
srcs = ["i2c_glitch_filter.vhd"],
18+
deps = [
19+
"//hdl/ip/vhd/synchronizers:meta_sync",
20+
],
21+
visibility = ['PUBLIC']
22+
)
23+
1524
vhdl_unit(
1625
name = "i2c_target_vc",
1726
srcs = ["sims/i2c_target_vc.vhd", "sims/i2c_target_vc_pkg.vhd"],
+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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

Comments
 (0)