OpenCores
URL https://opencores.org/ocsvn/spi_master_lightweight/spi_master_lightweight/trunk

Subversion Repositories spi_master_lightweight

[/] [spi_master_lightweight/] [trunk/] [rtl/] [spi_master.vhd] - Blame information for rev 5

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 bbinb
--------------------------------------------------------------------------------
2
-- AUTHOR:                      MEHMET BURAK AYKENAR
3
-- CREATED:                     09.12.2019
4
-- REVISION DATE:       09.12.2019
5
--
6
--------------------------------------------------------------------------------
7
-- DESCRIPTION:         
8
--    This module implements master part of SPI communication interface and can be used to any SPI slave IC.
9
 
10
--    In order to read from a slave IC, mosi_data_i input signal should be assigned to desired value and en_i signal should be high. 
11
--    In order to write to a slave IC, en_i input signal should be high. 
12
--    data_ready_o output signal has the logic high value for one clock cycle as read or/and write operation finished. miso_data_o output signal
13
-- has the data read from slave IC. 
14
--    In order to read or/and write consecutively, en_i signal should be kept high. To end the transaction, en_i input signal should be assigned to zero
15
-- when data_ready_o output signal gets high.
16
--------------------------------------------------------------------------------
17
-- Limitation/Assumption: In order to use this module properly, the ratio of  (c_clkfreq / c_sclkFreq) should be equal to 8 or more. 
18
--    For higher SCLK frequencies are possible but more elaboration is needed.
19
-- Notes: c_cpol and c_cpha parameters are clock polarity and clock phase, respectively.
20
--------------------------------------------------------------------------------
21
-- VHDL DIALECT: VHDL '93
22
--
23
--------------------------------------------------------------------------------
24
-- PROJECT      : General purpose
25
-- BOARD        : General purpose
26
-- ENTITY       : spi_master
27
--------------------------------------------------------------------
28
-- FILE         : spi_master.vhd
29
--------------------------------------------------------------------------------
30
-- REVISION HISTORY:
31
-- REVISION  DATE                AUTHOR        COMMENT
32
-- --------  ----------  ------------  -----------
33
-- 1.0       19.12.2019  M.B.AYKENAR   INITIAL REVISION
34
--------------------------------------------------------------------------------
35
 
36
library IEEE;
37
use IEEE.STD_LOGIC_1164.ALL;
38
use IEEE.STD_LOGIC_UNSIGNED.ALL;
39
 
40
entity spi_master is
41
generic (
42
        c_clkfreq                       : integer := 50_000_000;
43
        c_sclkfreq                      : integer := 1_000_000;
44
        c_cpol                          : std_logic := '0';
45
        c_cpha                          : std_logic := '0'
46
);
47
Port (
48
        clk_i                   : in  STD_LOGIC;
49
        en_i                    : in  STD_LOGIC;
50
        mosi_data_i     : in  STD_LOGIC_VECTOR (7 downto 0);
51
        miso_data_o     : out STD_LOGIC_VECTOR (7 downto 0);
52
        data_ready_o    : out STD_LOGIC;
53
        cs_o                    : out STD_LOGIC;
54
        sclk_o                  : out STD_LOGIC;
55
        mosi_o                  : out STD_LOGIC;
56
        miso_i                  : in  STD_LOGIC
57
);
58
end spi_master;
59
 
60
architecture Behavioral of spi_master is
61
 
62
--------------------------------------------------------------------------------
63
-- CONSTANTS
64
constant c_edgecntrlimdiv2      : integer := c_clkfreq/(c_sclkfreq*2);
65
 
66
--------------------------------------------------------------------------------
67
-- INTERNAL SIGNALS
68
signal write_reg        : std_logic_vector (7 downto 0)  := (others => '0');
69
signal read_reg         : std_logic_vector (7 downto 0)  := (others => '0');
70
 
71
signal sclk_en          : std_logic := '0';
72
signal sclk                     : std_logic := '0';
73
signal sclk_prev        : std_logic := '0';
74
signal sclk_rise        : std_logic := '0';
75
signal sclk_fall        : std_logic := '0';
76
 
77
signal pol_phase        : std_logic_vector (1 downto 0) := (others => '0');
78
signal mosi_en          : std_logic := '0';
79
signal miso_en          : std_logic := '0';
80
signal once         : std_logic := '0';
81
 
