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; |
---|