---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 11:14:05 07/02/2012 -- Design Name: -- Module Name: lfr_time_management - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; LIBRARY lpp; USE lpp.general_purpose.Clk_divider; ENTITY lfr_time_management IS GENERIC ( masterclk : INTEGER := 25000000; -- master clock in Hz timeclk : INTEGER := 49152000; -- 2nd clock in Hz finetimeclk : INTEGER := 65536; -- divided clock used for the fine time counter nb_clk_div_ticks : INTEGER := 1 -- nb ticks before commutation to AUTO state ); PORT ( master_clock : IN STD_LOGIC; --! Clock -- 25MHz time_clock : IN STD_LOGIC; --! 2nd Clock -- 49MHz resetn : IN STD_LOGIC; --! Reset grspw_tick : IN STD_LOGIC; soft_tick : IN STD_LOGIC; --! soft tick, load the coarse_time value -- 25MHz coarse_time_load : IN STD_LOGIC_VECTOR(31 DOWNTO 0); -- 25MHz coarse_time : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); -- 25MHz fine_time : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); -- 25MHz next_commutation : IN STD_LOGIC_VECTOR(31 DOWNTO 0); -- 25MHz -- reset_next_commutation : OUT STD_LOGIC; irq1 : OUT STD_LOGIC; -- 25MHz irq2 : OUT STD_LOGIC -- 25MHz ); END lfr_time_management; ARCHITECTURE Behavioral OF lfr_time_management IS SIGNAL resetn_clk_div : STD_LOGIC; SIGNAL clk_div : STD_LOGIC; -- SIGNAL flag : STD_LOGIC; SIGNAL s_coarse_time : STD_LOGIC_VECTOR(31 DOWNTO 0); SIGNAL previous_coarse_time_load : STD_LOGIC_VECTOR(31 DOWNTO 0); SIGNAL cpt : INTEGER RANGE 0 TO 100000; SIGNAL secondary_cpt : INTEGER RANGE 0 TO 72000; -- SIGNAL sirq1 : STD_LOGIC; SIGNAL sirq2 : STD_LOGIC; SIGNAL cpt_next_commutation : INTEGER RANGE 0 TO 100000; SIGNAL p_next_commutation : STD_LOGIC_VECTOR(31 DOWNTO 0); SIGNAL latched_next_commutation : STD_LOGIC_VECTOR(31 DOWNTO 0); SIGNAL p_clk_div : STD_LOGIC; -- TYPE state_type IS (auto, slave); SIGNAL state : state_type; TYPE timer_type IS (idle, engaged); SIGNAL commutation_timer : timer_type; BEGIN --******************************************* -- COMMUTATION TIMER AND INTERRUPT GENERATION PROCESS(master_clock, resetn) BEGIN IF resetn = '0' THEN commutation_timer <= idle; cpt_next_commutation <= 0; sirq1 <= '0'; sirq2 <= '0'; latched_next_commutation <= x"ffffffff"; p_next_commutation <= (others => '0'); p_clk_div <= '0'; ELSIF master_clock'EVENT AND master_clock = '1' THEN CASE commutation_timer IS WHEN idle => sirq1 <= '0'; sirq2 <= '0'; IF s_coarse_time = latched_next_commutation THEN commutation_timer <= engaged; -- transition to state "engaged" sirq1 <= '1'; -- start the pulse on sirq1 latched_next_commutation <= x"ffffffff"; ELSIF NOT(p_next_commutation = next_commutation) THEN -- next_commutation has changed latched_next_commutation <= next_commutation; -- latch the value ELSE commutation_timer <= idle; END IF; WHEN engaged => sirq1 <= '0'; -- stop the pulse on sirq1 IF NOT(p_clk_div = clk_div) AND clk_div = '1' THEN -- detect a clk_div raising edge IF cpt_next_commutation = 65536 THEN cpt_next_commutation <= 0; commutation_timer <= idle; sirq2 <= '1'; -- start the pulse on sirq2 ELSE cpt_next_commutation <= cpt_next_commutation + 1; END IF; END IF; WHEN OTHERS => commutation_timer <= idle; END CASE; p_next_commutation <= next_commutation; p_clk_div <= clk_div; END IF; END PROCESS; irq1 <= sirq1; irq2 <= sirq2; -- reset_next_commutation <= '0'; -- --******************************************* --********************** -- synchronization stage PROCESS(master_clock, resetn) -- resynchronisation with clk BEGIN IF resetn = '0' THEN coarse_time(31 DOWNTO 0) <= x"80000000"; -- set the most significant bit of the coarse time to 1 on reset ELSIF master_clock'EVENT AND master_clock = '1' THEN coarse_time(31 DOWNTO 0) <= s_coarse_time(31 DOWNTO 0); -- coarse_time is changed synchronously with clk END IF; END PROCESS; -- --********************** -- PROCESS(clk_div, resetn, grspw_tick, soft_tick, flag, coarse_time_load) -- JC PROCESS(clk_div, resetn) -- JC BEGIN IF resetn = '0' THEN flag <= '0'; cpt <= 0; secondary_cpt <= 0; s_coarse_time <= x"80000000"; -- set the most significant bit of the coarse time to 1 on reset previous_coarse_time_load <= x"80000000"; state <= auto; --ELSIF grspw_tick = '1' OR soft_tick = '1' THEN -- --IF flag = '1' THEN -- coarse_time_load shall change at least 1/65536 s before the timecode -- -- s_coarse_time <= coarse_time_load; -- -- flag <= '0'; -- --ELSE -- if coarse_time_load has not changed, increment the value autonomously -- -- s_coarse_time <= STD_LOGIC_VECTOR(UNSIGNED(s_coarse_time) + 1); -- --END IF; -- cpt <= 0; -- secondary_cpt <= 0; -- state <= slave; ELSIF clk_div'EVENT AND clk_div = '1' THEN CASE state IS WHEN auto => IF grspw_tick = '1' OR soft_tick = '1' THEN IF flag = '1' THEN -- coarse_time_load shall change at least 1/65536 s before the timecode s_coarse_time <= coarse_time_load; ELSE -- if coarse_time_load has not changed, increment the value autonomously s_coarse_time <= STD_LOGIC_VECTOR(UNSIGNED(s_coarse_time) + 1); END IF; flag <= '0'; cpt <= 0; secondary_cpt <= 0; state <= slave; ELSE IF cpt = 65535 THEN IF flag = '1' THEN s_coarse_time <= coarse_time_load; flag <= '0'; ELSE s_coarse_time <= STD_LOGIC_VECTOR(UNSIGNED(s_coarse_time) + 1); END IF; cpt <= 0; secondary_cpt <= secondary_cpt + 1; ELSE cpt <= cpt + 1; END IF; END IF; WHEN slave => IF grspw_tick = '1' OR soft_tick = '1' THEN IF flag = '1' THEN -- coarse_time_load shall change at least 1/65536 s before the timecode s_coarse_time <= coarse_time_load; ELSE -- if coarse_time_load has not changed, increment the value autonomously s_coarse_time <= STD_LOGIC_VECTOR(UNSIGNED(s_coarse_time) + 1); END IF; flag <= '0'; cpt <= 0; secondary_cpt <= 0; state <= slave; ELSE IF cpt = 65536 + nb_clk_div_ticks THEN -- 1 / 65536 = 15.259 us state <= auto; -- commutation to AUTO state IF flag = '1' THEN s_coarse_time <= coarse_time_load; flag <= '0'; ELSE s_coarse_time <= STD_LOGIC_VECTOR(UNSIGNED(s_coarse_time) + 1); END IF; cpt <= nb_clk_div_ticks; -- reset cpt at nb_clk_div_ticks secondary_cpt <= secondary_cpt + 1; ELSE cpt <= cpt + 1; END IF; END IF; WHEN OTHERS => state <= auto; END CASE; IF secondary_cpt > 60 THEN s_coarse_time(31) <= '1'; END IF; IF NOT(previous_coarse_time_load = coarse_time_load) THEN flag <= '1'; END IF; previous_coarse_time_load <= coarse_time_load; END IF; END PROCESS; fine_time <= STD_LOGIC_VECTOR(to_unsigned(cpt, 32)); -- resetn grspw_tick soft_tick resetn_clk_div -- 0 0 0 0 -- 0 0 1 0 -- 0 1 0 0 -- 0 1 1 0 -- 1 0 0 1 -- 1 0 1 0 -- 1 1 0 0 -- 1 1 1 0 resetn_clk_div <= '1' WHEN ((resetn = '1') AND (grspw_tick = '0') AND (soft_tick = '0')) ELSE '0'; Clk_divider0 : Clk_divider -- the target frequency is 65536 Hz GENERIC MAP (timeclk, finetimeclk) PORT MAP (time_clock, resetn_clk_div, clk_div); END Behavioral;