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

Subversion Repositories timerocd

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 dewhisna
--------------------------------------------------------------------------------
2
--
3
--   FileName:         spi_slave.vhd
4
--   Dependencies:     none
5
--   Design Software:  Quartus II 32-bit Version 11.1 Build 173 SJ Full Version
6
--
7
--   HDL CODE IS PROVIDED "AS IS."  DIGI-KEY EXPRESSLY DISCLAIMS ANY
8
--   WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
9
--   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
10
--   PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
11
--   BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
12
--   DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
13
--   PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
14
--   BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
15
--   ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
16
--
17
--   Version History
18
--   Version 1.0 7/5/2012 Scott Larson
19
--     Initial Public Release
20
--   Version 1.1 11/27/2012 Scott Larson
21
--     Added an asynchronous active low reset
22
--
23
--------------------------------------------------------------------------------
24
 
25
LIBRARY ieee;
26
USE ieee.std_logic_1164.all;
27
USE ieee.std_logic_arith.all;
28
 
29
ENTITY spi_slave IS
30
  GENERIC(
31
    cpol    : STD_LOGIC := '0';  --spi clock polarity mode
32
    cpha    : STD_LOGIC := '0';  --spi clock phase mode
33
    d_width : INTEGER := 8);     --data width in bits
34
  PORT(
35
    sclk         : IN     STD_LOGIC;  --spi clk from master
36
    reset_n      : IN     STD_LOGIC;  --active low reset
37
    ss_n         : IN     STD_LOGIC;  --active low slave select
38
    mosi         : IN     STD_LOGIC;  --master out, slave in
39
    rx_req       : IN     STD_LOGIC;  --'1' while busy = '0' moves data to the rx_data output
40
    st_load_en   : IN     STD_LOGIC;  --asynchronous load enable
41
    st_load_trdy : IN     STD_LOGIC;  --asynchronous trdy load input
42
    st_load_rrdy : IN     STD_LOGIC;  --asynchronous rrdy load input
43
    st_load_roe  : IN     STD_LOGIC;  --asynchronous roe load input
44
    tx_load_en   : IN     STD_LOGIC;  --asynchronous transmit buffer load enable
45
    tx_load_data : IN     STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);  --asynchronous tx data to load
46
    trdy         : BUFFER STD_LOGIC := '0';  --transmit ready bit
47
    rrdy         : BUFFER STD_LOGIC := '0';  --receive ready bit
48
    roe          : BUFFER STD_LOGIC := '0';  --receive overrun error bit
49
    rx_data      : OUT    STD_LOGIC_VECTOR(d_width-1 DOWNTO 0) := (OTHERS => '0');  --receive register output to logic
50
    busy         : OUT    STD_LOGIC := '0';  --busy signal to logic ('1' during transaction)
51
    miso         : OUT    STD_LOGIC := 'Z'); --master in, slave out
52
END spi_slave;
53
 
54
ARCHITECTURE logic OF spi_slave IS
55
  SIGNAL mode    : STD_LOGIC;  --groups modes by clock polarity relation to data
56
  SIGNAL clk     : STD_LOGIC;  --clock
57
  SIGNAL bit_cnt : STD_LOGIC_VECTOR(d_width+8 DOWNTO 0);  --'1' for active transaction bit
58
  SIGNAL wr_add  : STD_LOGIC;  --address of register to write ('0' = receive, '1' = status)
59
  SIGNAL rd_add  : STD_LOGIC;  --address of register to read ('0' = transmit, '1' = status)
60
  SIGNAL rx_buf  : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0) := (OTHERS => '0');  --receiver buffer
61
  SIGNAL tx_buf  : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0) := (OTHERS => '0');  --transmit buffer
62
BEGIN
63
  busy <= NOT ss_n;  --high during transactions
64
 
65
  --adjust clock so writes are on rising edge and reads on falling edge
66
  mode <= cpol XOR cpha;  --'1' for modes that write on rising edge
67
  WITH mode SELECT
68
    clk <= sclk WHEN '1',
69
           NOT sclk WHEN OTHERS;
70
 
71
  --keep track of miso/mosi bit counts for data alignmnet
72
  PROCESS(ss_n, clk)
73
  BEGIN
74
    IF(ss_n = '1' OR reset_n = '0') THEN                         --this slave is not selected or being reset
75
           bit_cnt <= (conv_integer(NOT cpha) => '1', OTHERS => '0'); --reset miso/mosi bit count
76
    ELSE                                                         --this slave is selected
77
      IF(rising_edge(clk)) THEN                                  --new bit on miso/mosi
78
        bit_cnt <= bit_cnt(d_width+8-1 DOWNTO 0) & '0';          --shift active bit indicator
79
      END IF;
80
    END IF;
81
  END PROCESS;
82
 
83
  PROCESS(ss_n, clk, st_load_en, tx_load_en, rx_req)
84
  BEGIN
85
 
86
    --write address register ('0' for receive, '1' for status)
87
    IF(bit_cnt(1) = '1' AND falling_edge(clk)) THEN
88
      wr_add <= mosi;
