-------------------------------------------------------------
-- MSS copyright 2012-2013
-- Filename:  MEASURE_INTERVAL.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 2
-- Last modified: 7/2/13
-- Inheritance: 	N/A
--
-- description: Measure the average interval between quasi-periodic PULSE_IN pulses, expressed in number of CLK periods.
-- Averaged over 256 pulse periods. Count starts at the first PULSE_IN.
-- As the measurement is truncated, the PERIOD value is always <= the actual period.
--
-- Rev 2 7/2/13 AZ
-- Added PERIOD_FULL_PRECISION output
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MEASURE_INTERVAL is
    Port ( 
		--// CLK, RESET
		CLK: in std_logic;
			-- processing clock
		SYNC_RESET: in std_logic;
			-- synchronous reset = start a new computation
		PULSE_IN: in std_logic;
			-- quasi-periodic pulses. 1 CLK wide.
		
		PERIOD: out std_logic_vector(15 downto 0) := (others => '0');
			-- measured interval. Read at rising edge of CLK when PERIOD_SAMPLE_CLK = '1'
		PERIOD_FULL_PRECISION: out std_logic_vector(23 downto 0) := (others => '0');
			-- same as PERIOD above no truncation (with 8 bits after decimal point). Format 16.8
		PERIOD_SAMPLE_CLK: out std_logic

			);
end entity;

architecture Behavioral of MEASURE_INTERVAL is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
signal PULSE_COUNTER: std_logic_vector(8 downto 0) := (others => '0');
signal PULSE_COUNTER_INC: std_logic_vector(8 downto 0) := (others => '0');
signal PULSE_COUNTER_MSb_D: std_logic := '0';
signal PERIOD_COUNTER: std_logic_vector(24 downto 0) := (others => '0');

--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

--Algorithm: to compute the average period, count the number of CLK periods between 256 successive input pulses, 
-- then divide by 256 and truncate (i.e shift 8 notches to the right)
PULSE_COUNTER_INC <= PULSE_COUNTER + 1;
PULSE_COUNTER_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			-- Start a new computation
			PULSE_COUNTER <= (others => '0');
		elsif(PULSE_IN = '1') and (PULSE_COUNTER /= 257) then
			-- count pulses from 1 to 257 and stay there
			PULSE_COUNTER <= PULSE_COUNTER_INC;
		end if;
	end if;
end process;

PERIOD_COUNTER_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') or (PULSE_COUNTER = 0) then
			-- about to start a new computation. Wait for the first pulse after reset to start counting.
			PERIOD_COUNTER <= (0 => '1', others => '0');
		elsif((PULSE_COUNTER /= 257)  and (PERIOD_COUNTER(24) = '0')) then
			-- count up to the max (PERIOD max = 64k, thus PERIOD_COUNTER max is 64k*256)
			PERIOD_COUNTER <= PERIOD_COUNTER + 1;
		end if;
	end if;
end process;

PERIOD_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(PULSE_IN = '1') and (PULSE_COUNTER = 256) then
			-- detect the end of the computation process
			-- generate a ready pulse 
			PERIOD_SAMPLE_CLK <= '1';
			
			if(PERIOD_COUNTER(24) = '1') then
				-- overflow. clamp to the max
				PERIOD <= (others => '1');
				PERIOD_FULL_PRECISION <= (others => '1');
			else
				PERIOD <= PERIOD_COUNTER(23 downto 8); 
				PERIOD_FULL_PRECISION <= PERIOD_COUNTER(23 downto 0);
			end if;
		else
			PERIOD_SAMPLE_CLK <= '0';
		end if;
	end if;
end process;



end Behavioral;

