library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.spi_pkg.all;
entity spi_clkgen is
generic (
DIVISORS : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256);
DIVISORS_LOG2 : natural := 3
);
port (
clk_i : in std_logic;
rst_in : in std_logic;
start_i : in std_logic;
-- next_data_i : in std_logic;
div_sel_i : in std_logic_vector(DIVISORS_LOG2 - 1 downto 0);
clock_polarity_i : in std_logic;
clock_phase_i : in std_logic;
sck_o : out std_logic;
sck_mask_i : in std_logic;
clock_rising_o : out std_logic;
sample_data_o : out std_logic;
change_data_o : out std_logic);
end entity spi_clkgen;
architecture a1 of spi_clkgen is
constant MAX : natural := get_max_natural(DIVISORS);
signal curr_running : std_logic;
signal next_running : std_logic;
signal selected_divisor : natural range 0 to MAX := 1;
signal changing : std_logic;
signal curr_counter : integer range 0 to MAX - 1;
signal next_counter : integer range 0 to MAX - 1;
signal curr_sck : std_logic;
signal next_sck : std_logic;
begin -- architecture a1
set_data: process (clk_i) is
begin -- process set_data
if rising_edge(clk_i) then -- rising clock edge
if rst_in = '0' then -- synchronous reset (active low)
curr_running <= '0';
curr_sck <= '0';
curr_counter <= 0;
else
curr_running <= next_running;
curr_sck <= next_sck;
curr_counter <= next_counter;
end if;
end if;
end process set_data;
selected_divisor <= DIVISORS(to_integer(unsigned(div_sel_i)));
changing <= '1' when curr_counter = 0 and curr_running = '1' else '0';
next_counter <= selected_divisor - 2 when changing = '1' else
0 when curr_counter = 0 else
curr_counter - 1 when curr_running = '1' else
selected_divisor - 1;
sample_data_o <= sck_mask_i when curr_sck = clock_phase_i and changing = '1' else '0';
change_data_o <= sck_mask_i when curr_sck /= clock_phase_i and changing = '1' else
'1' when clock_phase_i = '0' and start_i = '1' and curr_running = '0' else
-- '1' when next_data_i = '1' else
'0';
next_sck <= not curr_sck when changing = '1'
else curr_sck when curr_running = '1' else
'0';
next_running <= start_i;
sck_o <= clock_polarity_i when sck_mask_i = '0' else
curr_sck when clock_polarity_i = '0' else
not curr_sck;
clock_rising_o <= '1' when curr_sck = clock_phase_i and changing = '1' else '0';
end architecture a1;