89
    END IF;
90
 
91
    --read address register ('0' for transmit, '1' for status)
92
    IF(bit_cnt(2) = '1' AND falling_edge(clk)) THEN
93
      rd_add <= mosi;
94
    END IF;
95
 
96
    --trdy register
97
    IF((ss_n = '1' AND st_load_en = '1' AND st_load_trdy = '0') OR reset_n = '0') THEN
98
      trdy <= '0';   --cleared by user logic or reset
99
    ELSIF(ss_n = '1' AND ((st_load_en = '1' AND st_load_trdy = '1') OR tx_load_en = '1')) THEN
100
      trdy <= '1';   --set when tx buffer written or set by user logic                                  
101
    ELSIF(wr_add = '1' AND bit_cnt(9) = '1' AND falling_edge(clk)) THEN
102
      trdy <= mosi;  --new value written over spi bus
103
    ELSIF(rd_add = '0' AND bit_cnt(d_width+8) = '1' AND falling_edge(clk)) THEN
104
      trdy <= '0';   --clear when transmit buffer read
105
    END IF;
106
 
107
    --rrdy register
108
    IF((ss_n = '1' AND ((st_load_en = '1' AND st_load_rrdy = '0') OR rx_req = '1')) OR reset_n = '0') THEN
109
      rrdy <= '0';   --cleared by user logic or rx_data has been requested or reset
110
    ELSIF(ss_n = '1' AND st_load_en = '1' AND st_load_rrdy = '1') THEN
111
      rrdy <= '1';   --set when set by user logic
112
    ELSIF(wr_add = '1' AND bit_cnt(10) = '1' AND falling_edge(clk)) THEN
113
      rrdy <= mosi;  --new value written over spi bus
114
    ELSIF(wr_add = '0' AND bit_cnt(d_width+8) = '1' AND falling_edge(clk)) THEN
115
      rrdy <= '1';   --set when new data received
116
    END IF;
117
 
118
    --roe register
119
    IF((ss_n = '1' AND st_load_en = '1' AND st_load_roe = '0') OR reset_n = '0') THEN
120
      roe <= '0';   --cleared by user logic or reset
121
    ELSIF(ss_n = '1' AND st_load_en = '1' AND st_load_roe = '1') THEN
122
      roe <= '1';   --set by user logic
123
    ELSIF(rrdy = '1' AND wr_add = '0' AND bit_cnt(d_width+8) = '1' AND falling_edge(clk)) THEN
124
      roe <= '1';   --set by actual overrun
125
    ELSIF(wr_add = '1' AND bit_cnt(11) = '1' AND falling_edge(clk)) THEN
126
      roe <= mosi;  --new value written by spi bus
127
    END IF;
128
 
129
    --receive registers
130
    --write to the receive register from master
131
    IF(reset_n = '0') THEN
132
      rx_buf <= (OTHERS => '0');
133
    ELSE
134
      FOR i IN 0 TO d_width-1 LOOP
135
        IF(wr_add = '0' AND bit_cnt(i+9) = '1' AND falling_edge(clk)) THEN
136
          rx_buf(d_width-1-i) <= mosi;
137
        END IF;
138
      END LOOP;
139
    END IF;
140
    --fulfill user logic request for receive data
141
    IF(reset_n = '0') THEN
142
      rx_data <= (OTHERS => '0');
143
    ELSIF(ss_n = '1' AND rx_req = '1') THEN
144
      rx_data <= rx_buf;
145
    END IF;
146
 
147
    --transmit registers
148
    IF(reset_n = '0') THEN
149
      tx_buf <= (OTHERS => '0');
150
    ELSIF(ss_n = '1' AND tx_load_en = '1') THEN  --load transmit register from user logic
151
      tx_buf <= tx_load_data;
152
    ELSIF(rd_add = '0' AND bit_cnt(7 DOWNTO 0) = "00000000" AND bit_cnt(d_width+8) = '0' AND rising_edge(clk)) THEN
153
      tx_buf(d_width-1 DOWNTO 0) <= tx_buf(d_width-2 DOWNTO 0) & tx_buf(d_width-1);  --shift through tx data
154
    END IF;
155
 
156
    --miso output register
157
    IF(ss_n = '1' OR reset_n = '0') THEN           --no transaction occuring or reset
158
      miso <= 'Z';
159
    ELSIF(rd_add = '1' AND rising_edge(clk)) THEN  --write status register to master
160
      CASE bit_cnt(10 DOWNTO 8) IS
161
        WHEN "001" => miso <= trdy;
162
        WHEN "010" => miso <= rrdy;
163
        WHEN "100" => miso <= roe;
164
        WHEN OTHERS => NULL;
165
      END CASE;
166
    ELSIF(rd_add = '0' AND bit_cnt(7 DOWNTO 0) = "00000000" AND bit_cnt(d_width+8) = '0' AND rising_edge(clk)) THEN
167
      miso <= tx_buf(d_width-1);                  --send transmit register data to master
168
    END IF;
169
 
170
  END PROCESS;
171
END logic;

powered by: WebSVN 2.1.0

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