1 | ---------------------------------------------------------------------------------------------
|
---|
2 | ---------------------------------------------------------------------------------------------
|
---|
3 | -- File: sck_logic_16.vhd
|
---|
4 | --
|
---|
5 | --
|
---|
6 | -- Original file: sck_logic.vhd
|
---|
7 | --
|
---|
8 |
|
---|
9 | -- Created: 8-23-00 ALS
|
---|
10 | -- This file generates an internal SCK by dividing the system clock as determined by CLKDIV.
|
---|
11 | -- This internal SCK has a CPHA=1 relationship to data and is used to clock the internal SPI
|
---|
12 | -- shift register. This internal SCK is used to generate the desired output SCK as determined
|
---|
13 | -- by CPHA and CPOL in the control register. The SCK output to the SPI bus is output only when
|
---|
14 | -- the slave select signals are asserted, but the internal SCK runs continuously.
|
---|
15 | --
|
---|
16 | -- Revised: 8-28-00 ALS
|
---|
17 | -- Revised: 9-11-00 ALS
|
---|
18 | -- Revised: 10-17-00 ALS
|
---|
19 |
|
---|
20 | ---------------------------------------------------------------------------------------------
|
---|
21 | ---------------------------------------------------------------------------------------------
|
---|
22 | -- Modified from 8 to 16 bit word size by Patrick Vogler
|
---|
23 | -- 18th November 2009
|
---|
24 | --
|
---|
25 | -- Modifications are marked by: *Mod: <modification>
|
---|
26 | --
|
---|
27 | -- Cleaned up by Quirin Weitzel
|
---|
28 | -- 21th January 2010
|
---|
29 | ---------------------------------------------------------------------------------------------
|
---|
30 | ---------------------------------------------------------------------------------------------
|
---|
31 | library IEEE;
|
---|
32 | use IEEE.std_logic_1164.all;
|
---|
33 | use IEEE.std_logic_arith.all;
|
---|
34 |
|
---|
35 | entity sck_logic is
|
---|
36 | port(
|
---|
37 | -- internal uC interface signals
|
---|
38 | clkdiv : in std_logic_vector(1 downto 0); -- sets the clock divisor for sck clock
|
---|
39 | cpha : in std_logic; -- sets clock phase for output sck clock
|
---|
40 | cpol : in std_logic; -- sets clock polarity for output sck clock
|
---|
41 |
|
---|
42 | -- internal spi interface signals
|
---|
43 | clk0_mask : in std_logic; -- clock mask for sck when cpha=0
|
---|
44 | clk1_mask : in std_logic; -- clock mask for sck when cpha=1
|
---|
45 | sck_1 : inout std_logic; -- internal sck created from dividing system clock
|
---|
46 | sck_int_re : out std_logic; -- rising edge of internal sck
|
---|
47 | sck_int_fe : out std_logic; -- falling edge of internal sck
|
---|
48 | sck_re : out std_logic; -- rising edge of external sck
|
---|
49 | sck_fe : out std_logic; -- falling edge of external sck
|
---|
50 | ss_in_int : in std_logic; -- another master is on the bus
|
---|
51 |
|
---|
52 | -- external spi interface signals
|
---|
53 | sck : inout std_logic; -- sck as determined by cpha, cpol, and clkdiv
|
---|
54 |
|
---|
55 | -- clock and reset
|
---|
56 | reset : in std_logic; -- active high reset
|
---|
57 | clk : in std_logic -- clock
|
---|
58 |
|
---|
59 | );
|
---|
60 |
|
---|
61 | end sck_logic;
|
---|
62 |
|
---|
63 | architecture DEFINITION of sck_logic is
|
---|
64 |
|
---|
65 | --**************************** Constants ***************************************
|
---|
66 |
|
---|
67 | constant RESET_ACTIVE : std_logic := '0';
|
---|
68 |
|
---|
69 | --**************************** Signals ***************************************
|
---|
70 |
|
---|
71 | signal clk_cnt : STD_LOGIC_VECTOR(4 downto 0); -- clock divider output
|
---|
72 | signal clk_cnt_en : STD_LOGIC; -- count enable for clock divider
|
---|
73 | signal clk_cnt_rst : STD_LOGIC; -- clock count reset
|
---|
74 |
|
---|
75 |
|
---|
76 | signal sck_int_d1 : STD_LOGIC; -- sck_int delayed one clock for edge detection
|
---|
77 | signal sck_int : STD_LOGIC; -- version of sck when CPHA=1
|
---|
78 | signal sck_0 : STD_LOGIC; -- version of sck when CPHA=0
|
---|
79 | signal sck_out : STD_LOGIC; -- sck to be output if SS_IN_INT is not asserted
|
---|
80 | signal sck_d1 : std_logic; -- output sck delayed one clock for edge detection
|
---|
81 |
|
---|
82 |
|
---|
83 | --**************************** Component Definitions ********************************
|
---|
84 | -- 5-bit counter for clock divider
|
---|
85 | component upcnt5
|
---|
86 | port(
|
---|
87 | cnt_en : in STD_LOGIC; -- Count enable
|
---|
88 | clr : in STD_LOGIC; -- Active high clear
|
---|
89 | clk : in STD_LOGIC; -- Clock
|
---|
90 | qout : inout STD_LOGIC_VECTOR (4 downto 0)
|
---|
91 | );
|
---|
92 |
|
---|
93 | end component;
|
---|
94 |
|
---|
95 | begin
|
---|
96 |
|
---|
97 | --************************** Clock Divider Instantiation ********************************
|
---|
98 | CLK_DIVDR : upcnt5
|
---|
99 | port map(
|
---|
100 | cnt_en => clk_cnt_en,
|
---|
101 | clr => clk_cnt_rst,
|
---|
102 | clk => clk,
|
---|
103 | qout => clk_cnt
|
---|
104 | );
|
---|
105 | -- This counter is always enabled, can't instantiate the counter with a literal
|
---|
106 | clk_cnt_en <= '1';
|
---|
107 |
|
---|
108 | -- Clock counter is reset whenever reset is active and ss_in_int is asserted
|
---|
109 | clk_cnt_rst <= RESET_ACTIVE when reset = RESET_ACTIVE or ss_in_int = '0'
|
---|
110 | else not(RESET_ACTIVE);
|
---|
111 |
|
---|
112 | --************************** Internal SCK Generation ***************************************
|
---|
113 | -- SCK when CPHA=1 is simply the output of the clock divider determined by the CLK_DIV bits
|
---|
114 | -- SCK_INT is based off the CPHA=1 waveforms and is used as the internal SCK
|
---|
115 | -- SCK_INT is used to clock the SPI shift register, therefore, it runs before and after SS_N
|
---|
116 | -- is asserted
|
---|
117 | -- SCK_1 is SCK_INT when clk1_mask = 1. The clock mask blocks SCK_INT edges that are before
|
---|
118 | -- and after SS_N
|
---|
119 | sck_int_process: process (clk,reset)
|
---|
120 | begin
|
---|
121 | if reset = RESET_ACTIVE then
|
---|
122 | sck_int <= '0';
|
---|
123 | elsif clk'event and clk = '1' then
|
---|
124 | -- determine clock divider output based on control register
|
---|
125 | case clkdiv is
|
---|
126 | when "00" =>
|
---|
127 | sck_int <= clk_cnt(1);
|
---|
128 | when "01" =>
|
---|
129 | sck_int <= clk_cnt(2);
|
---|
130 | when "10" =>
|
---|
131 | sck_int <= clk_cnt(3);
|
---|
132 | when "11" =>
|
---|
133 | sck_int <= clk_cnt(4);
|
---|
134 | when others => -- error in register
|
---|
135 | sck_int <= '0';
|
---|
136 | end case;
|
---|
137 | end if;
|
---|
138 | end process;
|
---|
139 |
|
---|
140 | sck_1 <= sck_int and clk1_mask;
|
---|
141 |
|
---|
142 | -- Detect rising and falling edges of SCK_1 to use as state transition
|
---|
143 | sck_intedge_process: process(clk, reset)
|
---|
144 | begin
|
---|
145 | if reset = RESET_ACTIVE then
|
---|
146 | sck_int_d1 <= '0';
|
---|
147 | elsif clk'event and clk = '1' then
|
---|
148 | sck_int_d1 <= sck_int;
|
---|
149 | end if;
|
---|
150 | end process;
|
---|
151 |
|
---|
152 | sck_int_re <= '1' when sck_int = '1' and sck_int_d1 = '0'
|
---|
153 | else '0';
|
---|
154 | sck_int_fe <= '1' when sck_int = '0' and sck_int_d1 = '1'
|
---|
155 | else '0';
|
---|
156 |
|
---|
157 | -- SCK when CPHA=0 is out of phase with internal SCK - therefore its toggle needs to be delayed
|
---|
158 | -- by the signal clk_mask and then its simply an inversion of the counter bit
|
---|
159 |
|
---|
160 | sck_0_process: process (clk, reset)
|
---|
161 | begin
|
---|
162 | if reset = RESET_ACTIVE then
|
---|
163 | sck_0 <= '0';
|
---|
164 | elsif clk'event and clk = '1' then
|
---|
165 | if clk0_mask = '0' then
|
---|
166 | sck_0 <= '0';
|
---|
167 | else
|
---|
168 | case clkdiv is
|
---|
169 | when "00" =>
|
---|
170 | sck_0 <= not(clk_cnt(1));
|
---|
171 | when "01" =>
|
---|
172 | sck_0 <= not(clk_cnt(2));
|
---|
173 | when "10" =>
|
---|
174 | sck_0 <= not(clk_cnt(3));
|
---|
175 | when "11" =>
|
---|
176 | sck_0 <= not(clk_cnt(4));
|
---|
177 | when others => -- error in register
|
---|
178 | sck_0 <= '0';
|
---|
179 | end case;
|
---|
180 | end if;
|
---|
181 | end if;
|
---|
182 | end process;
|
---|
183 |
|
---|
184 | --************************** External SCK Generation **********************************
|
---|
185 | -- This process outputs SCK based on the CPHA and CPOL parameters set in the control register
|
---|
186 | sck_out_process: process(clk, reset, cpol)
|
---|
187 | variable temp: std_logic_vector(1 downto 0);
|
---|
188 | begin
|
---|
189 | if reset = RESET_ACTIVE then
|
---|
190 | sck_out <= '0';
|
---|
191 | elsif clk'event and clk = '1' then
|
---|
192 | temp := cpol & cpha;
|
---|
193 | case temp is
|
---|
194 | when "00" => -- polarity = 0, phase = 0
|
---|
195 | -- sck = sck_0
|
---|
196 | sck_out <= sck_0;
|
---|
197 | when "01" => -- polarity= 0, phase = 1
|
---|
198 | -- sck = sck_1
|
---|
199 | sck_out <= sck_1;
|
---|
200 | when "10" => -- polarity = 1, phase = 0
|
---|
201 | -- sck = not(sck_0)
|
---|
202 | sck_out <= not(sck_0);
|
---|
203 | when "11" => -- polarity = 1, phase = 1
|
---|
204 | -- sck = not(sck_1)
|
---|
205 | sck_out <= not(sck_1);
|
---|
206 | when others => -- default to sck_0
|
---|
207 | sck_out <= sck_0;
|
---|
208 | end case;
|
---|
209 | end if;
|
---|
210 | end process;
|
---|
211 |
|
---|
212 | -- Detect rising and falling edges of SCK_OUT to use to end cycle correctly
|
---|
213 | -- and to keep RCV_LOAD signal 1 system clock in width
|
---|
214 | SCK_DELAY_PROCESS: process(clk, reset)
|
---|
215 | begin
|
---|
216 | if reset = RESET_ACTIVE then
|
---|
217 | sck_d1 <= '0';
|
---|
218 | elsif clk'event and clk = '1' then
|
---|
219 | sck_d1 <= sck_out;
|
---|
220 | end if;
|
---|
221 | end process;
|
---|
222 |
|
---|
223 | sck_re <= '1' when sck_out = '1' and sck_d1 = '0'
|
---|
224 | else '0';
|
---|
225 | sck_fe <= '1' when sck_out = '0' and sck_d1 = '1'
|
---|
226 | else '0';
|
---|
227 |
|
---|
228 | -- The SCK output is 3-stated if the SS_IN_INT signal is asserted indicating that another
|
---|
229 | -- master is on the bus
|
---|
230 | sck <= sck_out when ss_in_int = '1'
|
---|
231 | else 'Z';
|
---|
232 |
|
---|
233 | end DEFINITION;
|
---|