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

Subversion Repositories timerocd

[/] [timerocd/] [trunk/] [src/] [spi_slave.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 dewhisna
--------------------------------------------------------------------------------
2
--      File name : spi_slave.vhd
3
--------------------------------------------------------------------------------
4
--      Copyright (C) 2015 Donna Whisnant/Dewtronics.
5
--      Contact: http://www.dewtronics.com/
6
--
7
--      This file may be used under the terms of the GNU Lesser General Public License
8
--      version 3.0 as published by the Free Software Foundation and appearing
9
--      in the files lgpl-3.0.txt/gpl-3.0.txt included in the packaging of this file.
10
--      Please review the following information to ensure the GNU Lesser General
11
--      Public License version 3.0 requirements will be met:
12
--      https://www.gnu.org/licenses/lgpl-3.0.html
13
--      Attribution requested, but not required.
14
--
15
--      Target Device: Xilinx Spartan-6 XC6SLX9-2-TQG144
16
--              Using Numato Mimas Spartan 6 FPGA Development Board
17
--              http://numato.com/mimas-spartan-6-fpga-development-board.html
18
--
19
--
20
--      SPI Slave Entity for TimerOCD
21
--
22
--------------------------------------------------------------------------------
23
 
24
library IEEE;
25
use IEEE.std_logic_1164.all;
26
use IEEE.std_logic_arith.all;
27
use IEEE.std_logic_unsigned.all;
28
 
29
library UNISIM;
30
use UNISIM.VCOMPONENTS.all;
31
 
32
entity spi_slave is
33
        generic (
34
                cpol    : STD_LOGIC := '0';              --spi clock polarity mode
35
                cpha    : STD_LOGIC := '0';              --spi clock phase mode
36
                d_width : INTEGER := 8                  --data width in bits
37
        );
38
        port (
39
                sync_clk                : in     STD_LOGIC;             --system clock in for synchronization of the SS signal
40
                sclk                    : in     STD_LOGIC;             --spi clk from master
41
                reset_n                 : in     STD_LOGIC;             --active low reset
42
                ss_n                    : in     STD_LOGIC;             --active low slave select
43
                mosi                    : in     STD_LOGIC;             --master out, slave in
44
                rrdy                    : out    STD_LOGIC := '0';       --receive ready bit
45
                rx_data                 : out    STD_LOGIC_VECTOR(d_width-1 downto 0) := (OTHERS => '0'); --receive register output to logic
46
                busy                    : out    STD_LOGIC := '0';       --busy signal to logic ('1' during transaction)
47
                miso                    : out    STD_LOGIC := 'Z';      --master in, slave out
48
                tx_load_data    : in     STD_LOGIC_VECTOR(d_width-1 downto 0);           --Tx data to load (synchronous with end of address receive)
49
                addr                    : out    STD_LOGIC_VECTOR(7 downto 0) := (OTHERS => '0'); -- Address to Read or Write (as received from SPI)
50
                addr_latch              : out    STD_LOGIC := '0';       -- Address Latch Enable Output (Set to True when the address is ready on the output and data should be supplied)
51
                cmd_load_data   : in     STD_LOGIC_VECTOR(3 downto 0) := (OTHERS => '0')  -- Data nybble to shift out during low nybble of command byte receive
52
        );
53
end spi_slave;
54
 
55
architecture logic of spi_slave is
56
        signal mode    : STD_LOGIC;             --groups modes by clock polarity relation to data
57
        signal clk     : STD_LOGIC;             --clock
58
        constant nRSB : integer := 4;                                                           -- Number of RxState Bits (used for conversions)
59
        signal rx_state : STD_LOGIC_VECTOR(nRSB-1 downto 0);             -- Receive state-machine
60
        signal rxbit_cnt : INTEGER range 0 to d_width-1;                 -- Bit count for data received
61
        constant nTSB : integer := 3;                                                           -- Number of TxState Bits (used for conversions)
62
        signal tx_state : STD_LOGIC_VECTOR(nTSB-1 downto 0);             -- Transmit state-machine
63
        constant nTBCSB : integer := 3;                                                         -- Transmit Bit Count State Bits (used for conversions)
64
        signal txbit_flg : STD_LOGIC_VECTOR(nTBCSB-1 downto 0);          -- Bit count for data sent
65
        signal wr_add  : STD_LOGIC := '1';      -- address of register to write ('0' = receive, '1' = status)
66
        signal cmd_add : STD_LOGIC := '0';       -- command or data ('0' = data, '1' = command)
67
        signal rx_buf  : STD_LOGIC_VECTOR(d_width-2 downto 0) := (OTHERS => '0'); --receiver buffer
68
        signal tx_buf  : STD_LOGIC_VECTOR(d_width-1 downto 0) := (OTHERS => '0'); -- transmit buffer
69
        signal cmd_buf : STD_LOGIC_VECTOR(2 downto 0) := (OTHERS => '0');                 -- command buffer
70
        signal out_data : STD_LOGIC;            -- Output data gated to miso
71
        signal syn_ss_n : STD_LOGIC;            -- Synchronized SS_N signal
72
        signal syn_mosi : STD_LOGIC;            -- MOSI synchronized to sync_clk
73
        signal syn_clk_fall : STD_LOGIC;        -- CLK falling edge synchronized to sync_clk
74
        signal syn_clk_rise : STD_LOGIC;        -- CLK rising edge synchronized to sync_clk
75
        signal resync_clk : STD_LOGIC_VECTOR(3 downto 0);
76
        signal resync_ss : STD_LOGIC_VECTOR(1 downto 0);
77
        signal resync_mosi : STD_LOGIC_VECTOR(1 downto 0);
78
        signal rrdy_int : STD_LOGIC;            -- Internal rrdy.  Set in the Rx State-Machine.  Used to trigger a delayed rrdy pulse back to the main logic to get data a setup/hold time
79
        signal rrdy_out : STD_LOGIC;            -- Output rrdy (used to eliminate buffer type)
80
        signal addr_latch_int : STD_LOGIC;      -- Internal addr_latch.  Set in the Rx State-Machine.  Used to trigger a delayed addr_latch pulse back to the main logic to get data a setup/hold time
81
        signal addr_latch_out : STD_LOGIC;      -- Output addr_latch (used to eliminate buffer type)
82
begin
83
        --adjust clock so writes are on rising edge and reads on falling edge
84
        mode <= cpol XOR cpha;  --'1' for modes that write on rising edge
85
        with mode select
86
                clk <= sclk when '1', NOT sclk when OTHERS;
87
 
88
        -- Input synchronization:
89
        sync_clk_proc:process(sync_clk)
90
        begin
91
                if (rising_edge(sync_clk)) then
92
                        syn_ss_n <= resync_ss(0);
93
                        syn_mosi <= resync_mosi(0);
94
                        resync_clk <= resync_clk(2 downto 0) & clk;
95
                        resync_ss <= resync_ss(0) & ss_n;
96
                        resync_mosi <= resync_mosi(0) & mosi;
97
                end if;
98
        end process sync_clk_proc;
99
        syn_clk_fall <= resync_clk(3) and not resync_clk(2);    -- '1' when going from 1 -> 0
100
        syn_clk_rise <= not resync_clk(2) and resync_clk(1);    -- '1' when going from 0 -> 1
101
 
102
        -- output drive:
103
        with (syn_ss_n OR (NOT reset_n)) select
104
                miso <= 'Z' when '1', out_data when OTHERS;
105
 
106
        busy <= NOT syn_ss_n;  --high during transactions
107
 
108
        -- rrdy synchronization:
109
        --      Since rxspiproc is triggered on the rising_edge of
110
        --              sync_clk, this process delays reporting it
111
        --              by 1/2 clock cycle, giving the data time to
112
        --              get stored:
113
        rrdyproc:process(syn_ss_n, sync_clk, reset_n)
114
        begin
115
                if ((syn_ss_n = '1') OR (reset_n = '0')) then
116
                        rrdy_out <= '0';
117
                elsif (falling_edge(sync_clk)) then
118
                        if (rrdy_out = '0') then
119
                                rrdy_out <= rrdy_int;
120
                        end if;
121
                end if;
122
        end process rrdyproc;
123
        rrdy <= rrdy_out;
124
 
125
        -- addr_latch synchronization:
126
        --      Since rxspiproc is triggered on the rising_edge of
127
        --              sync clk, this process delays reporting it
128
        --              by 1/2 clock cycle, giving the data time to
129
        --              get stored:
130
        addrlatchproc:process(syn_ss_n, sync_clk, reset_n)
131
        begin
132
                if ((syn_ss_n = '1') OR (reset_n = '0')) then
133
                        addr_latch_out <= '0';
134
                elsif (falling_edge(sync_clk)) then
135
                        if (addr_latch_out = '0') then
136
                                addr_latch_out <= addr_latch_int;
137
                        end if;
138
                end if;
139
        end process addrlatchproc;
140
        addr_latch <= addr_latch_out;
141
 
142
        -- rxspiproc: Receives incoming data
143
        rxspiproc:process(syn_ss_n, syn_clk_fall, reset_n)
144
        begin
145
                if ((syn_ss_n = '1') OR (reset_n = '0')) then
146
                        rx_state <= (OTHERS => '0');
147
                        rx_buf <= (OTHERS => '0');
148
                        rxbit_cnt <= d_width-1;
149
                        rrdy_int <= '0';
150
                        addr_latch_int <= '0';
151
                elsif (falling_edge(syn_clk_fall)) then
152
                        case CONV_INTEGER(rx_state) is
153
                                when 0 =>
154
                                        --read/write mode ('0' for write, '1' for read)
155
                                        wr_add <= syn_mosi;
156
                                        addr(7) <= syn_mosi;
157
                                        rx_state <= CONV_STD_LOGIC_VECTOR(1, nRSB);
158
                                when 1 =>
159
                                        --cmd/data mode ('0' for data, '1' for cmd)
160
                                        cmd_add <= syn_mosi;
161
                                        addr(6) <= syn_mosi;
162
                                        rx_state <= CONV_STD_LOGIC_VECTOR(3, nRSB);
163
                                when 3 =>
164
                                        addr(5) <= syn_mosi;
165
                                        rx_state <= CONV_STD_LOGIC_VECTOR(2, nRSB);
166
                                when 2 =>
167
                                        addr(4) <= syn_mosi;
168
                                        rx_state <= CONV_STD_LOGIC_VECTOR(6, nRSB);
169
                                when 6 =>
170
                                        addr(3) <= syn_mosi;
171
                                        rx_state <= CONV_STD_LOGIC_VECTOR(7, nRSB);
172
                                when 7 =>
173
                                        addr(2) <= syn_mosi;
174
                                        rx_state <= CONV_STD_LOGIC_VECTOR(5, nRSB);
175
                                when 5 =>
176
                                        addr(1) <= syn_mosi;
177
                                        rx_state <= CONV_STD_LOGIC_VECTOR(4, nRSB);
178
                                when 4 =>
179
                                        addr(0) <= syn_mosi;
180
                                        if (cmd_add = '1') then
181
                                                rx_state <= CONV_STD_LOGIC_VECTOR(13, nRSB);
182
                                                if (wr_add = '0') then
183
                                                        rrdy_int <= '1';
184
                                                end if;
185
                                        else
186
                                                addr_latch_int <= '1';
187
                                                rx_state <= CONV_STD_LOGIC_VECTOR(12, nRSB);
188
                                        end if;
189
                                when 12 =>
190
                                        if (rxbit_cnt = 0) then
191
                                                if (wr_add = '0') then
192
                                                        rx_data <= rx_buf & syn_mosi;
193
                                                        rrdy_int <= '1';
194
                                                end if;
195
                                                rx_state <= CONV_STD_LOGIC_VECTOR(13, nRSB);
196
                                        else
197
                                                if (wr_add = '0') then
198
                                                        rx_buf <= rx_buf(rx_buf'HIGH-1 downto 0) & syn_mosi;
199
                                                end if;
200
                                                rxbit_cnt <= (rxbit_cnt - 1);
201
                                                -- Stay in this state until all bits are received
202
                                        end if;
203
                                when 13 =>
204
                                        -- Stay in this state.  The SS_n signal will release us
205
                                when OTHERS =>
206
                        end case;
207
                end if;
208
        end process rxspiproc;
209
 
210
 
211
        -- txspiproc: Transmits outgoing data
212
        --      Note: Commented out code for cmd_buf/cmd_load_data and
213
        --              tx_buf/tx_load_data can be used to determine the point
214
        --              where data must be ready/available from the main TimerOCD
215
        --              relative to the SPI traffic.  This allows for faster SPI
216
        --              clock rates by only requiring the first couple of bits and/or
217
        --              first byte of data to be valid when the SPI clock begins
218
        --              shifting it out.  Since several memory read operations are
219
        --              required to obtain the data needed to be sent, this allows
220
        --              for several SPI clock cycle times before that data reading
221
        --              must be completed.
222
        txspiproc:process(syn_ss_n, syn_clk_rise, reset_n)
223
        begin
224
                if ((syn_ss_n = '1') OR (reset_n = '0')) then
225
                        tx_state <= (OTHERS => '0');
226
                        tx_buf <= (OTHERS => '0');
227
                        txbit_flg <= (OTHERS => '0');
228
                        out_data <= '0';
229
                elsif (rising_edge(syn_clk_rise)) then
230
                        case CONV_INTEGER(tx_state) is
231
                                when 0 =>
232
                                        tx_state <= CONV_STD_LOGIC_VECTOR(1, nTSB);
233
                                when 1 =>
234
                                        tx_state <= CONV_STD_LOGIC_VECTOR(3, nTSB);
235
                                when 3 =>
236
                                        tx_state <= CONV_STD_LOGIC_VECTOR(2, nTSB);
237
                                when 2 =>
238
                                        out_data <= cmd_load_data(3);
239
--                                      cmd_buf <= cmd_load_data(2 downto 0);
240
                                        tx_state <= CONV_STD_LOGIC_VECTOR(6, nTSB);
241
                                when 6 =>
242
--                                      out_data <= cmd_buf(2);
243
                                        out_data <= cmd_load_data(2);
244
                                        cmd_buf <= cmd_load_data(2 downto 0);
245
                                        tx_state <= CONV_STD_LOGIC_VECTOR(7, nTSB);
246
                                when 7 =>
247
                                        out_data <= cmd_buf(1);
248
                                        tx_state <= CONV_STD_LOGIC_VECTOR(5, nTSB);
249
                                when 5 =>
250
                                        out_data <= cmd_buf(0);
251
                                        tx_state <= CONV_STD_LOGIC_VECTOR(4, nTSB);
252
                                when 4 =>
253
                                        if (cmd_add='0') then
254
                                                case CONV_INTEGER(txbit_flg) is
255
                                                        when 0 =>
256
                                                                out_data <= tx_load_data(d_width-1);
257
--                                                              tx_buf <= tx_load_data(d_width-2 downto 0) & "0";
258
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(1, nTBCSB);
259
                                                        when 1 =>
260
                                                                out_data <= tx_load_data(d_width-2);
261
--                                                              tx_buf <= tx_load_data(d_width-3 downto 0) & "00";
262
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(3, nTBCSB);
263
                                                        when 3 =>
264
                                                                out_data <= tx_load_data(d_width-3);
265
--                                                              tx_buf <= tx_load_data(d_width-4 downto 0) & "000";
266
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(2, nTBCSB);
267
                                                        when 2 =>
268
                                                                out_data <= tx_load_data(d_width-4);
269
--                                                              tx_buf <= tx_load_data(d_width-5 downto 0) & "0000";
270
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(6, nTBCSB);
271
                                                        when 6 =>
272
                                                                out_data <= tx_load_data(d_width-5);
273
--                                                              tx_buf <= tx_load_data(d_width-6 downto 0) & "00000";
274
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(7, nTBCSB);
275
                                                        when 7 =>
276
                                                                out_data <= tx_load_data(d_width-6);
277
--                                                              tx_buf <= tx_load_data(d_width-7 downto 0) & "000000";
278
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(5, nTBCSB);
279
                                                        when 5 =>
280
                                                                out_data <= tx_load_data(d_width-7);
281
                                                                tx_buf <= tx_load_data(d_width-8 downto 0) & "0000000";
282
                                                                txbit_flg <= CONV_STD_LOGIC_VECTOR(4, nTBCSB);
283
                                                        when 4 =>
284
                                                                out_data <= tx_buf(tx_buf'HIGH);
285
                                                                tx_buf <= tx_buf(tx_buf'HIGH-1 downto 0) & "0";
286
                                                                -- Stay here and shift out remaining data.  SS_n will release us
287
                                                        when OTHERS =>
288
                                                end case;
289
                                        else
290
                                                out_data <= '0';
291
                                        end if;
292
                                        -- stay in this state shifting data out
293
                                when OTHERS =>                                                  -- There are no other states, but keep ghdl happy
294
                        end case;
295
                end if;
296
        end process txspiproc;
297
end logic;

powered by: WebSVN 2.1.0

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