Skip to content

Commit d0bf49a

Browse files
committed
SPI SLAVE [BUGFIX]: Add sync FFs to eliminate metastability
1 parent 92b5e90 commit d0bf49a

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

rtl/spi_slave.vhd

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ architecture RTL of SPI_SLAVE is
5757

5858
constant BIT_CNT_WIDTH : natural := natural(ceil(log2(real(WORD_SIZE))));
5959

60+
signal sclk_meta : std_logic;
61+
signal cs_n_meta : std_logic;
62+
signal mosi_meta : std_logic;
63+
signal sclk_reg : std_logic;
64+
signal cs_n_reg : std_logic;
65+
signal mosi_reg : std_logic;
6066
signal spi_clk_reg : std_logic;
6167
signal spi_clk_redge_en : std_logic;
6268
signal spi_clk_fedge_en : std_logic;
@@ -71,6 +77,23 @@ architecture RTL of SPI_SLAVE is
7177

7278
begin
7379

80+
-- -------------------------------------------------------------------------
81+
-- INPUT SYNCHRONIZATION REGISTERS
82+
-- -------------------------------------------------------------------------
83+
84+
-- Synchronization registers to eliminate possible metastability.
85+
sync_ffs_p : process (CLK)
86+
begin
87+
if (rising_edge(CLK)) then
88+
sclk_meta <= SCLK;
89+
cs_n_meta <= CS_N;
90+
mosi_meta <= MOSI;
91+
sclk_reg <= sclk_meta;
92+
cs_n_reg <= cs_n_meta;
93+
mosi_reg <= mosi_meta;
94+
end if;
95+
end process;
96+
7497
-- -------------------------------------------------------------------------
7598
-- SPI CLOCK REGISTER
7699
-- -------------------------------------------------------------------------
@@ -82,7 +105,7 @@ begin
82105
if (RST = '1') then
83106
spi_clk_reg <= '0';
84107
else
85-
spi_clk_reg <= SCLK;
108+
spi_clk_reg <= sclk_reg;
86109
end if;
87110
end if;
88111
end process;
@@ -91,23 +114,23 @@ begin
91114
-- SPI CLOCK EDGES FLAGS
92115
-- -------------------------------------------------------------------------
93116

94-
-- Falling edge is detect when SCLK=0 and spi_clk_reg=1.
95-
spi_clk_fedge_en <= not SCLK and spi_clk_reg;
96-
-- Rising edge is detect when SCLK=1 and spi_clk_reg=0.
97-
spi_clk_redge_en <= SCLK and not spi_clk_reg;
117+
-- Falling edge is detect when sclk_reg=0 and spi_clk_reg=1.
118+
spi_clk_fedge_en <= not sclk_reg and spi_clk_reg;
119+
-- Rising edge is detect when sclk_reg=1 and spi_clk_reg=0.
120+
spi_clk_redge_en <= sclk_reg and not spi_clk_reg;
98121

99122
-- -------------------------------------------------------------------------
100123
-- RECEIVED BITS COUNTER
101124
-- -------------------------------------------------------------------------
102125

103126
-- The counter counts received bits from the master. Counter is enabled when
104-
-- falling edge of SPI clock is detected and not asserted CS_N.
127+
-- falling edge of SPI clock is detected and not asserted cs_n_reg.
105128
bit_cnt_p : process (CLK)
106129
begin
107130
if (rising_edge(CLK)) then
108131
if (RST = '1') then
109132
bit_cnt <= (others => '0');
110-
elsif (spi_clk_fedge_en = '1' and CS_N = '0') then
133+
elsif (spi_clk_fedge_en = '1' and cs_n_reg = '0') then
111134
if (bit_cnt_max = '1') then
112135
bit_cnt <= (others => '0');
113136
else
@@ -156,7 +179,7 @@ begin
156179
if (RST = '1') then
157180
shreg_busy <= '0';
158181
else
159-
if (DIN_VLD = '1' and (CS_N = '1' or rx_data_vld = '1')) then
182+
if (DIN_VLD = '1' and (cs_n_reg = '1' or rx_data_vld = '1')) then
160183
shreg_busy <= '1';
161184
elsif (rx_data_vld = '1') then
162185
shreg_busy <= '0';
@@ -167,9 +190,9 @@ begin
167190
end if;
168191
end process;
169192

170-
-- The SPI slave is ready for accept new input data when CS_N is assert and
193+
-- The SPI slave is ready for accept new input data when cs_n_reg is assert and
171194
-- shift register not busy or when received data are valid.
172-
slave_ready <= (CS_N and not shreg_busy) or rx_data_vld;
195+
slave_ready <= (cs_n_reg and not shreg_busy) or rx_data_vld;
173196

174197
-- The new input data is loaded into the shift register when the SPI slave
175198
-- is ready and input data are valid.
@@ -186,8 +209,8 @@ begin
186209
if (rising_edge(CLK)) then
187210
if (load_data_en = '1') then
188211
data_shreg <= DIN;
189-
elsif (spi_clk_redge_en = '1' and CS_N = '0') then
190-
data_shreg <= data_shreg(WORD_SIZE-2 downto 0) & MOSI;
212+
elsif (spi_clk_redge_en = '1' and cs_n_reg = '0') then
213+
data_shreg <= data_shreg(WORD_SIZE-2 downto 0) & mosi_reg;
191214
end if;
192215
end if;
193216
end process;
@@ -197,13 +220,13 @@ begin
197220
-- -------------------------------------------------------------------------
198221

199222
-- The output MISO register ensures that the bits are transmit to the master
200-
-- when is not assert CS_N and falling edge of SPI clock is detected.
223+
-- when is not assert cs_n_reg and falling edge of SPI clock is detected.
201224
miso_p : process (CLK)
202225
begin
203226
if (rising_edge(CLK)) then
204227
if (load_data_en = '1') then
205228
MISO <= DIN(WORD_SIZE-1);
206-
elsif (spi_clk_fedge_en = '1' and CS_N = '0') then
229+
elsif (spi_clk_fedge_en = '1' and cs_n_reg = '0') then
207230
MISO <= data_shreg(WORD_SIZE-1);
208231
end if;
209232
end if;

0 commit comments

Comments
 (0)