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