OpenCores

Subversion Repositories System09

[/] [System09/] [trunk/] [rtl/] [VHDL/] [spi-master.vhd] - Blame information for rev 99

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

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

powered by: WebSVN 2.1.0

© copyright 1999-2014 OpenCores.org, equivalent to ORSoC AB, all rights reserved. OpenCores®, registered trademark.