82
signal edgecntr         : integer range 0 to c_edgecntrlimdiv2 := 0;
83
 
84
signal cntr             : integer range 0 to 15 := 0;
85
 
86
--------------------------------------------------------------------------------
87
-- STATE DEFINITIONS
88
type states is (S_IDLE, S_TRANSFER);
89
signal state : states := S_IDLE;
90
 
91
--------------------------------------------------------------------------------
92
--------------------------------------------------------------------------------
93
--------------------------------------------------------------------------------
94
begin
95
 
96
pol_phase <= c_cpol & c_cpha;
97
 
98
--------------------------------------------------------------------------------
99
--    SAMPLE_EN process assigns mosi_en and miso_en internal signals to sclk_fall or sclk_rise in a combinational logic according to 
100
-- generic parameters of c_cpol and c_cpha via pol_phase signal.
101
P_SAMPLE_EN : process (pol_phase, sclk_fall, sclk_rise) begin
102
 
103
        case pol_phase is
104
 
105
                when "00" =>
106
 
107
                        mosi_en <= sclk_fall;
108
                        miso_en <= sclk_rise;
109
 
110
                when "01" =>
111
 
112
                        mosi_en <= sclk_rise;
113
                        miso_en <= sclk_fall;
114
 
115
                when "10" =>
116
 
117
                        mosi_en <= sclk_rise;
118
                        miso_en <= sclk_fall;
119
 
120
                when "11" =>
121
 
122
                        mosi_en <= sclk_fall;
123
                        miso_en <= sclk_rise;
124
 
125
                when others =>
126
 
127
        end case;
128
 
129
end process P_SAMPLE_EN;
130
 
131
--------------------------------------------------------------------------------
132
--    RISEFALL_DETECT process assigns sclk_rise and sclk_fall signals in a combinational logic.
133
P_RISEFALL_DETECT : process (sclk, sclk_prev) begin
134
 
135
        if (sclk = '1' and sclk_prev = '0') then
136
                sclk_rise <= '1';
137
        else
138
                sclk_rise <= '0';
139
        end if;
140
 
141
        if (sclk = '0' and sclk_prev = '1') then
142
                sclk_fall <= '1';
143
        else
144
                sclk_fall <= '0';
145
        end if;
146
 
147
end process P_RISEFALL_DETECT;
148
 
149
--------------------------------------------------------------------------------
150
--    In the MAIN process S_IDLE and S_TRANSFER states are implemented. state changes from S_IDLE to S_TRANSFER when en_i input
151
-- signal has the logic high value. At that cycle, write_reg signal is assigned to mosi_data_i input signal. According to c_cpha generic 
152
-- parameter, the transaction operation changes slightly. This operational difference is well explained in the paper that can be found
153
-- in Documents folder of the SPI, which is located in SVN server.
154
P_MAIN : process (clk_i) begin
155
if (rising_edge(clk_i)) then
156
 
157
    data_ready_o <= '0';
158
        sclk_prev       <= sclk;
159
 
160
        case state is
161
 
162
--------------------------------------------------------------------------------        
163
                when S_IDLE =>
164
 
165
                        cs_o                    <= '1';
166
                        mosi_o                  <= '0';
167
                        data_ready_o    <= '0';
168
                        sclk_en                 <= '0';
169
                        cntr                    <= 0;
170
 
171
                        if (c_cpol = '0') then
172
                                sclk_o  <= '0';
173
                        else
174
                                sclk_o  <= '1';
175
                        end if;
176
 
177
                        if (en_i = '1') then
178
                                state           <= S_TRANSFER;
179
                                sclk_en         <= '1';
180
                                write_reg       <= mosi_data_i;
181
                                mosi_o          <= mosi_data_i(7);
182
                                read_reg        <= x"00";
183
                        end if;
184
 
185
--------------------------------------------------------------------------------                        
186
                when S_TRANSFER =>
187
 
188
                        cs_o    <= '0';
189
                        mosi_o  <= write_reg(7);
190
 
191
 
192
                        if (c_cpha = '1') then
193
 
194
                                if (cntr = 0) then
195
                                        sclk_o  <= sclk;
196
                                        if (miso_en = '1') then
197
                                                read_reg(0)                              <= miso_i;
198
                                                read_reg(7 downto 1)    <= read_reg(6 downto 0);
199
                                                cntr                                    <= cntr + 1;
