-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathspi_controller.vhdl
191 lines (184 loc) · 8.99 KB
/
spi_controller.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
------------------------------------------------------------------------------
---- ----
---- SPI Controller ----
---- ----
---- This file is part FPGA Libre project http://fpgalibre.sf.net/ ----
---- ----
---- Description: ----
---- Configurable Master Serial Protocol Interface controller. ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author: ----
---- - Francisco Salomón, fsalomon en inti gob ar ----
---- - Salvador E. Tropea, salvador en inti gob ar ----
---- ----
------------------------------------------------------------------------------
---- ----
---- Copyright (c) 2010 Francisco Salomón <fsalomon en inti gob ar> ----
---- Copyright (c) 2008 Salvador E. Tropea <salvador en inti gob ar> ----
---- Copyright (c) 2008-2010 Instituto Nacional de Tecnología Industrial ----
---- ----
---- Distributed under the GPL v2 or newer license ----
---- ----
------------------------------------------------------------------------------
---- ----
---- Design unit: SPI_controller(RTL) (Entity and architecture) ----
---- File name: spi_controller.vhdl ----
---- Note: None ----
---- Limitations: None known ----
---- Errors: None known ----
---- Library: None ----
---- Dependencies: IEEE.std_logic_1164 ----
---- IEEE.numeric_std ----
---- utils.Stdlib ----
---- Target FPGA: Spartan 3A (XC3S400-FT256) ----
---- Language: VHDL ----
---- Wishbone: None ----
---- Synthesis tools: Xilinx Release 10.1i - xst K.37 ----
---- Simulation tools: GHDL [Sokcho edition] (0.2x) ----
---- Text editor: SETEdit 0.5.x ----
---- ----
------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library utils;
use utils.Stdlib.all;
entity SPI_controller is
generic(
SCLK_PHASE : std_logic:='0'; -- Indicates Sclk's edge for sampling
SCLK_POLARITY : std_logic:='0'; -- Sclk level for no transaction state
SLAVE_QTT : positive:=2; -- Number of selectable slave devices
SS_BITS_QTT : positive:=1; -- Number of bits for ss input
DATA_W : positive:=8; -- Transaction data width
MSB_IS_FIRST : boolean :=false -- MSB is sent first
);
port(
-- System
clk_i : in std_logic;
rst_i : in std_logic;
ena_i : in std_logic;
-- Interface
start_i : in std_logic;
tx_i : in std_logic_vector(DATA_W-1 downto 0);
rx_o : out std_logic_vector(DATA_W-1 downto 0);
ss_i : in std_logic_vector(SS_BITS_QTT-1 downto 0);
busy_o : out std_logic;
irq_o : out std_logic;
-- SPI
miso_i : in std_logic;
sclk_o : out std_logic;
mosi_o : out std_logic;
ss_o : out std_logic_vector(SLAVE_QTT-1 downto 0):=
(others => '1')
);
end entity SPI_controller;
architecture RTL of SPI_controller is
constant SCLK_IDLE_LV : std_logic:=SCLK_POLARITY;
type state_type is (idle, init_sd, leading_sclk, trailing_sclk);
signal state : state_type:=idle; -- states for shifter_FSM.
signal tx_shift_r : std_logic_vector(DATA_W-1 downto 0):=
(others=>'0');
signal rx_shift_r : std_logic_vector(DATA_W-1 downto 0);
signal ss : std_logic_vector(SLAVE_QTT-1 downto 0):=
(others => '1');
signal sclk_r : std_logic:=SCLK_IDLE_LV;
begin
shifter_FSM:
process (clk_i)
variable bit_cnt : natural range 0 to DATA_W:=0;
begin
if rising_edge(clk_i) then
irq_o <= '0';
if rst_i='1' then
state <= idle;
sclk_r <= SCLK_IDLE_LV;
ss_o <= (others => '1');
busy_o <= '0';
bit_cnt:=0;
elsif ena_i = '1' then
case state is
when idle =>
if start_i='1' then -- init transaction
state <= init_sd;
bit_cnt:=0;
ss_o <= ss; -- latch slave-select
if MSB_IS_FIRST then -- latch data to send
for i in tx_i'range loop
tx_shift_r((DATA_W-1)-i) <= tx_i(i);
end loop;
else
tx_shift_r <= tx_i;
end if;
busy_o <= '1';
end if;
when init_sd =>
state <= leading_sclk;
sclk_r <= not sclk_r;
if SCLK_PHASE='0' then
rx_shift_r <= rx_shift_r((DATA_W-2) downto 0)
& miso_i;
end if;
when leading_sclk =>
state <= trailing_sclk;
sclk_r <= not sclk_r;
if SCLK_PHASE='0' then
tx_shift_r <= "0"&tx_shift_r(DATA_W-1 downto 1);
else
rx_shift_r <= rx_shift_r((DATA_W-2) downto 0)
& miso_i;
end if;
when trailing_sclk =>
if bit_cnt=(DATA_W-1) then
if MSB_IS_FIRST then -- pass received data
rx_o <= rx_shift_r;
else
for i in rx_o'range loop
rx_o((DATA_W-1)-i) <= rx_shift_r(i);
end loop;
end if;
if start_i='1' then -- evaluate ongoing transaction
state <= init_sd;
bit_cnt:=0;
-- latch data to send, using the last slave
if MSB_IS_FIRST then
for i in tx_i'range loop
tx_shift_r((DATA_W-1)-i) <= tx_i(i);
end loop;
else
tx_shift_r <= tx_i;
end if;
else -- end of transaction
state <= idle;
ss_o <= (others => '1');
busy_o <= '0';
end if;
irq_o <= '1';
else
bit_cnt:=bit_cnt+1;
state <= leading_sclk;
sclk_r <= not sclk_r;
if SCLK_PHASE='0' then
rx_shift_r <= rx_shift_r((DATA_W-2) downto 0)
& miso_i;
else
tx_shift_r <= "0" &
tx_shift_r(DATA_W-1 downto 1);
end if;
end if;
end case;
end if;
end if;
end process shifter_FSM;
-- Decode ss_i
decode_ss_gen:
for i in ss'range generate
ss(i) <= '0' when i=sv2uint(ss_i) else '1';
end generate decode_ss_gen;
-- sclk output
sclk_o <= sclk_r;
-- mosi output
mosi_o <= tx_shift_r(0);
end architecture RTL; -- Entity: SPI_controller