1 ---------------------------------------------------------------------------------- 2 -- Company: 3 -- Engineer: shangdawei@gmail.com 4 -- 5 -- Create Date: 08:46:25 05/12/2012 6 -- Design Name: 7 -- Module Name: spi_master - Behavioral 8 -- Project Name: 9 -- Target Devices: 10 -- Tool versions: 11 -- Description: 12 -- 13 -- Dependencies: 14 -- 15 -- Revision: 16 -- Revision 0.01 - File Created 17 -- Additional Comments: 18 -- 19 ---------------------------------------------------------------------------------- 20 21 library IEEE; 22 use IEEE.std_logic_1164.all; 23 24 -- Uncomment the following library declaration if using 25 -- arithmetic functions with Signed or Unsigned values 26 use IEEE.NUMERIC_STD.all; 27 28 -- Uncomment the following library declaration if instantiating 29 -- any Xilinx primitives in this code. 30 -- library UNISIM; 31 -- use UNISIM.VComponents.all; 32 33 entity spi_master is 34 generic ( 35 C_MODE : natural := 0; -- dymatic change enabled when C_MODE > 3 36 C_WIDTH : natural := 9 ); 37 port ( 38 i_clock : in std_logic; -- system clock 39 i_tick : in std_logic; -- xfer enable 40 i_cpol : in std_logic; -- spi clock polarity 41 i_cpha : in std_logic; -- spi clock phase 42 o_sck : out std_logic; -- spi clock 43 o_ss_n : out std_logic; -- spi ss_n ( Ready/nBusy ) 44 o_mosi : out std_logic; -- master out, slave in 45 i_miso : in std_logic; -- master in, slave out 46 i_repeat : in std_logic; -- repeat receive 47 i_tx_valid : in std_logic; -- initiate transaction 48 o_tx_taken : out std_logic; -- tx data taken 49 o_rx_valid : out std_logic; -- rx data valid 50 i_tx_msb : in std_logic_vector (4 downto 0); -- msb of transmit word 51 o_rx_data : out std_logic_vector (C_WIDTH-1 downto 0); -- ( to fifo or rdr ) 52 i_tx_data : in std_logic_vector (C_WIDTH-1 downto 0)); -- ( from fifo or tdr ) 53 end spi_master; 54 55 architecture Behavioral of spi_master is 56 57 signal cpha : std_logic; 58 signal cpol : std_logic; 59 signal cpol_cpha : unsigned (1 downto 0); 60 signal rx_sample : std_logic; 61 signal tx_taken : std_logic := '0'; 62 signal tx_pending : std_logic := '0'; 63 signal rx_last : std_logic; 64 signal rx_done : std_logic := '0'; 65 signal xfer_done : std_logic := '0'; 66 signal rx_valid : std_logic := '0'; 67 signal miso : std_logic; 68 signal sck : std_logic := '0'; 69 signal mosi : std_logic := '0'; 70 signal ss_n : std_logic := '1'; 71 signal rx_cntr : unsigned( 5 downto 0 ) := ( others => '0' ); -- max 32 bits 72 signal shift_reg : std_logic_vector (C_WIDTH-1 downto 0) := ( others => '0' ); 73 signal sreg_load : std_logic; 74 75 begin 76 o_sck <= sck; 77 o_mosi <= mosi; 78 o_ss_n <= ss_n; 79 o_tx_taken <= tx_taken; 80 o_rx_valid <= rx_valid; 81 o_rx_data <= shift_reg; 82 83 cpol_cpha <= to_unsigned( C_MODE, 2 ); 84 cpha <= i_cpha when C_MODE > 3 else cpol_cpha(0); 85 cpol <= i_cpol when C_MODE > 3 else cpol_cpha(1); 86 87 rx_sample <= ( not ( sck xor cpha xor cpol ) ) and ( not ss_n ); -- diff with cpha/cpol 88 rx_last <= '1' when ( rx_cntr = unsigned(i_tx_msb) ) and ( sck = ( cpha xor cpol) ) else '0'; 89 rx_done <= rx_last when rising_edge( i_clock ) and (i_tick = '1' ); -- for both cpha 90 sreg_load <= ( i_tx_valid and ss_n ) or ( i_tx_valid and rx_done ); -- idle or running 91 92 -- xfer done : whether restart next xfer, or go idle 93 process begin 94 wait until rising_edge( i_clock ); 95 if (i_tick = '1' ) then 96 if ( cpha = '0' ) then 97 xfer_done <= rx_done; 98 else -- ( cpha = '1' ) 99 xfer_done <= rx_last; 100 end if; 101 end if; 102 end process; 103 104 process begin 105 wait until rising_edge( i_clock ); 106 if rx_last = '1' then -- rx_last : 1 spi clock cycle 107 rx_valid <= i_tick; -- rx_valid : 1 clock cycle 108 else 109 rx_valid <= '0'; 110 end if; 111 end process; 112 113 -- host can write next data to xfer 114 process begin 115 wait until rising_edge( i_clock ); 116 if ss_n = '1' then -- first xfer only, always tx_taken 117 tx_taken <= i_tick and sreg_load; 118 else -- last xfer no tx_taken ( sreg_load = '0' ) 119 tx_taken <= i_tick and rx_done and sreg_load; 120 end if; -- other xfer give ack 121 end process; 122 123 -- Counting SPI word length : rx_bit # 124 process begin 125 wait until rising_edge( i_clock ); 126 if (i_tick = '1' ) then 127 if ( ss_n = '1' ) or ( rx_last = '1' ) then 128 rx_cntr <= ( others => '0' ); 129 elsif (sck = ( cpha xor cpol ) ) then 130 rx_cntr <= rx_cntr + 1; 131 end if; 132 end if; 133 end process; 134 135 process begin 136 wait until rising_edge( i_clock ); 137 if (i_tick = '1' ) then 138 if cpha = '0' then 139 if ( rx_done = '1' ) then 140 tx_pending <= sreg_load; 141 elsif ( xfer_done = '1' ) then 142 tx_pending <= '0'; 143 end if; 144 end if; 145 end if; 146 end process; 147 148 149 -- Writing the ss_n 150 -- xfer done : whether restart next xfer, or go idle 151 process begin 152 wait until rising_edge( i_clock ); 153 if (i_tick = '1' ) then 154 if ( i_tx_valid = '1' ) then -- xfer_done -> tx_taken -> i_tx_valid 155 ss_n <= '0'; -- i_tx_valid until xfer_done for cpha = '1' 156 157 elsif ( xfer_done = '1' ) then -- cpha = '0' 158 ss_n <= (not i_repeat) and ( not tx_pending ) ; 159 end if; 160 end if; 161 end process; 162 163 -- Generating the SPI clock 164 -- xfer done : whether restart next xfer, or go idle 165 process begin 166 wait until rising_edge( i_clock ); 167 if (i_tick = '1' ) then 168 if ( xfer_done = '1' ) then --- cpha = '1' --- --- cpha = '0' --- 169 if ( i_repeat = '1' ) or ( sreg_load = '1' ) or ( tx_pending = '1' ) then 170 sck <= not sck; 171 else 172 sck <= cpol; -- idle 173 end if; 174 elsif ( ss_n = '0' ) then 175 sck <= not sck; 176 else 177 sck <= cpol; -- idle 178 end if; 179 end if; 180 end process; 181 182 -- Writing the mosi from init data or shifted data 183 process begin 184 wait until rising_edge( i_clock ); 185 if (i_tick = '1' ) then 186 if sreg_load = '1' then 187 -- mosi <= i_tx_data( to_integer( unsigned(i_tx_msb) ) ); 188 mosi <= shift_reg( to_integer( unsigned(i_tx_msb) ) ); 189 else 190 mosi <= shift_reg( to_integer( unsigned(i_tx_msb) ) ); 191 end if; 192 end if; 193 end process; 194 195 -- Reading the miso line and shifting for mosi at next tick 196 process begin 197 wait until rising_edge( i_clock ); 198 if (i_tick = '1' ) then 199 if sreg_load = '1' then 200 shift_reg <= i_tx_data; 201 elsif ( rx_sample = '1' ) then -- mosi is ready to set at next i_tick 202 shift_reg <= shift_reg(shift_reg'high-1 downto 0 ) & i_miso; 203 204 end if; 205 end if; 206 end process; 207 208 end Behavioral;
1 -------------------------------------------------------------------------------- 2 -- Company: 3 -- Engineer: 4 -- 5 -- Create Date: 23:02:26 05/13/2012 6 -- Design Name: 7 -- Module Name: D:/projects/arm9_ise/chapter8/chapter8/spi_xfer_tb.vhd 8 -- Project Name: chapter8 9 -- Target Device: 10 -- Tool versions: 11 -- Description: 12 -- 13 -- VHDL Test Bench Created by ISE for module: spi_xfer 14 -- 15 -- Dependencies: 16 -- 17 -- Revision: 18 -- Revision 0.01 - File Created 19 -- Additional Comments: 20 -- 21 -- Notes: 22 -- This testbench has been automatically generated using types std_logic and 23 -- std_logic_vector for the ports of the unit under test. Xilinx recommends 24 -- that these types always be used for the top-level I/O of a design in order 25 -- to guarantee that the testbench will bind correctly to the post-implementation 26 -- simulation model. 27 -------------------------------------------------------------------------------- 28 library ieee; 29 use ieee.std_logic_1164.all; 30 31 -- Uncomment the following library declaration if using 32 -- arithmetic functions with Signed or Unsigned values 33 use ieee.numeric_std.all; 34 35 entity spi_xfer_tb is 36 end spi_xfer_tb; 37 38 architecture behavior of spi_xfer_tb is 39 40 constant C_MODE : natural := 4; 41 constant C_WIDTH : natural := 8; 42 43 -- Component Declaration for the Unit Under Test (UUT) 44 45 component spi_xfer 46 generic ( 47 C_MODE : natural := 4; -- dymatic change enabled 48 C_WIDTH : natural := 16 ); 49 port ( 50 i_clock : in std_logic; --system clock 51 i_tick : in std_logic; -- xfer enable 52 i_cpol : in std_logic; --spi clock polarity -- sck when idle 53 i_cpha : in std_logic; --spi clock phase 54 i_miso : in std_logic; --master in, slave out 55 o_mosi : out std_logic; --master out, slave in 56 o_sck : out std_logic; --spi clock 57 o_ss_n : out std_logic; -- spi ss_n 58 i_repeat : in std_logic; -- xfering ... 59 i_tx_valid : in std_logic; --initiate transaction 60 i_tx_data : in std_logic_vector (C_WIDTH-1 downto 0); --data to transmit 61 i_tx_msb : in std_logic_vector (4 downto 0); -- # of bit to transmit word 62 o_tx_taken : out std_logic; -- tx data complete 63 o_rx_data : out std_logic_vector (C_WIDTH-1 downto 0); --data received 64 o_rx_valid : out std_logic); -- rx data ready 65 end component; 66 67 68 --Inputs 69 signal i_repeat : std_logic := '0'; 70 signal i_clock : std_logic := '0'; 71 signal i_tick : std_logic := '0'; 72 signal i_cpol : std_logic := '0'; 73 signal i_cpha : std_logic := '0'; 74 signal i_miso : std_logic := '0'; 75 signal i_tx_valid : std_logic := '0'; 76 signal i_tx_data : std_logic_vector(C_WIDTH-1 downto 0) := (others => '0'); 77 signal i_tx_msb : std_logic_vector(4 downto 0) := std_logic_vector( to_unsigned(C_WIDTH-1, 5) ); 78 79 --Outputs 80 signal o_ss_n : std_logic; -- spi ss_n 81 signal o_mosi : std_logic; 82 signal o_sck : std_logic; 83 signal o_tx_taken : std_logic; 84 signal o_rx_data : std_logic_vector(C_WIDTH-1 downto 0); 85 signal o_rx_valid : std_logic; 86 87 signal tx_cntr : unsigned(15 downto 0) := X"0000"; 88 -- Clock period definitions 89 constant i_clock_period : time := 10 ns; 90 91 constant spi_div : natural := 1; 92 signal tick_sr : unsigned(spi_div downto 0) := to_unsigned( 1, spi_div+1); 93 94 begin 95 96 -- Instantiate the Unit Under Test (UUT) 97 uut : spi_xfer 98 generic map ( 99 C_MODE => C_MODE, 100 C_WIDTH => C_WIDTH ) 101 port map ( 102 i_clock => i_clock, 103 i_tick => i_tick, 104 i_cpol => i_cpol, 105 i_cpha => i_cpha, 106 i_miso => i_miso, 107 o_mosi => o_mosi, 108 o_sck => o_sck, 109 o_ss_n => o_ss_n, 110 i_repeat => i_repeat, 111 i_tx_valid => i_tx_valid, 112 i_tx_data => i_tx_data, 113 i_tx_msb => i_tx_msb, 114 o_tx_taken => o_tx_taken, 115 o_rx_data => o_rx_data, 116 o_rx_valid => o_rx_valid 117 ); 118 119 -- Clock process definitions 120 i_clock_process : process 121 begin 122 i_clock <= '0'; 123 wait for i_clock_period/2; 124 i_clock <= '1'; 125 wait for i_clock_period/2; 126 end process; 127 128 i_tick <= tick_sr(0); 129 tick_sr <= tick_sr(tick_sr'high-1 downto 0) & tick_sr(tick_sr'high) when rising_edge ( i_clock ); 130 131 -- Stimulus process 132 stim_proc : 133 process ( i_clock ) 134 begin 135 if rising_edge( i_clock ) then 136 if ( tx_cntr < 100 ) then -- delay 137 i_cpol <= '0'; 138 i_cpha <= '0'; 139 i_tx_msb <= "00111"; 140 i_tx_data <= X"55"; 141 tx_cntr <= tx_cntr + 1; 142 elsif ( tx_cntr < 103 ) then -- setup 143 if ( tx_cntr = 100 ) then 144 i_tx_valid <= '1'; 145 tx_cntr <= tx_cntr + 1; 146 elsif ( o_tx_taken = '1' ) then 147 i_tx_data <= i_tx_data(i_tx_data'high-1 downto 0) & i_tx_data(i_tx_data'high); 148 tx_cntr <= tx_cntr + 1; 149 end if; 150 151 elsif ( tx_cntr < 120 ) then -- delay 152 i_tx_valid <= '0'; 153 if ( o_ss_n = '1' ) then 154 i_cpol <= '0'; 155 i_cpha <= '1'; 156 tx_cntr <= tx_cntr + 1; 157 end if; 158 elsif ( tx_cntr < 123 ) then 159 if ( tx_cntr = 120 ) then 160 i_tx_valid <= '1'; 161 tx_cntr <= tx_cntr + 1; 162 elsif ( o_tx_taken = '1' ) then 163 i_tx_data <= i_tx_data(i_tx_data'high-1 downto 0) & i_tx_data(i_tx_data'high); 164 tx_cntr <= tx_cntr + 1; 165 end if; 166 167 elsif ( tx_cntr < 140 ) then -- delay 168 i_tx_valid <= '0'; 169 if ( o_ss_n = '1' ) then 170 i_cpol <= '1'; 171 i_cpha <= '0'; 172 tx_cntr <= tx_cntr + 1; 173 end if; 174 elsif ( tx_cntr < 143 ) then 175 if ( tx_cntr = 140 ) then 176 i_tx_valid <= '1'; 177 tx_cntr <= tx_cntr + 1; 178 elsif ( o_tx_taken = '1' ) then 179 i_tx_data <= i_tx_data(i_tx_data'high-1 downto 0) & i_tx_data(i_tx_data'high); 180 tx_cntr <= tx_cntr + 1; 181 end if; 182 183 elsif ( tx_cntr < 160 ) then 184 i_tx_valid <= '0'; 185 if ( o_ss_n = '1' ) then 186 i_cpol <= '1'; 187 i_cpha <= '1'; 188 tx_cntr <= tx_cntr + 1; 189 end if; 190 elsif ( tx_cntr < 163 ) then 191 if ( tx_cntr = 160 ) then 192 i_tx_valid <= '1'; 193 tx_cntr <= tx_cntr + 1; 194 elsif ( o_tx_taken = '1' ) then 195 i_tx_data <= i_tx_data(i_tx_data'high-1 downto 0) & i_tx_data(i_tx_data'high); 196 tx_cntr <= tx_cntr + 1; 197 end if; 198 199 elsif ( tx_cntr < 180 ) then 200 i_tx_valid <= '0'; 201 if ( o_ss_n = '1' ) then 202 i_cpol <= '0'; 203 i_cpha <= '0'; 204 tx_cntr <= tx_cntr + 1; 205 end if; 206 elsif ( tx_cntr < 183 ) then 207 if ( tx_cntr = 180 ) then 208 i_tx_valid <= '1'; 209 tx_cntr <= tx_cntr + 1; 210 elsif ( o_tx_taken = '1' ) then 211 i_repeat <= '1'; 212 i_tx_valid <= '0'; 213 tx_cntr <= to_unsigned(183, tx_cntr'length); 214 end if; 215 elsif ( tx_cntr < 185 ) then 216 if o_rx_valid = '1' then 217 tx_cntr <= tx_cntr + 1; 218 end if; 219 else 220 i_repeat <= '0'; 221 end if; 222 end if; 223 end process; 224 225 226 end;