spi master vhdl

  1 http://eewiki.net/display/LOGIC/Serial+Peripheral+Interface+(SPI)+Master+(VHDL)
  2 
  3 --------------------------------------------------------------------------------
  4 --
  5 --   FileName:         spi_master.vhd
  6 --   Dependencies:     none
  7 --   Design Software:  Quartus II Version 9.0 Build 132 SJ Full Version
  8 --
  9 --   HDL CODE IS PROVIDED "AS IS."  DIGI-KEY EXPRESSLY DISCLAIMS ANY
 10 --   WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
 11 --   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 12 --   PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
 13 --   BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
 14 --   DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
 15 --   PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 16 --   BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
 17 --   ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
 18 --
 19 --   Version History
 20 --   Version 1.0 7/23/2010 Scott Larson
 21 --     Initial Public Release
 22 --    
 23 --------------------------------------------------------------------------------
 24 
 25 library ieee;
 26 use ieee.std_logic_1164.all;
 27 use ieee.std_logic_arith.all;
 28 use ieee.std_logic_unsigned.all;
 29 
 30 entity spi_master is
 31   generic(
 32     slaves  : INTEGER := 8;  --number of spi slaves
 33     d_width : INTEGER := 8); --data bus width
 34   port(
 35     clock   : in     STD_LOGIC;                             --system clock
 36     reset_n : in     STD_LOGIC;                             --asynchronous reset
 37     enable  : in     STD_LOGIC;                             --initiate transaction
 38     cpol    : in     STD_LOGIC;                             --spi clock polarity
 39     cpha    : in     STD_LOGIC;                             --spi clock phase
 40     cont    : in     STD_LOGIC;                             --continuous mode command
 41     clk_div : in     INTEGER;                               --system clock cycles per 1/2 period of sclk
 42     addr    : in     INTEGER;                               --address of slave
 43     tx_data : in     STD_LOGIC_VECTOR(d_width-1 downto 0);  --data to transmit
 44     miso    : in     STD_LOGIC;                             --master in, slave out
 45     sclk    : buffer STD_LOGIC;                             --spi clock
 46     ss_n    : buffer STD_LOGIC_VECTOR(slaves-1 downto 0);   --slave select
 47     mosi    : out    STD_LOGIC;                             --master out, slave in
 48     busy    : out    STD_LOGIC;                             --busy / data ready signal
 49     rx_data : out    STD_LOGIC_VECTOR(d_width-1 downto 0)); --data received
 50 end spi_master;
 51 
 52 architecture logic of spi_master is
 53   type machine is(ready, execute);                           --state machine data type
 54   signal state       : machine;                              --current state
 55   signal slave       : INTEGER;                              --slave selected for current transaction
 56   signal clk_ratio   : INTEGER;                              --current clk_div
 57   signal count       : INTEGER;                              --counter to trigger sclk from system clock
 58   signal clk_toggles : INTEGER range 0 to d_width*2 + 1;     --count spi clock toggles
 59   signal assert_data : STD_LOGIC;                            --'1' is tx sclk toggle, '0' is rx sclk toggle
 60   signal continue    : STD_LOGIC;                            --flag to continue transaction
 61   signal rx_buffer   : STD_LOGIC_VECTOR(d_width-1 downto 0); --receive data buffer
 62   signal tx_buffer   : STD_LOGIC_VECTOR(d_width-1 downto 0); --transmit data buffer
 63   signal last_bit_rx : INTEGER range 0 to d_width*2;         --last rx data bit location
 64 begin
 65   process(clock, reset_n)
 66   begin
 67 
 68     if(reset_n = '0') then        --reset system
 69       busy    <= '1';                --set busy signal
 70       ss_n    <= (others => '1');    --deassert all slave select lines
 71       mosi    <= 'Z';                --set master out to high impedance
 72       rx_data <= (others => '0'); --clear receive data port
 73       state   <= ready;             --go to ready state when reset is exited
 74 
 75     elsif(clock'EVENT and clock = '1') then
 76       case state is               --state machine
 77 
 78         when ready =>
 79           busy     <= '0';             --clock out not busy signal
 80           ss_n     <= (others => '1'); --set all slave select outputs high
 81           mosi     <= 'Z';             --set mosi output high impedance
 82           continue <= '0';         --clear continue flag
 83 
 84           --user input to initiate transaction
 85           if(enable = '1') then
 86             busy <= '1';             --set busy signal
 87             if(addr < slaves) then   --check for valid slave address
 88               slave <= addr;         --clock in current slave selection if valid
 89             else
 90               slave <= 0;            --set to first slave if not valid
 91             end if;
 92             if(clk_div = 0) then     --check for valid spi speed
 93               clk_ratio <= 1;        --set to maximum speed if zero
 94               count     <= 1;            --initiate system-to-spi clock counter
 95             else
 96               clk_ratio <= clk_div;  --set to input selection if valid
 97               count     <= clk_div;      --initiate system-to-spi clock counter
 98             end if;
 99             sclk        <= cpol;            --set spi clock polarity
100             assert_data <= not cpha; --set spi clock phase
101             tx_buffer   <= tx_data;    --clock in data for transmit into buffer
102             clk_toggles <= 0;        --initiate clock toggle counter
103             last_bit_rx <= d_width*2 + conv_integer(cpha) - 1; --set last rx data bit
104             state       <= execute;        --proceed to execute state
105           else
106             state <= ready;          --remain in ready state
107           end if;
108 
109         when execute =>
110           busy        <= '1';        --set busy signal
111           ss_n(slave) <= '0'; --set proper slave select output
112 
113           --system clock to sclk ratio is met
114           if(count = clk_ratio) then
115             count       <= 1;                     --reset system-to-spi clock counter
116             assert_data <= not assert_data; --switch transmit/receive indicator
117             clk_toggles <= clk_toggles + 1; --increment spi clock toggles counter
118 
119             --spi clock toggle needed
120             if(clk_toggles <= d_width*2 and ss_n(slave) = '0') then
121               sclk <= not sclk; --toggle spi clock
122             end if;
123 
124             --receive spi clock toggle
125             if(assert_data = '0' and clk_toggles < last_bit_rx + 1 and ss_n(slave) = '0') then
126               rx_buffer <= rx_buffer(d_width-2 downto 0) & miso; --shift in received bit
127             end if;
128 
129             --transmit spi clock toggle
130             if(assert_data = '1' and clk_toggles < last_bit_rx) then
131               mosi      <= tx_buffer(d_width-1);                     --clock out data bit
132               tx_buffer <= tx_buffer(d_width-2 downto 0) & '0'; --shift data transmit buffer
133             end if;
134 
135             --last data receive, but continue
136             if(clk_toggles = last_bit_rx and cont = '1') then
137               tx_buffer   <= tx_data;                       --reload transmit buffer
138               clk_toggles <= last_bit_rx - d_width*2 + 1; --reset spi clock toggle counter
139               continue    <= '1';                            --set continue flag
140             end if;
141 
142             --normal end of transaction, but continue
143             if(continue = '1') then
144               continue <= '0';      --clear continue flag
145               busy     <= '0';          --clock out signal that first receive data is ready
146               rx_data  <= rx_buffer; --clock out received data to output port
147             end if;
148 
149             --end of transaction
150             if((clk_toggles = d_width*2 + 1) and cont = '0') then
151               busy    <= '0';             --clock out not busy signal
152               ss_n    <= (others => '1'); --set all slave selects high
153               mosi    <= 'Z';             --set mosi output high impedance
154               rx_data <= rx_buffer;    --clock out received data to output port
155               state   <= ready;          --return to ready state
156             else                       --not end of transaction
157               state <= execute;        --remain in execute state
158             end if;
159 
160           else        --system clock to sclk ratio not met
161             count <= count + 1; --increment counter
162             state <= execute;   --remain in execute state
163           end if;
164 
165       end case;
166     end if;
167   end process;
168 end logic;
posted @ 2012-05-14 10:20  IAmAProgrammer  阅读(1181)  评论(0编辑  收藏  举报