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;