Skip to content

Commit b6c6a00

Browse files
committed
Added SPI_MASTER and SPI_MASTER_TB
1 parent a2ba008 commit b6c6a00

File tree

2 files changed

+456
-0
lines changed

2 files changed

+456
-0
lines changed

rtl/spi_master.vhd

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
--------------------------------------------------------------------------------
2+
-- PROJECT: SPI MASTER CONTROLLER FOR FPGA
3+
--------------------------------------------------------------------------------
4+
-- MODULE NAME: SPI_MASTER
5+
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
6+
-- LICENSE: LGPL-3.0, please read LICENSE file
7+
-- WEBSITE: https://github.com/jakubcabal/spi_master_fpga
8+
-- USED TOOLS: Quartus II 13.0 SP1
9+
-- CREATE DATE: 02.06.‎2016
10+
--------------------------------------------------------------------------------
11+
-- COPYRIGHT NOTICE:
12+
--------------------------------------------------------------------------------
13+
-- SPI MASTER CONTROLLER FOR FPGA
14+
-- Copyright (C) 2016 Jakub Cabal
15+
--
16+
-- This source file is free software: you can redistribute it and/or modify
17+
-- it under the terms of the GNU Lesser General Public License as published by
18+
-- the Free Software Foundation, either version 3 of the License, or
19+
-- (at your option) any later version.
20+
--
21+
-- This source file is distributed in the hope that it will be useful,
22+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
23+
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24+
-- GNU Lesser General Public License for more details.
25+
--
26+
-- You should have received a copy of the GNU Lesser General Public License
27+
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
28+
--------------------------------------------------------------------------------
29+
30+
library IEEE;
31+
use IEEE.STD_LOGIC_1164.ALL;
32+
use IEEE.NUMERIC_STD.ALL;
33+
use IEEE.MATH_REAL.ALL;
34+
35+
-- MY SPI MASTER MODULE SUPPORT ONLY SPI MODE 0 (CPOL=0, CPHA=0)!!!
36+
37+
entity SPI_MASTER is
38+
Generic (
39+
CLK_FREQ : integer := 50; -- set system clock frequency in MHz
40+
SCLK_FREQ : integer := 5; -- set SPI clock frequency in MHz (must be < CLK_FREQ/9)
41+
DATA_WIDTH : integer := 8 -- set SPI datawidth in bits
42+
);
43+
Port (
44+
CLK : in std_logic; -- system clock
45+
RST : in std_logic; -- high active synchronous reset
46+
-- SPI MASTER INTERFACE
47+
SCLK : out std_logic;
48+
CS_N : out std_logic;
49+
MOSI : out std_logic;
50+
MISO : in std_logic;
51+
-- USER INTERFACE
52+
DIN : in std_logic_vector(DATA_WIDTH-1 downto 0);
53+
DIN_VLD : in std_logic; -- when DIN_VLD = 1, data on DIN are valid and will be transmit
54+
READY : out std_logic; -- when READY = 1, SPI master is ready to accept data on DIN
55+
DOUT : out std_logic_vector(DATA_WIDTH-1 downto 0);
56+
DOUT_VLD : out std_logic -- when DOUT_VLD = 1, data on DOUT are valid
57+
);
58+
end SPI_MASTER;
59+
60+
architecture FULL of SPI_MASTER is
61+
62+
constant DIVIDER_VALUE_REAL : real := (real(CLK_FREQ)/real(SCLK_FREQ))/2.0;
63+
constant DIVIDER_VALUE : integer := integer(ceil(DIVIDER_VALUE_REAL));
64+
constant WIDTH_CLK_CNT : integer := integer(ceil(log2(real(DIVIDER_VALUE))));
65+
constant WIDTH_BIT_CNT : integer := integer(ceil(log2(real(DATA_WIDTH))));
66+
67+
signal sys_clk_cnt : unsigned(WIDTH_CLK_CNT-1 downto 0);
68+
signal spi_clk : std_logic;
69+
signal spi_clk_reg0 : std_logic;
70+
signal spi_clk_reg1 : std_logic;
71+
signal spi_clk_rising_edge_en1 : std_logic;
72+
signal spi_clk_falling_edge_en0 : std_logic;
73+
signal spi_clk_falling_edge_en1 : std_logic;
74+
signal spi_clk_en_set : std_logic;
75+
signal spi_chip_select_n : std_logic;
76+
signal spi_mosi_reg : std_logic;
77+
signal spi_mosi_reg_en : std_logic;
78+
signal spi_mosi_reg_load : std_logic;
79+
signal spi_shreg : std_logic_vector(DATA_WIDTH-1 downto 0);
80+
signal spi_shreg_en : std_logic;
81+
signal spi_shreg_load : std_logic;
82+
signal spi_bit_cnt : unsigned(WIDTH_BIT_CNT-1 downto 0);
83+
signal spi_bit_cnt_en : std_logic;
84+
signal spi_last_bit : std_logic;
85+
signal spi_dout_vld : std_logic;
86+
signal spi_ready : std_logic;
87+
88+
type state is (idle, transmit, check_data);
89+
signal present_state, next_state : state;
90+
91+
begin
92+
93+
ASSERT (DIVIDER_VALUE_REAL > 4.5) REPORT "SCLK_FREQ must be < CLK_FREQ/9" SEVERITY ERROR;
94+
95+
spi_shreg_load <= spi_ready AND DIN_VLD;
96+
spi_shreg_en <= spi_clk_rising_edge_en1;
97+
spi_mosi_reg_load <= spi_shreg_load;
98+
spi_mosi_reg_en <= spi_clk_falling_edge_en1;
99+
spi_bit_cnt_en <= spi_clk_falling_edge_en1 AND NOT spi_chip_select_n;
100+
spi_clk_en_set <= spi_clk_falling_edge_en0;
101+
spi_dout_vld <= spi_clk_falling_edge_en0 AND spi_last_bit;
102+
103+
SCLK <= spi_clk_reg1;
104+
CS_N <= spi_chip_select_n;
105+
MOSI <= spi_mosi_reg;
106+
READY <= spi_ready;
107+
DOUT <= spi_shreg;
108+
109+
-- -------------------------------------------------------------------------
110+
-- SPI MASTER CLOCK
111+
-- -------------------------------------------------------------------------
112+
113+
sys_clk_cnt_reg_p : process (CLK)
114+
begin
115+
if (rising_edge(CLK)) then
116+
if (RST = '1' OR spi_chip_select_n = '1') then
117+
sys_clk_cnt <= (others => '0');
118+
else
119+
if (to_integer(sys_clk_cnt) = DIVIDER_VALUE-1) then
120+
sys_clk_cnt <= (others => '0');
121+
else
122+
sys_clk_cnt <= sys_clk_cnt + 1;
123+
end if;
124+
end if;
125+
end if;
126+
end process;
127+
128+
spi_clk_gen_p : process (CLK)
129+
begin
130+
if (rising_edge(CLK)) then
131+
if (RST = '1') then
132+
spi_clk <= '0';
133+
elsif (to_integer(sys_clk_cnt) = DIVIDER_VALUE-1) then
134+
spi_clk <= NOT spi_clk;
135+
end if;
136+
end if;
137+
end process;
138+
139+
spi_clk_reg_p : process (CLK)
140+
begin
141+
if (rising_edge(CLK)) then
142+
if (RST = '1') then
143+
spi_clk_reg0 <= '0';
144+
spi_clk_reg1 <= '0';
145+
else
146+
spi_clk_reg0 <= spi_clk;
147+
spi_clk_reg1 <= spi_clk_reg0;
148+
end if;
149+
end if;
150+
end process;
151+
152+
-- -------------------------------------------------------------------------
153+
-- SPI MASTER CLOCK EDGES FLAGS
154+
-- -------------------------------------------------------------------------
155+
156+
spi_clk_falling_edge_en0 <= '1' WHEN ((spi_clk = '0') AND (spi_clk_reg0 = '1')) ELSE '0';
157+
spi_clk_falling_edge_en1 <= '1' WHEN ((spi_clk_reg0 = '0') AND (spi_clk_reg1 = '1')) ELSE '0';
158+
spi_clk_rising_edge_en1 <= '1' WHEN ((spi_clk_reg0 = '1') AND (spi_clk_reg1 = '0')) ELSE '0';
159+
160+
-- -------------------------------------------------------------------------
161+
-- SPI MASTER MOSI REGISTER
162+
-- -------------------------------------------------------------------------
163+
164+
spi_mosi_reg_p : process (CLK)
165+
begin
166+
if (rising_edge(CLK)) then
167+
if (spi_mosi_reg_load = '1') then
168+
spi_mosi_reg <= DIN(DATA_WIDTH-1);
169+
elsif (spi_mosi_reg_en = '1') then
170+
spi_mosi_reg <= spi_shreg(DATA_WIDTH-1);
171+
end if;
172+
end if;
173+
end process;
174+
175+
-- -------------------------------------------------------------------------
176+
-- SPI MASTER SHIFT REGISTER
177+
-- -------------------------------------------------------------------------
178+
179+
spi_shreg_p : process (CLK)
180+
begin
181+
if (rising_edge(CLK)) then
182+
if (spi_shreg_load = '1') then
183+
spi_shreg <= DIN;
184+
elsif (spi_shreg_en = '1') then
185+
spi_shreg <= spi_shreg(DATA_WIDTH-2 downto 0) & MISO;
186+
end if;
187+
end if;
188+
end process;
189+
190+
-- -------------------------------------------------------------------------
191+
-- SPI MASTER DATA OUT VALID FLAG REGISTER
192+
-- -------------------------------------------------------------------------
193+
194+
spi_dout_vld_reg_p : process (CLK)
195+
begin
196+
if (rising_edge(CLK)) then
197+
if (RST = '1') then
198+
DOUT_VLD <= '0';
199+
else
200+
DOUT_VLD <= spi_dout_vld;
201+
end if;
202+
end if;
203+
end process;
204+
205+
-- -------------------------------------------------------------------------
206+
-- SPI MASTER BIT COUNTER REGISTERS
207+
-- -------------------------------------------------------------------------
208+
209+
spi_bit_cnt_reg_p : process (CLK)
210+
begin
211+
if (rising_edge(CLK)) then
212+
if (RST = '1') then
213+
spi_bit_cnt <= (others => '0');
214+
elsif (spi_bit_cnt_en = '1') then
215+
if (spi_bit_cnt = to_unsigned(DATA_WIDTH-1, spi_bit_cnt'length)) then
216+
spi_bit_cnt <= (others => '0');
217+
else
218+
spi_bit_cnt <= spi_bit_cnt + 1;
219+
end if;
220+
end if;
221+
end if;
222+
end process;
223+
224+
-- -------------------------------------------------------------------------
225+
-- SPI MASTER LAST BIT FLAG REGISTER
226+
-- -------------------------------------------------------------------------
227+
228+
spi_last_bit_reg_p : process (CLK)
229+
begin
230+
if (rising_edge(CLK)) then
231+
if (RST = '1') then
232+
spi_last_bit <= '0';
233+
else
234+
if (spi_bit_cnt = to_unsigned(DATA_WIDTH-1, spi_bit_cnt'length)) then
235+
spi_last_bit <= '1';
236+
else
237+
spi_last_bit <= '0';
238+
end if;
239+
end if;
240+
end if;
241+
end process;
242+
243+
-- -------------------------------------------------------------------------
244+
-- SPI MASTER FSM
245+
-- -------------------------------------------------------------------------
246+
247+
-- PRESENT STATE REGISTER
248+
process (CLK)
249+
begin
250+
if (rising_edge(CLK)) then
251+
if (RST = '1') then
252+
present_state <= idle;
253+
else
254+
present_state <= next_state;
255+
end if;
256+
end if;
257+
end process;
258+
259+
-- NEXT STATE AND OUTPUTS LOGIC
260+
process (present_state, DIN_VLD, spi_clk_en_set, spi_last_bit)
261+
begin
262+
263+
case present_state is
264+
265+
when idle =>
266+
spi_chip_select_n <= '1';
267+
spi_ready <= '1';
268+
269+
if (DIN_VLD = '1') then
270+
next_state <= transmit;
271+
else
272+
next_state <= idle;
273+
end if;
274+
275+
when transmit =>
276+
spi_chip_select_n <= '0';
277+
spi_ready <= '0';
278+
279+
if (spi_clk_en_set = '1' AND spi_last_bit = '1') then
280+
next_state <= check_data;
281+
else
282+
next_state <= transmit;
283+
end if;
284+
285+
when check_data =>
286+
spi_chip_select_n <= '0';
287+
spi_ready <= '1';
288+
289+
if (DIN_VLD = '1') then
290+
next_state <= transmit;
291+
else
292+
next_state <= idle;
293+
end if;
294+
295+
when others =>
296+
spi_chip_select_n <= '1';
297+
spi_ready <= '0';
298+
next_state <= idle;
299+
300+
end case;
301+
end process;
302+
303+
end FULL;

0 commit comments

Comments
 (0)