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

Subversion Repositories tinyvliw8

[/] [tinyvliw8/] [trunk/] [src/] [vhdl/] [spiMaster.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 steckol
--
2
-- SPI master module for 32 bit processor               kth @ IHP Dec. 2006
3
--
4
-- This VHDL ENTITY implements an SPI interface master core to be connected 
5
-- to a microprocessor. It occupies 4 registers of 32 bit width in the address 
6
-- space for the following functions:
7
--
8
--      addr 0 write:   write data to SPI interface and read at the same time
9
--      addr 0 read:    get last received SPI data word
10
--      addr 1 write:   set number of data bits in SPI word (bit 4:0)
11
--      addr 1 read:    bit 4-0: number of data bits in SPI word -1
12
--      addr 2 write:   set clock prescaler max. value (bit 3:0)
13
--      addr 2 read:    bit 4-0: clock prescaler maximum value
14
--      addr 3 write:   bit 0: SCK clock mode selector (see below)
15
--                     bit 1: SPI shift+strobe edge selector (see below)
16
--                     bit 2: SS active level selector (see below)
17
--      addr 3 read:    bit 0: SCK clock mode selector (see below)
18
--                     bit 1: SPI shift+strobe edge selector (see below)
19
--                     bit 2: SS active level selector (see below)
20
--                     bit 13-8: current clock prescaler (counter) value
21
--                     bit 22-16: current state (shift) counter 
22
--                     bit 31: operation completed, high active
23
--
24
-- The output port "intr" is equivalent to status bit 31 and can be used for 
25
-- an interrupt to the processor on completion of a data transfer. 
26
-- The bit is cleared when a new transfer starts. 
27
-- The core averages all input (MISO) bits before shifting them into the input 
28
-- data register. For this purpose the design countains an accumulator, which 
29
-- is cleared on every "shifting" edge of the SPI clock SCK. Then, it strobes 
30
-- the MISO input on every rising edge og teh primary clock. Finally, the 
31
-- accumulated sum is compared with the clock prescaler value to make a 
32
-- majority decision whether the bit is high or low. 
33
--
34
-- Configurable parameters of SPI master core:
35
--
36
--   number of data bits in SPI word (addr 1, bit 4-0, default value = 7): 
37
--      The parameter gives the number of data bits - 1, which will be sent 
38
--      and received when writing a word to address 0. The parameter's range 
39
--      is 0 - 31, which corresponds to 1 - 32 bit. 
40
--   clock prescaler max. value (addr 2, bit 3-0, default value = 3): 
41
--      The parameter gives the max. count value of a prescaler to generate 
42
--      the SPI clock signal SCK from input clock. The prescaler completely 
43
--      expires in every half SCK cycle (high / low). The parameter's range 
44
--      is 1(!) - 15, which corresponds to a divider ratio of 1:4 - 1:32. 
45
--   SCK clock mode selector (addr 3, bit 0, default value = low): 
46
--      low : SCK is low  in idle phases, first edge is a rising  edge
47
--      high: SCK is high in idle phases, first edge is a falling edge
48
--   SPI shift+strobe edge selector (addr 3, bit 1, default value = low): 
49
--      low : first  (and all odd)  SCK edges strobe the MOSI and MISO values
50
--            second (and all even) shift the data word to the next bit
51
--      high: first  (and all odd)  shift the data word to the next bit
52
--            second (and all even) SCK edges strobe the MOSI and MISO values
53
--   SS active level selector (addr 3, bit 2, default value = low): 
54
--      low : SS (slave select) output is low active (high in idle phases)
55
--      high: SS (slave select) output is high active (low in idle phases)
56
 
57
LIBRARY ieee;
58
USE ieee.std_logic_1164.all;
59
USE     ieee.numeric_std.all;
60
 
61
ENTITY SPImaster IS
62
  PORT (
63
        inclk : IN  STD_LOGIC;  -- system clock
64
        rst_n : IN  STD_LOGIC;  -- synchr. system reset, high active
65
 
66
-- processor interface
67
        we_n  : IN  STD_LOGIC;  -- write enable, low active
68
        re_n  : IN  STD_LOGIC;  -- read  enable, low active
69
        addr  : IN  STD_LOGIC_VECTOR(1 DOWNTO 0); -- address from processor
70
        din   : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);-- data from processor
71
        dout  : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);-- async. data to processor
72
        intr  : OUT STD_LOGIC;  -- interrupt to processor, high active
73
        intra : IN STD_LOGIC;   -- interrupt acknowledge
74
 
75
-- SPI interface
76
        SCK  : OUT STD_LOGIC;   -- SPI clock
77
        SS   : OUT STD_LOGIC;   -- SPI slave select, active level configurable
