-------------------------------------------------------------------------
--	AD1_controller.VHD
-------------------------------------------------------------------------
--	Author 		: Todd Harless
-- CopyRight 2005 Digilent, Inc.
-------------------------------------------------------------------------
--	Description : This file is the VHDL code for a PMOD-AD1 controller.
--
-------------------------------------------------------------------------
--	Revision History:
-- 07/11/2005 Created	(Todd Harless)
-- 08/09/2005 revision 0.1		(Todd Harless)
-------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;



-------------------------------------------------------------------------
--Title 		: AD1 controller entity
--
--	Inputs		: 3
--	Outputs		: 3
--
--	Description	: 	This is the AD1 controller entity. The input ports are 
--					  	a 50 MHz clock and an asynchronous 
--						reset	button along with the data from the ADC7476 that 
--						is serially shifted in on each clock cycle. The outputs 
--						are the SCLK signal which clocks the PMOD-AD1 board at 
--						12.5 MHz and a chip select signal (CS) that latches the 
--						data into the PMOD-AD1 board as well as an 12-bit output 
--						vector labeled DATA_OUT which can be used by any 
--						external components.
--
--------------------------------------------------------------------------


entity AD1_controller is
	  Port	(	
     --General usage
        CLK      : in std_logic;	-- System Clock (50MHz)     
        RST		: in std_logic;
	 
	 --Pmod interface signals
        SDATA1    : in std_logic;
        SDATA2   : in std_logic;
		SCLK	: out std_logic;
		CS    : out std_logic;
		
	--User interface signals
	 	DATA1    : out std_logic_vector(11 downto 0);
		DATA2    : out std_logic_vector(11 downto 0);
	 	START	 : in std_logic; 
        DONE     : out std_logic
     		 
				
			);
end AD1_controller;

architecture AD1 of AD1_controller is

--------------------------------------------------------------------------------
--Title 		: 	Local signal assignments
--
--	Description		: 	The following signals will be used to drive the processes of 
--						this VHDL file.
--
--		current_state:	 This signal will be the pointer that will point at the
--							 current state of the Finite State Machine of the 
--							 controller.
--		next_state   :	 This signal will be the pointer that will point at the
--							 current state of the Finite State Machine of the 
--							 controller.
--		temp1   :	 This is a 16-bit vector that will store the 16-bits of data 
--						that are serially shifted-in form the  first ADC7476 chip inside the
--						PMOD-AD1 board.
--		temp2   :	 This is a 16-bit vector that will store the 16-bits of data 
--						that are serially shifted-in form the second ADC7476 chip inside the
--						PMOD-AD1 board.
--		dat1   :	 This is a 12-bit vector that will store the 12-bits of actual data 
--						that are serially shifted-in form the  first ADC7476 chip inside the
--						PMOD-AD1 board.
--		dat2   :	 This is a 12-bit vector that will store the 12-bits of actual data 
--						that are serially shifted-in form the second ADC7476 chip inside the
--						PMOD-AD1 board.
--		clk_div	 : 	This will be the divided 12.5 MHz clock signal that will
--						clock the PMOD-AD1 board
--		clk_counter	 :	This counter will be used to create a divided clock signal.
--
--		shiftCounter	 :	This counter will be used to count the shifted data from the 
--						ADC7476 chip inside the PMOD-AD1 board.
--		enShiftCounter	 :	This signal will be used to  enable the counter for the shifted  
--						data from the ADC7476 chip inside the PMOD-AD1 board.
--		enParalelLoad	 :	This signal will be used to  enable the load in a register the shifted  
--						data.
--------------------------------------------------------------------------------

type states is (Idle,
		  		 ShiftIn, 
				 SyncData);  
		  signal current_state : states;
		  signal next_state : states;
		  	  	 
		  signal temp1         : std_logic_vector(15 downto 0) := (others => '0');
		  signal temp2         : std_logic_vector(15 downto 0) := (others => '0'); 
        signal dat1         : std_logic_vector(11 downto 0):= x"000";
		  signal dat2         : std_logic_vector(11 downto 0):= x"000";        		  
		  signal clk_div       : std_logic;	  
		  signal clk_counter   : std_logic_vector(27 downto 0);	
		  signal shiftCounter  : std_logic_vector(3 downto 0) := x"0"; 
		  signal enShiftCounter: std_logic;
		  signal enParalelLoad : std_logic;



begin



