SPI bus master for System09

  1 -- SPI bus master for System09 
  2 -- (http://members.optushome.com.au/jekent/system09/index.html)
  3 
  4 -- This core implements a SPI master interface.  Transfer size is 4, 8, 12 or
  5 -- 16 bits.  The SPI clock is 0 when idle, sampled on the rising edge of the SPI
  6 -- clock.  The SPI clock is derived from the bus clock input divided 
  7 -- by 2, 4, 8 or 16.
  8 
  9 -- clk, reset, cs, rw, addr, data_in, data_out and irq represent the System09
 10 -- bus interface.
 11 -- spi_clk, spi_mosi, spi_miso and spi_cs_n are the standard SPI signals meant
 12 -- to be routed off-chip.
 13 
 14 -- The SPI core provides for four register addresses that the CPU can read or
 15 -- write:
 16 
 17 -- 0 -> DL: Data LSB
 18 -- 1 -> DH: Data MSB
 19 -- 2 -> CS: Command/Status
 20 -- 3 -> CO: Config
 21 
 22 -- Write bits, CS:
 23 --
 24 -- START CS[0]:   Start transfer
 25 -- END   CS[1]:   Deselect device after transfer (or immediately if START = '0')
 26 -- IRQEN CS[2]:   Generate IRQ at end of transfer
 27 -- SPIAD CS[6:4]: SPI device address
 28 -- 
 29 -- Read bits, CS:
 30 --
 31 -- BUSY  CS[0]: Currently transmitting data
 32 --
 33 -- Write BITS, CO:
 34 --
 35 -- DIVIDE CO[1:0]: SPI clock divisor, 00=clk/2, 01=clk/4, 10=clk/8, 11=clk/16
 36 -- LENGTH CO[3:2]: Transfer length, 00=4 bits, 01=8 bits, 10=12 bits, 11=16 bits
 37 --
 38 
 39 library ieee;
 40 use ieee.std_logic_1164.all;
 41 use ieee.std_logic_unsigned.all;
 42 
 43 entity spi_master is
 44   port (
 45     clk, reset, cs, rw : in  std_logic;
 46     addr               : in  std_logic_vector(1 downto 0);
 47     data_in            : in  std_logic_vector(7 downto 0);
 48     data_out           : out std_logic_vector(7 downto 0);
 49     irq                : out std_logic;
 50     spi_clk, spi_mosi  : out std_logic;
 51     spi_cs_n           : out std_logic_vector(7 downto 0);
 52     spi_miso           : in  std_logic);
 53 end;
 54 
 55 architecture rtl of spi_master is
 56 
 57   -- State type of the SPI transfer state machine
 58   type   state_type is (s_idle, s_running, s_done);
 59   signal state : state_type;
 60   -- Shift register
 61   signal shift_reg : std_logic_vector(15 downto 0);
 62   -- Buffer to hold data to be sent
 63   signal spi_data_buf : std_logic_vector(15 downto 0);
 64   -- Start transmission flag
 65   signal start : std_logic;
 66   -- Number of bits transfered
 67   signal count : std_logic_vector(3 downto 0);
 68   -- Buffered SPI clock
 69   signal spi_clk_buf : std_logic;
 70   -- Buffered SPI clock output
 71   signal spi_clk_out : std_logic;
 72   -- Previous SPI clock state
 73   signal prev_spi_clk : std_logic;
 74   -- Number of clk cycles-1 in this SPI clock period
 75   signal spi_clk_count : std_logic_vector(2 downto 0);
 76   -- SPI clock divisor
 77   signal spi_clk_divide : std_logic_vector(1 downto 0);
 78   -- SPI transfer length
 79   signal transfer_length : std_logic_vector(1 downto 0);
 80   -- Flag to indicate that the SPI slave should be deselected after the current
 81   -- transfer
 82   signal deselect : std_logic;
 83   -- Flag to indicate that an IRQ should be generated at the end of a transfer
 84   signal irq_enable : std_logic;
 85   -- Signal to clear IRQ
 86   signal irqack : std_logic;
 87   -- Internal chip select signal, will be demultiplexed through the cs_mux
 88   signal spi_cs : std_logic;
 89   -- Current SPI device address
 90   signal spi_addr : std_logic_vector(2 downto 0);
 91 begin
 92 
 93   -- Read CPU bus into internal registers
 94   cpu_write : process(clk, reset)
 95   begin
 96     if reset = '1' then
 97       deselect        <= '0';
 98       irq_enable      <= '0';
 99       start           <= '0';
100       spi_clk_divide  <= "11";
101       transfer_length <= "11";
102       spi_data_buf    <= (others => '0');
103     elsif falling_edge(clk) then
104       start  <= '0';
105       irqack <= '0';
106       if cs = '1' and rw = '0' then
107         case addr is
108           when "00" =>
109             spi_data_buf(7 downto 0) <= data_in;
110           when "01" =>
111             spi_data_buf(15 downto 8) <= data_in;
112           when "10" =>
113             start      <= data_in(0);
114             deselect   <= data_in(1);
115             irq_enable <= data_in(2);
116             spi_addr   <= data_in(6 downto 4);
117             irqack     <= '1';
118           when "11" =>
119             spi_clk_divide  <= data_in(1 downto 0);
120             transfer_length <= data_in(3 downto 2);
121           when others =>
122             null;
123         end case;
124       end if;
125     end if;
126   end process;
127 
128   -- Provide data for the CPU to read
129   cpu_read : process(shift_reg, addr, state, deselect, start)
130   begin
131     data_out <= (others => '0');
132     case addr is
133       when "00" =>
134         data_out <= shift_reg(7 downto 0);
135       when "01" =>
136         data_out <= shift_reg(15 downto 8);
137       when "10" =>
138         if state = s_idle then
139           data_out(0) <= '0';
140         else
141           data_out(0) <= '1';
142         end if;
143         data_out(1) <= deselect;
144       when others =>
145         null;
146     end case;
147   end process;
148 
149   spi_cs_n <= "11111110" when spi_addr = "000" and spi_cs = '1' else
150               "11111101" when spi_addr = "001" and spi_cs = '1' else
151               "11111011" when spi_addr = "010" and spi_cs = '1' else
152               "11110111" when spi_addr = "011" and spi_cs = '1' else
153               "11101111" when spi_addr = "100" and spi_cs = '1' else
154               "11011111" when spi_addr = "101" and spi_cs = '1' else
155               "10111111" when spi_addr = "110" and spi_cs = '1' else
156               "01111111" when spi_addr = "111" and spi_cs = '1' else
157               "11111111";
158 
159   -- SPI transfer state machine
160   spi_proc : process(clk, reset)
161   begin
162     if reset = '1' then
163       count        <= (others => '0');
164       shift_reg    <= (others => '0');
165       prev_spi_clk <= '0';
166       spi_clk_out  <= '0';
167       spi_cs       <= '0';
168       state        <= s_idle;
169       irq          <= '0';
170     elsif falling_edge(clk) then
171       prev_spi_clk <= spi_clk_buf;
172       irq          <= '0';
173       case state is
174         when s_idle =>
175           if start = '1' then
176             count     <= (others => '0');
177             shift_reg <= spi_data_buf;
178             spi_cs    <= '1';
179             state     <= s_running;
180           elsif deselect = '1' then
181             spi_cs <= '0';
182           end if;
183         when s_running =>
184           if prev_spi_clk = '1' and spi_clk_buf = '0' then
185             spi_clk_out <= '0';
186             count       <= count + "0001";
187             shift_reg   <= shift_reg(14 downto 0) & spi_miso;
188             if ((count = "0011" and transfer_length = "00")
189               or (count = "0111" and transfer_length = "01")
190                 or (count = "1011" and transfer_length = "10")
191                 or (count = "1111" and transfer_length = "11")) then
192               if deselect = '1' then
193                 spi_cs <= '0';
194               end if;
195               if irq_enable = '1' then
196                 irq   <= '1';
197                 state <= s_done;
198               end if;
199               state <= s_idle;
200             end if;
201           elsif prev_spi_clk = '0' and spi_clk_buf = '1' then
202             spi_clk_out <= '1';
203           end if;
204         when s_done =>
205           if irqack = '1' then
206             state <= s_idle;
207           end if;
208         when others =>
209           null;
210       end case;
211     end if;
212   end process;
213 
214   -- Generate SPI clock
215   spi_clock_gen : process(clk, reset)
216   begin
217     if reset = '1' then
218       spi_clk_count <= (others => '0');
219       spi_clk_buf   <= '0';
220     elsif falling_edge(clk) then
221       if state = s_running then
222         if ((spi_clk_divide = "00")
223           or (spi_clk_divide = "01" and spi_clk_count = "001")
224             or (spi_clk_divide = "10" and spi_clk_count = "011")
225             or (spi_clk_divide = "11" and spi_clk_count = "111")) then
226           spi_clk_buf   <= not spi_clk_buf;
227           spi_clk_count <= (others => '0');
228         else
229           spi_clk_count <= spi_clk_count + "001";
230         end if;
231       else
232         spi_clk_buf <= '0';
233       end if;
234     end if;
235   end process;
236 
237   spi_mosi_mux : process(shift_reg, transfer_length)
238   begin
239     case transfer_length is
240       when "00" =>
241         spi_mosi <= shift_reg(3);
242       when "01" =>
243         spi_mosi <= shift_reg(7);
244       when "10" =>
245         spi_mosi <= shift_reg(11);
246       when "11" =>
247         spi_mosi <= shift_reg(15);
248       when others =>
249         null;
250     end case;
251   end process;
252 
253   spi_clk <= spi_clk_out;
254 
255 end rtl;
posted @ 2012-05-16 12:06  IAmAProgrammer  阅读(314)  评论(0编辑  收藏  举报