1 -- SPI
bus master
for System09
2 -- (http:
//members.optushome.com.au/jekent/system09/index.html)
3
4 -- This core implements a SPI master interface. Transfer size
is 4,
8,
12 or
5 --
16 bits. The SPI clock
is 0 when idle, sampled
on the rising edge
of the SPI
6 -- clock. The SPI clock
is derived from the
bus clock
input divided
7 -- by
2,
4,
8 or 16.
8
9 -- clk, reset, cs, rw, addr, data_in, data_out
and irq represent the System09
10 --
bus interface.
11 -- spi_clk, spi_mosi, spi_miso
and spi_cs_n are the
standard SPI signals meant
12 --
to be routed off-
chip.
13
14 -- The SPI core provides
for four
register addresses that the CPU can
read or
15 --
write:
16
17 --
0 ->
DL: Data LSB
18 --
1 ->
DH: Data MSB
19 --
2 -> CS: Command/
Status
20 --
3 ->
CO: Config
21
22 --
Write bits, CS:
23 --
24 -- START CS[
0]: Start transfer
25 --
END CS[
1]: Deselect device
after transfer (
or immediately
if START =
'0')
26 -- IRQEN CS[
2]: Generate IRQ at
end of transfer
27 -- SPIAD CS[
6:
4]: SPI device address
28 --
29 --
Read bits, CS:
30 --
31 -- BUSY CS[
0]: Currently transmitting data
32 --
33 --
Write BITS, CO:
34 --
35 -- DIVIDE CO[
1:
0]: SPI clock divisor,
00=clk/
2,
01=clk/
4,
10=clk/
8,
11=clk/
16
36 -- LENGTH CO[
3:
2]: Transfer length,
00=
4 bits,
01=
8 bits,
10=
12 bits,
11=
16 bits
37 --
38
39 library ieee;
40 use ieee.std_logic_1164.
all;
41 use ieee.std_logic_unsigned.
all;
42
43 entity spi_master
is
44 port (
45 clk, reset, cs, rw :
in std_logic;
46 addr :
in std_logic_vector(
1 downto 0);
47 data_in :
in std_logic_vector(
7 downto 0);
48 data_out :
out std_logic_vector(
7 downto 0);
49 irq :
out std_logic;
50 spi_clk, spi_mosi :
out std_logic;
51 spi_cs_n :
out std_logic_vector(
7 downto 0);
52 spi_miso :
in std_logic);
53 end;
54
55 architecture rtl
of spi_master
is
56
57 -- State
type of the SPI transfer state machine
58 type state_type
is (s_idle, s_running, s_done);
59 signal state : state_type;
60 -- Shift
register
61 signal shift_reg :
std_logic_vector(
15 downto 0);
62 -- Buffer
to hold data
to be sent
63 signal spi_data_buf :
std_logic_vector(
15 downto 0);
64 --
Start transmission flag
65 signal start :
std_logic;
66 -- Number
of bits transfered
67 signal count :
std_logic_vector(
3 downto 0);
68 --
Buffered SPI clock
69 signal spi_clk_buf :
std_logic;
70 -- Buffered SPI clock
output
71 signal spi_clk_out :
std_logic;
72 --
Previous SPI clock state
73 signal prev_spi_clk :
std_logic;
74 -- Number
of clk cycles-
1 in this SPI clock period
75 signal spi_clk_count :
std_logic_vector(
2 downto 0);
76 --
SPI clock divisor
77 signal spi_clk_divide :
std_logic_vector(
1 downto 0);
78 --
SPI transfer length
79 signal transfer_length :
std_logic_vector(
1 downto 0);
80 -- Flag
to indicate that the SPI slave should be deselected
after the current
81 --
transfer
82 signal deselect :
std_logic;
83 -- Flag
to indicate that an IRQ should be generated at the
end of a transfer
84 signal irq_enable :
std_logic;
85 -- Signal
to clear IRQ
86 signal irqack :
std_logic;
87 -- Internal chip
select signal, will be demultiplexed through the cs_mux
88 signal spi_cs :
std_logic;
89 --
Current SPI device address
90 signal spi_addr :
std_logic_vector(
2 downto 0);
91 begin
92
93 -- Read CPU
bus into internal registers
94 cpu_write :
process(clk, reset)
95 begin
96 if reset =
'1' then
97 deselect <=
'0';
98 irq_enable <=
'0';
99 start <=
'0';
100 spi_clk_divide <=
"11";
101 transfer_length <=
"11";
102 spi_data_buf <= (
others =>
'0');
103 elsif
falling_edge(clk)
then
104 start <=
'0';
105 irqack <=
'0';
106 if cs =
'1' and rw =
'0' then
107 case addr
is
108 when "00" =>
109 spi_data_buf(
7 downto 0) <=
data_in;
110 when "01" =>
111 spi_data_buf(
15 downto 8) <=
data_in;
112 when "10" =>
113 start <= data_in(
0);
114 deselect <= data_in(
1);
115 irq_enable <= data_in(
2);
116 spi_addr <= data_in(
6 downto 4);
117 irqack <=
'1';
118 when "11" =>
119 spi_clk_divide <= data_in(
1 downto 0);
120 transfer_length <= data_in(
3 downto 2);
121 when others =>
122 null;
123 end case;
124 end if;
125 end if;
126 end process;
127
128 -- Provide data
for the CPU
to read
129 cpu_read :
process(shift_reg, addr, state, deselect, start)
130 begin
131 data_out <= (
others =>
'0');
132 case addr
is
133 when "00" =>
134 data_out <= shift_reg(
7 downto 0);
135 when "01" =>
136 data_out <= shift_reg(
15 downto 8);
137 when "10" =>
138 if state = s_idle
then
139 data_out(
0) <=
'0';
140 else
141 data_out(
0) <=
'1';
142 end if;
143 data_out(
1) <=
deselect;
144 when others =>
145 null;
146 end case;
147 end process;
148
149 spi_cs_n <=
"11111110" when spi_addr =
"000" and spi_cs =
'1' else
150 "11111101" when spi_addr =
"001" and spi_cs =
'1' else
151 "11111011" when spi_addr =
"010" and spi_cs =
'1' else
152 "11110111" when spi_addr =
"011" and spi_cs =
'1' else
153 "11101111" when spi_addr =
"100" and spi_cs =
'1' else
154 "11011111" when spi_addr =
"101" and spi_cs =
'1' else
155 "10111111" when spi_addr =
"110" and spi_cs =
'1' else
156 "01111111" when spi_addr =
"111" and spi_cs =
'1' else
157 "11111111";
158
159 --
SPI transfer state machine
160 spi_proc :
process(clk, reset)
161 begin
162 if reset =
'1' then
163 count <= (
others =>
'0');
164 shift_reg <= (
others =>
'0');
165 prev_spi_clk <=
'0';
166 spi_clk_out <=
'0';
167 spi_cs <=
'0';
168 state <=
s_idle;
169 irq <=
'0';
170 elsif
falling_edge(clk)
then
171 prev_spi_clk <=
spi_clk_buf;
172 irq <=
'0';
173 case state
is
174 when s_idle =>
175 if start =
'1' then
176 count <= (
others =>
'0');
177 shift_reg <=
spi_data_buf;
178 spi_cs <=
'1';
179 state <=
s_running;
180 elsif deselect =
'1' then
181 spi_cs <=
'0';
182 end if;
183 when s_running =>
184 if prev_spi_clk =
'1' and spi_clk_buf =
'0' then
185 spi_clk_out <=
'0';
186 count <= count +
"0001";
187 shift_reg <= shift_reg(
14 downto 0) &
spi_miso;
188 if ((count =
"0011" and transfer_length =
"00")
189 or (count =
"0111" and transfer_length =
"01")
190 or (count =
"1011" and transfer_length =
"10")
191 or (count =
"1111" and transfer_length =
"11"))
then
192 if deselect =
'1' then
193 spi_cs <=
'0';
194 end if;
195 if irq_enable =
'1' then
196 irq <=
'1';
197 state <=
s_done;
198 end if;
199 state <=
s_idle;
200 end if;
201 elsif prev_spi_clk =
'0' and spi_clk_buf =
'1' then
202 spi_clk_out <=
'1';
203 end if;
204 when s_done =>
205 if irqack =
'1' then
206 state <=
s_idle;
207 end if;
208 when others =>
209 null;
210 end case;
211 end if;
212 end process;
213
214 --
Generate SPI clock
215 spi_clock_gen :
process(clk, reset)
216 begin
217 if reset =
'1' then
218 spi_clk_count <= (
others =>
'0');
219 spi_clk_buf <=
'0';
220 elsif
falling_edge(clk)
then
221 if state = s_running
then
222 if ((spi_clk_divide =
"00")
223 or (spi_clk_divide =
"01" and spi_clk_count =
"001")
224 or (spi_clk_divide =
"10" and spi_clk_count =
"011")
225 or (spi_clk_divide =
"11" and spi_clk_count =
"111"))
then
226 spi_clk_buf <=
not spi_clk_buf;
227 spi_clk_count <= (
others =>
'0');
228 else
229 spi_clk_count <= spi_clk_count +
"001";
230 end if;
231 else
232 spi_clk_buf <=
'0';
233 end if;
234 end if;
235 end process;
236
237 spi_mosi_mux :
process(shift_reg, transfer_length)
238 begin
239 case transfer_length
is
240 when "00" =>
241 spi_mosi <= shift_reg(
3);
242 when "01" =>
243 spi_mosi <= shift_reg(
7);
244 when "10" =>
245 spi_mosi <= shift_reg(
11);
246 when "11" =>
247 spi_mosi <= shift_reg(
15);
248 when others =>
249 null;
250 end case;
251 end process;
252
253 spi_clk <=
spi_clk_out;
254
255 end rtl;
转载于:https://www.cnblogs.com/shangdawei/archive/2012/05/16/2503733.html