200
                                                once                    <= '1';
201
                                        end if;
202
                                elsif (cntr = 8) then
203
                                    if (once = '1') then
204
                                        data_ready_o    <= '1';
205
                                        once            <= '0';
206
                                    end if;
207
                                        miso_data_o             <= read_reg;
208
                                        if (mosi_en = '1') then
209
                                                if (en_i = '1') then
210
                                                        write_reg       <= mosi_data_i;
211
                                                        mosi_o          <= mosi_data_i(7);
212
                                                        sclk_o          <= sclk;
213
                                                        cntr            <= 0;
214
                                                else
215
                                                        state   <= S_IDLE;
216
                                                        cs_o    <= '1';
217
                                                end if;
218
                                        end if;
219
                                elsif (cntr = 9) then
220
                                        if (miso_en = '1') then
221
                                                state   <= S_IDLE;
222
                                                cs_o    <= '1';
223
                                        end if;
224
                                else
225
                                        sclk_o  <= sclk;
226
                                        if (miso_en = '1') then
227
                                                read_reg(0)                              <= miso_i;
228
                                                read_reg(7 downto 1)    <= read_reg(6 downto 0);
229
                                                cntr                                    <= cntr + 1;
230
                                        end if;
231
                                        if (mosi_en = '1') then
232
                                                mosi_o  <= write_reg(7);
233
                                                write_reg(7 downto 1)   <= write_reg(6 downto 0);
234
                                        end if;
235
                                end if;
236
 
237
                        else    -- c_cpha = '0'
238
 
239
                                if (cntr = 0) then
240
                                        sclk_o  <= sclk;
241
                                        if (miso_en = '1') then
242
                                                read_reg(0)                              <= miso_i;
243
                                                read_reg(7 downto 1)    <= read_reg(6 downto 0);
244
                                                cntr                                    <= cntr + 1;
245
                                                once                    <= '1';
246
                                        end if;
247
                                elsif (cntr = 8) then
248
                    if (once = '1') then
249
                        data_ready_o    <= '1';
250
                        once            <= '0';
251
                    end if;
252
                                        miso_data_o             <= read_reg;
253
                                        sclk_o                  <= sclk;
254
                                        if (mosi_en = '1') then
255
                                                if (en_i = '1') then
256
                                                        write_reg       <= mosi_data_i;
257
                                                        mosi_o          <= mosi_data_i(7);
258
                                                        cntr            <= 0;
259
                                                else
260
                                                        cntr    <= cntr + 1;
261
                                                end if;
262
                                                if (miso_en = '1') then
263
                                                        state   <= S_IDLE;
264
                                                        cs_o    <= '1';
265
                                                end if;
266
                                        end if;
267
                                elsif (cntr = 9) then
268
                                        if (miso_en = '1') then
269
                                                state   <= S_IDLE;
270
                                                cs_o    <= '1';
271
                                        end if;
272
                                else
273
                                        sclk_o  <= sclk;
274
                                        if (miso_en = '1') then
275
                                                read_reg(0)                              <= miso_i;
276
                                                read_reg(7 downto 1)    <= read_reg(6 downto 0);
277
                                                cntr                                    <= cntr + 1;
278
                                        end if;
279
                                        if (mosi_en = '1') then
280
                                                write_reg(7 downto 1)   <= write_reg(6 downto 0);
281
                                        end if;
282
                                end if;
283
 
284
                        end if;
285
 
286
        end case;
287
 
288
end if;
289
end process P_MAIN;
290
 
291
--------------------------------------------------------------------------------
292
--    In the SCLK_GEN process, internal sclk signal is generated if sclk_en signal is '1'. 
293
P_SCLK_GEN : process (clk_i) begin
294
if (rising_edge(clk_i)) then
295
 
296
        if (sclk_en = '1') then
297
                if edgecntr = c_edgecntrlimdiv2-1 then
298
                        sclk            <= not sclk;
299
                        edgecntr        <= 0;
300
                else
301
                        edgecntr        <= edgecntr + 1;
302
                end if;
303
        else
304
                edgecntr        <= 0;
305
                if (c_cpol = '0') then
306
                        sclk    <= '0';
307
                else
308
                        sclk    <= '1';
309
                end if;
310
        end if;
311
 
312
end if;
313
end process P_SCLK_GEN;
314
 
315
end Behavioral;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.