--------------------------------------------------------------------------------
--Title			: 	clock divider process
--
--		Description	:	This is the process that will divide the 50 MHz clock 
--						down to a clock speed of 12.5 MHz to drive the ADC7476 chip. 
--------------------------------------------------------------------------------		
		clock_divide : process(rst,clk)
		begin
			if rst = '1' then
				clk_counter <= "0000000000000000000000000000";
			elsif (clk = '1' and clk'event) then
				clk_counter <= clk_counter + '1';
			end if;
		end process;

		clk_div <= clk_counter(1);
		SCLK <=  not clk_counter(1);

-----------------------------------------------------------------------------------
--
-- Title      : counter
--
-- Description: This is the process were the teporary registers will be loaded and 
--              shifted.When the enParalelLoad signal is generated inside the state 
--              the temp1 and temp2 registers will be loaded with the 8 bits of control
--			       concatenated with the 8 bits of data. When the enShiftCounter is 
--              activated, the 16-bits of data inside the temporary registers will be 
--              shifted. A 4-bit counter is used to keep shifting the data 
--					 inside temp1 and temp2 for 16 clock cycles.
--	
-----------------------------------------------------------------------------------	

counter : process(clk_div, enParalelLoad, enShiftCounter)
		begin
			if (clk_div = '1' and clk_div'event) then
			   
				if (enShiftCounter = '1') then 
				   temp1 <= temp1(14 downto 0) & SDATA1;
					temp2 <= temp2(14 downto 0) & SDATA2;	
					shiftCounter <= shiftCounter + '1';
				elsif (enParalelLoad = '1') then
				   shiftCounter <= "0000";
				   dat1 <= temp1(11 downto 0);
					dat2 <= temp2(11 downto 0);
				end if;
			end if;
		end process;
  DATA1 <= dat1 ;
  DATA2 <= dat2 ;
---------------------------------------------------------------------------------
--
-- Title      : Finite State Machine
--
-- Description: This 3 processes represent the FSM that contains three states. The first 
--					 state is the Idle state in which a temporary registers are 
--					 assigned the updated value of the input "DATA1" and "DATA2". The next state 
--					 is the ShiftIn state where the 16-bits of 
--					 data from each of the ADCS7476 chips are left shifted in the temp1 and temp2 shift registers.
--					The third 
--					 state SyncData drives the output signal CS high for
--					 1 clock period, and the second one in the Idle state telling the ADCS7476 to mark the end of the conversion.
-- Notes:		 The data will change on the lower edge of the clock signal. Their 
--					 is also an asynchronous reset that will reset all signals to their 
--					 original state.
--
-----------------------------------------------------------------------------------		
		
-----------------------------------------------------------------------------------
--
-- Title      : SYNC_PROC
--
-- Description: This is the process were the states are changed synchronously. At 
--              reset the current state becomes Idle state.
--	
-----------------------------------------------------------------------------------			
SYNC_PROC: process (clk_div, rst)
   begin
      if (clk_div'event and clk_div = '1') then
         if (rst = '1') then
            current_state <= Idle;
         else
            current_state <= next_state;
         end if;        
      end if;
   end process;
	
-----------------------------------------------------------------------------------
--
-- Title      : OUTPUT_DECODE
--
-- Description: This is the process were the output signals are generated
--              unsynchronously based on the state only (Moore State Machine).
--	
-----------------------------------------------------------------------------------		
OUTPUT_DECODE: process (current_state)
   begin
      if current_state = Idle then
			enShiftCounter <='0';
			DONE <='1';
			CS <='1';
			enParalelLoad <= '0';
		elsif current_state = ShiftIn then
			enShiftCounter <='1';
			DONE <='0';
			CS <='0';
			enParalelLoad <= '0';
		else --if current_state = SyncData then
			enShiftCounter <='0';
			DONE <='0';
			CS <='1';
			enParalelLoad <= '1';
		end if;
   end process;	
	
----------------------------------------------------------------------------------
--
-- Title      : NEXT_STATE_DECODE
--
-- Description: This is the process were the next state logic is generated 
--              depending on the current state and the input signals.
--	
-----------------------------------------------------------------------------------	
	NEXT_STATE_DECODE: process (current_state, START, shiftCounter)
   begin
      
      next_state <= current_state;  --default is to stay in current state
     
      case (current_state) is
         when Idle =>
            if START = '1' then
               next_state <= ShiftIn;
            end if;
         when ShiftIn =>
            if shiftCounter = x"F" then
               next_state <= SyncData;
            end if;
         when SyncData =>
			if START = '0' then
            next_state <= Idle;
			end if;
         when others =>
            next_state <= Idle;
      end case;      
   end process;


end AD1;
