1 --===========================================================================--
2 -- --
3 -- Synthesizable Serial Peripheral Interface Master --
4 -- --
5 --===========================================================================--
6 --
7 -- File name : spi-master.vhd
8 --
9 -- Entity name : spi-master
10 --
11 -- Purpose : Implements a SPI Master Controller
12 --
13 -- Dependencies : ieee.std_logic_1164
14 -- ieee.std_logic_unsigned
15 --
16 -- Author : Hans Huebner
17 --
18 -- Email : hans@huebner.org
19 --
20 -- Web : http://opencores.org/project,system09
21 --
22 -- Description : This core implements a SPI master interface.
23 -- Transfer size is 4, 8, 12 or 16 bits.
24 -- The SPI clock is 0 when idle, sampled on
25 -- the rising edge of the SPI clock.
26 -- The SPI clock is derived from the bus clock input
27 -- divided by 2, 4, 8 or 16.
28 --
29 -- clk, reset, cs, rw, addr, data_in, data_out and irq
30 -- represent the System09 bus interface.
31 -- spi_clk, spi_mosi, spi_miso and spi_cs_n are the
32 -- standard SPI signals meant to be routed off-chip.
33 --
34 -- The SPI core provides for four register addresses
35 -- that the CPU can read or writen to:
36 --
37 -- Base + $00 -> DL: Data Low LSB
38 -- Base + $01 -> DH: Data High MSB
39 -- Base + $02 -> CS: Command/Status
40 -- Base + $03 -> CO: Config
41 --
42 -- CS: Write bits:
43 --
44 -- CS[0] START : Start transfer
45 -- CS[1] END : Deselect device after transfer
46 -- (or immediately if START = '0')
47 -- CS[2] IRQEN : Generate IRQ at end of transfer
48 -- CS[6:4] SPIAD : SPI device address
49 --
50 -- CS: Read bits
51 --
52 -- CS[0] BUSY : Currently transmitting data
53 --
54 -- CO: Write bits
55 --
56 -- CO[1:0] DIVIDE: SPI clock divisor,
57 -- 00=clk/2,
58 -- 01=clk/4,
59 -- 10=clk/8,
60 -- 11=clk/16
61 -- CO[3:2] LENGTH: Transfer length,
62 -- 00= 4 bits,
63 -- 01= 8 bits,
64 -- 10=12 bits,
65 -- 11=16 bits
66 --
67 -- Copyright (C) 2009 - 2010 Hans Huebner
68 --
69 -- This program is free software: you can redistribute it and/or modify
70 -- it under the terms of the GNU General Public License as published by
71 -- the Free Software Foundation, either version 3 of the License, or
72 -- (at your option) any later version.
73 --
74 -- This program is distributed in the hope that it will be useful,
75 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
76 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77 -- GNU General Public License for more details.
78 --
79 -- You should have received a copy of the GNU General Public License
80 -- along with this program. If not, see <http://www.gnu.org/licenses/>.
81 --
82 --
83 --===========================================================================--
84 -- --
85 -- Revision History --
86 -- --
87 --===========================================================================--
88 --
89 -- Version Author Date Description
90 --
91 -- 0.1 Hans Huebner 23 February 2009 SPI bus master for System09
92 -- 0.2 John Kent 16 June 2010 Added GPL notice
93 --
94 --
95
96 library ieee;
97 use ieee.std_logic_1164.all;
98 use ieee.std_logic_unsigned.all;
99
100 entity spi_master is
101 port (
102 --
103 -- CPU Interface Signals
104 --
105 clk : in std_logic;
106 reset : in std_logic;
107 cs : in std_logic;
108 rw : in std_logic;
109 addr : in std_logic_vector(1 downto 0);
110 data_in : in std_logic_vector(7 downto 0);
111 data_out : out std_logic_vector(7 downto 0);
112 irq : out std_logic;
113 --
114 -- SPI Interface Signals
115 --
116 spi_miso : in std_logic;
117 spi_mosi : out std_logic;
118 spi_clk : out std_logic;
119 spi_cs_n : out std_logic_vector(7 downto 0)
120 );
121 end;
122
123 architecture rtl of spi_master is
124
125 -- State type of the SPI transfer state machine
126 type state_type is (s_idle, s_running);
127 signal state : state_type;
128 -- Shift register
129 signal shift_reg : std_logic_vector(15 downto 0);
130 -- Buffer to hold data to be sent
131 signal spi_data_buf : std_logic_vector(15 downto 0);
132 -- Start transmission flag
133 signal start : std_logic;
134 -- Number of bits transfered
135 signal count : std_logic_vector(3 downto 0);
136 -- Buffered SPI clock
137 signal spi_clk_buf : std_logic;
138 -- Buffered SPI clock output
139 signal spi_clk_out : std_logic;
140 -- Previous SPI clock state
141 signal prev_spi_clk : std_logic;
142 -- Number of clk cycles-1 in this SPI clock period
143 signal spi_clk_count : std_logic_vector(2 downto 0);
144 -- SPI clock divisor
145 signal spi_clk_divide : std_logic_vector(1 downto 0);
146 -- SPI transfer length
147 signal transfer_length : std_logic_vector(1 downto 0);
148 -- Flag to indicate that the SPI slave should be deselected after the current
149 -- transfer
150 signal deselect : std_logic;
151 -- Flag to indicate that an IRQ should be generated at the end of a transfer
152 signal irq_enable : std_logic;
153 -- Internal chip select signal, will be demultiplexed through the cs_mux
154 signal spi_cs : std_logic;
155 -- Current SPI device address
156 signal spi_addr : std_logic_vector(2 downto 0);
157 begin
158
159 -- Read CPU bus into internal registers
160 cpu_write : process(clk, reset)
161 begin
162 if reset = '1' then
163 deselect <= '0';
164 irq_enable <= '0';
165 start <= '0';
166 spi_clk_divide <= "11";
167 transfer_length <= "11";
168 spi_data_buf <= (others => '0');
169 elsif falling_edge(clk) then
170 start <= '0';
171 if cs = '1' and rw = '0' then
172 case addr is
173 when "00" =>
174 spi_data_buf(7 downto 0) <= data_in;
175 when "01" =>
176 spi_data_buf(15 downto 8) <= data_in;
177 when "10" =>
178 start <= data_in(0);
179 deselect <= data_in(1);
180 irq_enable <= data_in(2);
181 spi_addr <= data_in(6 downto 4);
182 when "11" =>
183 spi_clk_divide <= data_in(1 downto 0);
184 transfer_length <= data_in(3 downto 2);
185 when others =>
186 null;
187 end case;
188 end if;
189 end if;
190 end process;
191
192 -- Provide data for the CPU to read
193 cpu_read : process(shift_reg, addr, state, deselect, start)
194 begin
195 data_out <= (others => '0');
196 case addr is
197 when "00" =>
198 data_out <= shift_reg(7 downto 0);
199 when "01" =>
200 data_out <= shift_reg(15 downto 8);
201 when "10" =>
202 if state = s_idle then
203 data_out(0) <= '0';
204 else
205 data_out(0) <= '1';
206 end if;
207 data_out(1) <= deselect;
208 when others =>
209 null;
210 end case;
211 end process;
212
213 spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
214 "11111101" when spi_addr = "001" and spi_cs = '1' else
215 "11111011" when spi_addr = "010" and spi_cs = '1' else
216 "11110111" when spi_addr = "011" and spi_cs = '1' else
217 "11101111" when spi_addr = "100" and spi_cs = '1' else
218 "11011111" when spi_addr = "101" and spi_cs = '1' else
219 "10111111" when spi_addr = "110" and spi_cs = '1' else
220 "01111111" when spi_addr = "111" and spi_cs = '1' else
221 "11111111";
222
223 -- SPI transfer state machine
224 spi_proc : process(clk, reset)
225 begin
226 if reset = '1' then
227 count <= (others => '0');
228 shift_reg <= (others => '0');
229 prev_spi_clk <= '0';
230 spi_clk_out <= '0';
231 spi_cs <= '0';
232 state <= s_idle;
233 irq <= 'Z';
234 elsif falling_edge(clk) then
235 prev_spi_clk <= spi_clk_buf;
236 irq <= 'Z';
237 case state is
238 when s_idle =>
239 if start = '1' then
240 count <= (others => '0');
241 shift_reg <= spi_data_buf;
242 spi_cs <= '1';
243 state <= s_running;
244 elsif deselect = '1' then
245 spi_cs <= '0';
246 end if;
247 when s_running =>
248 if prev_spi_clk = '1' and spi_clk_buf = '0' then
249 spi_clk_out <= '0';
250 count <= count + "0001";
251 shift_reg <= shift_reg(14 downto 0) & spi_miso;
252 if ((count = "0011" and transfer_length = "00")
253 or (count = "0111" and transfer_length = "01")
254 or (count = "1011" and transfer_length = "10")
255 or (count = "1111" and transfer_length = "11")) then
256 if deselect = '1' then
257 spi_cs <= '0';
258 end if;
259 if irq_enable = '1' then
260 irq <= '1';
261 end if;
262 state <= s_idle;
263 end if;
264 elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
265 spi_clk_out <= '1';
266 end if;
267 when others =>
268 null;
269 end case;
270 end if;
271 end process;
272
273 -- Generate SPI clock
274 spi_clock_gen : process(clk, reset)
275 begin
276 if reset = '1' then
277 spi_clk_count <= (others => '0');
278 spi_clk_buf <= '0';
279 elsif falling_edge(clk) then
280 if state = s_running then
281 if ((spi_clk_divide = "00")
282 or (spi_clk_divide = "01" and spi_clk_count = "001")
283 or (spi_clk_divide = "10" and spi_clk_count = "011")
284 or (spi_clk_divide = "11" and spi_clk_count = "111")) then
285 spi_clk_buf <= not spi_clk_buf;
286 spi_clk_count <= (others => '0');
287 else
288 spi_clk_count <= spi_clk_count + "001";
289 end if;
290 else
291 spi_clk_buf <= '0';
292 end if;
293 end if;
294 end process;
295
296 spi_mosi_mux : process(shift_reg, transfer_length)
297 begin
298 case transfer_length is
299 when "00" =>
300 spi_mosi <= shift_reg(3);
301 when "01" =>
302 spi_mosi <= shift_reg(7);
303 when "10" =>
304 spi_mosi <= shift_reg(11);
305 when "11" =>
306 spi_mosi <= shift_reg(15);
307 when others =>
308 null;
309 end case;
310 end process;
311
312 spi_clk <= spi_clk_out;
313
314 end rtl;