SPI bus master for System09 (2)

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