78
        MOSI : OUT STD_LOGIC;   -- SPI master output, slave input
79
        MISO : IN  STD_LOGIC    -- SPI master input, slave output
80
  );
81
END SPImaster;
82
 
83
 
84
ARCHITECTURE behav OF SPImaster IS
85
 
86
  SIGNAL busy_s  : STD_LOGIC;            -- transfer active
87
  SIGNAL irqEn   : STD_LOGIC;            -- interrupt enable
88
  SIGNAL enable  : STD_LOGIC;            -- enable spi
89
  SIGNAL clkmode : STD_LOGIC;            -- low: SCK starts with rising edge
90
  SIGNAL bitmode : STD_LOGIC;            -- low: strobe at 1st SCK edge, shift at 2nd edge
91
  SIGNAL sslevel : STD_LOGIC;            -- active level of SS output signal
92
  signal ssmode  : std_logic;            -- automatic SS output signal
93
  SIGNAL prsc    : UNSIGNED(4 DOWNTO 0); -- clock prescaler counter
94
  SIGNAL bits    : UNSIGNED(2 DOWNTO 0); -- number of bits in SPI word
95
  SIGNAL words   : unsigned(4 downto 0); -- number of SPI words in single transfer
96
 
97
  SIGNAL clkcnt : UNSIGNED(prsc'LENGTH-1 DOWNTO 0);-- clock counter within one bit
98
  SIGNAL bitcnt : UNSIGNED(bits'LENGTH+1 DOWNTO 0);-- state machine / bit counter
99
  SIGNAL data : STD_LOGIC_VECTOR(7 DOWNTO 0);    -- internal data shift register
100
  SIGNAL accu : STD_LOGIC_VECTOR(7 DOWNTO 0);   -- accumulator to MISO values
101
 
102
  SIGNAL bitcntmax : UNSIGNED(bitcnt'LENGTH-1 DOWNTO 0);-- tmp. variable
103
 
104
  signal fin_s  : std_logic;
105
  signal cs_s   : std_logic;
106
  signal mosi_s : std_logic;
107
 
108
  SIGNAL fin_clk : std_logic;
109
  SIGNAL clk : std_logic;
110
  SIGNAL sclk_s : std_logic;
111
 
112
BEGIN
113
 
114
        bitcntmax <= Shift_Left(RESIZE(bits, bitcntmax'LENGTH), 1) + 4;
115
 
116
        clk <= not(inclk) when enable = '1' and rst_n = '1' else
117
               '0';
118
 
119
  PROCESS (rst_n, we_n)                 -- SPI config. registers
120
    BEGIN
121
        IF rst_n = '0' THEN
122
          clkmode <= '0';
123
          bitmode <= '0';
124
          sslevel <= '0';
125
          ssmode  <= '0';
126
          enable  <= '0';
127
          irqEn   <= '0';
128
          prsc    <= "00011";
129
          bits    <= "111";
130
          words   <= "00001";
131
          data    <= (others => '0');
132
        ELSIF (we_n'event and we_n = '0') THEN
133
                if (re_n = '0') then
134
                        if (addr = "00" and bitcnt = bitcntmax and clkcnt = prsc) then
135
                                data <= din;
136
                                if (words /= "00000") then
137
                                        words <= words - 1;
138
                                end if;
139
                        else
140
                                CASE addr IS
141
                                WHEN "11" => clkmode <= din(0);
142
                              bitmode <= din(1);
143
                              sslevel <= din(2);
144
                                          ssmode  <= din(3);
145
                              irqEn   <= din(6);
146
                              enable  <= din(7);
147
                                WHEN "10" => prsc <= UNSIGNED(din(4 DOWNTO 0));
148
                                WHEN "01" => words <= UNSIGNED(din(7 DOWNTO 3));
149
                                         bits <= UNSIGNED(din(2 DOWNTO 0));
150
                                WHEN OTHERS => NULL;
151
                                END CASE;
152
                        end if;
153
                end if;
154
        END IF;
155
  END PROCESS;
156
 
157
        fin_clk <= '1' when bitcnt = 0 and clkcnt = 0 else
158
                   '1' when re_n = '0' and we_n = '0' and addr = "00" else
159
                   '0';
160
 
161
        process (rst_n, fin_clk)
162
        begin
163
                if (rst_n = '0') then
164
                        fin_s <= '1';
165
                else
166
                        if (fin_clk'event and fin_clk = '1') then
167
                                if (re_n = '0' and we_n = '0' and addr = "00") then
168
                                        fin_s <= '0';
169
                                else
170
                                        fin_s <= '1';
171
                                end if;
172
                        end if;
173
                end if;
174
        end process;
175
 
176
        cnt_p : process (rst_n, clk)
177
        begin
178
                if (rst_n = '0') then
179
                        bitcnt <= (others => '1');
180
                        clkcnt <= (others => '1');
181
                        -- bitcnt <= bitcntmax;
182
                        -- clkcnt <= prsc;
183
                else
184
                        IF clk'EVENT AND clk='0' THEN
185
                                if (fin_s = '0') then
186
                                        IF clkcnt /= 0 THEN
187
                                                clkcnt <= clkcnt - 1;
188
                                        ELSIF bitcnt /= 0 THEN
189
                                                bitcnt <= bitcnt - 1;
190
                                        end if;
191
                                else
192
                                        bitcnt <= bitcntmax;
193
                                        clkcnt <= prsc;
194
                                end if;
195
                        end if;
196
                end if;
197
        end process;
198
 
199
        busy_flag_p : PROCESS (rst_n, clk)                      -- signals generated from state machine
200
        BEGIN
201
                IF rst_n = '0' THEN
202
                        busy_s <= '0';
203
                ELSIF clk'EVENT AND clk = '1' THEN
204
                        if (fin_s = '0') then
205
                                IF clkcnt = 0 and bitcnt = 1 THEN
206
                                        busy_s <= '0';
207
                                else
208
                                        busy_s <= '1';
209
                                END IF;
210
                        else
211
                                busy_s <= '0';
212
                        END IF;
213
                END IF;
214
        END PROCESS;
215
 
216
        cs_gen_p : process (rst_n, busy_s)
217
        begin
218
                if (rst_n = '0') then
219
                        cs_s <= '1';
220
                else
221
                        if (busy_s'event and busy_s = '1') then
222
                                if (words = "00000") then
223
                                        cs_s <= '1';
224
                                else
225
                                        cs_s <= '0';
226
                                end if;
227
                        end if;
228
                end if;
229
        end process;
230
 
231
        SS <= 'Z'          when enable = '0' else
232
              not(sslevel) when ssmode = '1' and (cs_s = '1' and busy_s = '0') else
233
              sslevel;
234
 
235
        PROCESS (rst_n, clk)
236
        BEGIN
237
                if (rst_n = '0') then
238
                        sclk_s <= '0';
239
                        accu   <= (others => '0');
240
                        mosi_s   <= '0';
241
                ELSIF clk'EVENT AND clk='1' THEN
242
                        IF clkcnt /= 0 THEN
243
                                NULL;
244
                        ELSIF bitcnt > 1 AND bitcnt < bitcntmax THEN
245
                                sclk_s <= clkmode XOR bitcnt(0);
246
 
247
                                if ((bitmode = '0' and sclk_s = not(clkmode)) or (bitmode = '1' and sclk_s = clkmode)) then
248
                                        if (bitmode = '0') then
249
                                                mosi_s <= accu(To_Integer(bits));
250
                                        else
251
                                                mosi_s <= accu(To_Integer(bits));
252
                                        end if;
253
                                else
254
                                        accu <= accu(6 downto 0) & MISO;
255
                                end if;
256
                        ELSE
257
                                sclk_s <= clkmode;
258
 
259
                                if (fin_s = '0' and bitcnt = bitcntmax) then
260
                                        accu <= data;
261
                                        mosi_s <= data(To_Integer(bits));
262
                                end if;
263
                        END IF;
264
                END IF;
265
        END PROCESS;
266
 
267
        MOSI <= mosi_s when enable = '1' else
268
                'Z';
269
        SCK  <= sclk_s when enable = '1' else
270
                'Z';
271
 
272
        irq_gen : process(enable, irqEn, clk)
273
        begin
274
                IF (enable = '0' and irqEn = '0') THEN
275
                         intr <= '0';
276
                ELSE
277
                        if (clk'EVENT AND clk = '0') THEN
278
                                if (intra = '1') then
279
                                        intr <= '0';
280
                                else
281
                                        if fin_s = '1' and bitcnt = 0 and clkcnt = 0 then
282
                                                intr <= '1';
283
                                        end if;
284
                                end if;
285
                        end if;
286
                end if;
287
        end process;
288
 
289
        WITH addr SELECT dout <=
290
                accu                                                               WHEN "00",
291
                std_logic_vector(words) & STD_LOGIC_VECTOR(bits)                   WHEN "01",
292
                STD_LOGIC_VECTOR(RESIZE(prsc,dout'LENGTH))                         WHEN "10",
293
                enable & irqEn & '0' & busy_s & ssmode & sslevel & bitmode & clkmode WHEN OTHERS;
294
 
295
END behav;

powered by: WebSVN 2.1.0

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