RSS Git Download  Clone
Raw Blame History
-- =============================================================================================
--                             	                                                            **
-- =============================================================================================
--	Title: phy_cntrl.vhd
--	Description:	VHDL  design file for control of an I2C interface
--
--	Interfaces to the I2C bus to provide control of DP83865 PHY
--	Notes
--	a)Max clock speed for this device is 2.5 MHz, standard I2C is 100 kHz
--  b)Data format is start (2), opcode(2), Phy Address(5), RegAddress(5), turnround (2)
--    data bits (16)
--	Mod Record
--	===========
--	1)23/01/2008 11:50		 created
--
--
-- (C) Copyright Alpha Data Parallel Systems Ltd. 1999-2008
--
--
-------------------------------------------------------------------------------------------------



--********************************************************************************************








--********************************************************************************************
--			Entity Definition
--
-- Notes:
--********************************************************************************************
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;





entity phy_cntrl is
port
(
		--Host controls
		reset		:in		std_logic;
		clock		:in		std_logic;
		ckdiv_cnt	:in		std_logic_vector(15 downto 0);

		rd_flag	:in		std_logic;
		wr_flag	:in		std_logic;

		busy		:out		std_logic;

		--	Params for I2C transfer
		phy_addr		:in		std_logic_vector(4 downto 0);
		reg_addr		:in		std_logic_vector(4 downto 0);

		wrdata_in		:in		std_logic_vector(15 downto 0);
		rddata_out	:out		std_logic_vector(15 downto 0);

		--PHY signals
		phy_reset_l :out		std_logic;
		i2c_clock	:out		std_logic;
		i2c_data  :inout		std_logic
	);
end phy_cntrl;
--********************************************************************************************







--********************************************************************************************
--	Architecture Definition
--
--********************************************************************************************
architecture synth of phy_cntrl is









--********************************************************************************************
--	Constant/Type Definitions
--********************************************************************************************
constant MSB_CNT :integer := 23;
constant PHY0_ADDR :std_logic_vector := "10000";
constant PHY1_ADDR :std_logic_vector := "10001";

constant REG0_ADDR :std_logic_vector  := "00000";
constant REG13_ADDR :std_logic_vector := "10011";
constant PWDN_CODE :std_logic_vector  := x"0800";
constant LED_CODE :std_logic_vector   := x"0c00";	--steady green



  type state_type is (
						i2c_idle,
						i2c_reset,
						i2c_init,
						i2c_wait0,
						i2c_pwdn1,
						i2c_wait1,
						i2c_pwdn2,
						i2c_wait2,
						i2c_led1,
						i2c_wait3,
						i2c_led2,
						i2c_wait4,
						i2c_stop
					);

--********************************************************************************************


--********************************************************************************************
--	Component Definitions
--********************************************************************************************
component phy_i2c is
port
(
		--Host controls
		reset		:in		std_logic;
		clock		:in		std_logic;
		ckdiv_cnt	:in		std_logic_vector(15 downto 0);

		rd_flag	:in		std_logic;
		wr_flag	:in		std_logic;
		ini_flag	:in		std_logic;

		busy		:out		std_logic;

		--	Params for I2C transfer
		phy_addr		:in		std_logic_vector(4 downto 0);
		reg_addr		:in		std_logic_vector(4 downto 0);

		wrdata_in		:in		std_logic_vector(15 downto 0);
		rddata_out	:out		std_logic_vector(15 downto 0);

		--I2C signals
		i2c_clock	:out		std_logic;
		i2c_data  :inout		std_logic
	);
end component phy_i2c;


--********************************************************************************************







--********************************************************************************************
--	Signal Definitions
--
--********************************************************************************************



signal	if_wr_flag_sig	:		std_logic;
signal	if_rd_flag_sig	:		std_logic;
signal if_phyaddr_sig		:	std_logic_vector(4 downto 0);
signal	if_regaddr_sig		:std_logic_vector(4 downto 0);
signal	rd_data_sig	:		std_logic_vector(15 downto 0);
signal	if_wrdata_sig		:	std_logic_vector(15 downto 0);
signal	i2c_data_sig	 :		std_logic;





signal	busy_sig           :std_logic;

signal	bitcnt_sig         :std_logic_vector(7 downto 0);
signal	rcvd_data_sig		:std_logic_vector(15 downto 0);
signal	optype_sig        	:std_logic;


------------------------------------------------------



------------------------------------------------------
--I2c data port input
------------------------------------------------------
signal	i2c_data_bit_in_sig   :std_logic;
------------------------------------------------------




------------------------------------------------------
--Local bus i/f
------------------------------------------------------
signal	reset_sig      :std_logic;
signal	clock_sig      :std_logic;
signal	data_in_sig        :std_logic_vector(15 downto 0);
signal	addr_sig      :std_logic_vector( 12 downto 0);
------------------------------------------------------


------------------------------------------------------
--Control signals
------------------------------------------------------
signal	ckdiv_cnt_sig      :std_logic_vector(15 downto 0);
signal	cntr_sig      :std_logic_vector( 15 downto 0);
signal	cntr_carry_sig      :std_logic;

signal	rd_flag_sig      :std_logic;
signal	wr_flag_sig      :std_logic;
signal	rd_strobe_sig      :std_logic;
signal	wr_strobe_sig      :std_logic;
signal	rd_posedge_sig      :std_logic;
signal	wr_posedge_sig      :std_logic;


signal	cnt_flag_sig      :std_logic_vector( 1 downto 0);
signal	ini_strobe_sig      :std_logic;
signal	ini_posedge_sig      :std_logic;

------------------------------------------------------

--********************************************************************************************






--********************************************************************************************
--	Attributes
--********************************************************************************************



	signal	phy_inicnt_sig	:std_logic_vector ( MSB_CNT downto 0);
	signal	phy_iniflag_sig	:std_logic_vector ( 3 downto 0);



signal	sm_phyaddr_sig		:	std_logic_vector(4 downto 0);
signal	sm_regaddr_sig		:	std_logic_vector(4 downto 0);
signal	next_sm_phyaddr_sig		:	std_logic_vector(4 downto 0);
signal	next_sm_regaddr_sig		:	std_logic_vector(4 downto 0);




signal	sm_wrdata_sig		:	std_logic_vector(15 downto 0);
signal	next_sm_wrdata_sig		:	std_logic_vector(15 downto 0);

signal	sm_busy_sig		:	std_logic;
signal	sm_wrflag_sig		:	std_logic;
signal	next_sm_busy_sig		:	std_logic;
signal	next_sm_wrflag_sig		:	std_logic;



signal	if_busy_sig		:	std_logic;
signal	if_busypl_sig		:	std_logic_vector(1 downto 0);


signal	sm_iniflag_sig		:	std_logic;
signal	next_sm_iniflag_sig		:	std_logic;



signal	phy_addr_sig		:	std_logic_vector(4 downto 0);
signal	reg_addr_sig		:	std_logic_vector(4 downto 0);

signal	wr_data_sig		:	std_logic_vector(15 downto 0);

signal	i2c_state_sig		:	state_type;
signal	next_i2c_state_sig		:	state_type;
signal phy_reset_l_sig	:std_logic;
--********************************************************************************************



























--********************************************************************************************
--	Architectural Statements
--********************************************************************************************

begin
--==============================================================================================
-- Map ports to sigs
--==============================================================================================
	reset_sig <= reset;
	clock_sig <= clock;
	ckdiv_cnt_sig <= ckdiv_cnt;


	rd_flag_sig <=rd_flag;
	wr_flag_sig <=wr_flag;
	phy_addr_sig <=phy_addr;
	reg_addr_sig <=reg_addr;

	wr_data_sig <= wrdata_in;
	rddata_out <= rd_data_sig;


	busy <= busy_sig;

	phy_reset_l <=phy_reset_l_sig;

------------------------------------------------------------------------------------------------










--==============================================================================================
--Delay from end of reset for 1.2 ms min then init the phy interface.
--1.2 ms at 80 MHz = 1e6 so 20 bits at least plus margin
--Once complete, restore external control of the serial interface
-- reset must be held low for a min of 150 us= 12000 (0x=2ee0) counts min at 80 MHz- us 0x3000
--==============================================================================================
process(reset_sig, clock_sig)
begin
	if reset_sig = '1' then
		phy_inicnt_sig <= (others=> '0');
		phy_reset_l_sig <='0';
	elsif rising_edge(clock_sig) then

		if phy_inicnt_sig(13 downto 12) ="11" then
			phy_reset_l_sig <= '1';
		end if;

		if phy_inicnt_sig(MSB_CNT) ='0' then
			phy_inicnt_sig <= phy_inicnt_sig + '1';
		end if;
		cnt_flag_sig(0)<=phy_inicnt_sig(MSB_CNT);
		cnt_flag_sig(1)<=cnt_flag_sig(0);
	end if;
end process;
------------------------------------------------------------------------------------------------





--==============================================================================================
--Mux the control signals
--==============================================================================================
process(reset_sig, clock_sig)
begin
	if reset_sig = '1' then
		busy_sig <='1';
		if_phyaddr_sig <= PHY0_ADDR;
		if_regaddr_sig <= REG0_ADDR;
		if_wrdata_sig <=PWDN_CODE;
		if_rd_flag_sig <= '0';
		if_wr_flag_sig <= '0';
	elsif rising_edge(clock_sig) then
		if sm_busy_sig ='1' then
			busy_sig <='1';
			if_phyaddr_sig <= sm_phyaddr_sig;
			if_regaddr_sig <= sm_regaddr_sig;
			if_wrdata_sig <=sm_wrdata_sig;
			if_rd_flag_sig <= '0';
			if_wr_flag_sig <= sm_wrflag_sig;
		else
			busy_sig <=if_busy_sig;
			if_phyaddr_sig <= phy_addr_sig;
			if_regaddr_sig <= reg_addr_sig;
			if_wrdata_sig <=wr_data_sig;
			if_rd_flag_sig <= rd_flag_sig;
			if_wr_flag_sig <= wr_flag_sig;
		end if;
	end if;
end process;
------------------------------------------------------------------------------------------------







--==============================================================================================
-- Instatiate the serial interface
--==============================================================================================
physerif:phy_i2c
port map
(
		--Host controls
		reset		  =>reset_sig,
		clock		  =>clock_sig,
		ckdiv_cnt	=>ckdiv_cnt_sig,

		rd_flag	  =>if_rd_flag_sig,
		wr_flag	  =>if_wr_flag_sig,
		ini_flag	=>sm_iniflag_sig,

		busy		=>if_busy_sig,

		--	Params for I2C transfer
		phy_addr		=>if_phyaddr_sig,
		reg_addr		=>if_regaddr_sig,

		wrdata_in		=>if_wrdata_sig,
		rddata_out	=>rd_data_sig,
		--I2C signals
		i2c_clock	=>i2c_clock,
		i2c_data  =>i2c_data
	);
------------------------------------------------------------------------------------------------















--==============================================================================================
--Pipeline the busy signal for SM use
--==============================================================================================
process(reset_sig, clock_sig)
begin
	if reset_sig = '1' then
		if_busypl_sig <= "00";
	elsif rising_edge(clock_sig) then
		if_busypl_sig(0) <=if_busy_sig;
		if_busypl_sig(1) <=if_busypl_sig(0);
	end if;
end process;
------------------------------------------------------------------------------------------------













--==============================================================================================
-- default for i2c data out is high on the bus
-- default for i2c clock is high on the bus
-- default for i2c dirn is master(FPGA or CPLD) driving
-- i2c data in is an slv
--==============================================================================================
state_adv:	process (clock_sig,reset_sig)
begin
	if reset_sig = '1' then
		sm_iniflag_sig<= '0';
		sm_wrflag_sig<= '0';
		sm_regaddr_sig <= (others =>'0');
		sm_phyaddr_sig <= (others =>'0');
		sm_wrdata_sig <= (others =>'0');
		sm_busy_sig <= '1';
		--state variable
		i2c_state_sig <= i2c_idle;

	elsif rising_edge(clock_sig) then
		sm_iniflag_sig <= next_sm_iniflag_sig;

		sm_wrflag_sig <= next_sm_wrflag_sig;
		sm_regaddr_sig <= next_sm_regaddr_sig;
		sm_phyaddr_sig <= next_sm_phyaddr_sig;
		sm_wrdata_sig <= next_sm_wrdata_sig;
		sm_busy_sig <= next_sm_busy_sig;
		--state variable
		i2c_state_sig <= next_i2c_state_sig;
	end if;
end process;
------------------------------------------------------------------------------------------------






--==============================================================================================
-- State machine
--==============================================================================================
state_mux:	process (i2c_state_sig
					)
begin
	case i2c_state_sig is

		------------------------------------------------
		--Wait for end of reset delay
		------------------------------------------------
		when i2c_idle =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';

			if  cnt_flag_sig="01" then
				next_i2c_state_sig <=i2c_init;
			else
				next_i2c_state_sig <=i2c_idle;
			end if;




		------------------------------------------------
		--Trigger the initialisation sequence for the serial if
		------------------------------------------------
		when i2c_init =>	-- send command
			next_sm_iniflag_sig <= '1';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			next_i2c_state_sig <=i2c_wait0;


		------------------------------------------------
		--Wait for falling edge of busy from i/f
		------------------------------------------------
		when i2c_wait0 =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			if  if_busypl_sig="10" then
				next_i2c_state_sig <=i2c_pwdn1;
			else
			next_i2c_state_sig <=i2c_wait0;
			end if;




		------------------------------------------------
		-- Write the PHY0 power down code
		-- reg 0, value 0x0800
		------------------------------------------------
		when i2c_pwdn1 =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '1';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			next_i2c_state_sig <=i2c_wait1;



		------------------------------------------------
		--Wait for falling edge of busy from i/f
		------------------------------------------------
		when i2c_wait1 =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			if  if_busypl_sig="10" then
				next_i2c_state_sig <=i2c_pwdn2;
			else
			next_i2c_state_sig <=i2c_wait1;
			end if;



		------------------------------------------------
		-- Write the PHY1 power down code
		-- reg 0, value 0x0800
		------------------------------------------------
		when i2c_pwdn2 =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '1';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY1_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			next_i2c_state_sig <=i2c_wait2;



		------------------------------------------------
		--Wait for falling edge of busy from i/f
		------------------------------------------------
		when i2c_wait2 =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY1_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '1';
			if  if_busypl_sig="10" then
				next_i2c_state_sig <=i2c_led1;
			else
			next_i2c_state_sig <=i2c_wait2;
			end if;



		------------------------------------------------
		-- Set the green LED
		-- reg 0x13, value 0x0800
		------------------------------------------------
		when i2c_led1 =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '1';
			next_sm_regaddr_sig <= REG13_ADDR;
			next_sm_phyaddr_sig <= PHY1_ADDR;
			next_sm_wrdata_sig <= LED_CODE;

			next_sm_busy_sig <= '1';
			next_i2c_state_sig <=i2c_wait3;

		------------------------------------------------
		--Wait for falling edge of busy from i/f
		------------------------------------------------
		when i2c_wait3 =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG13_ADDR;
			next_sm_phyaddr_sig <= PHY1_ADDR;
			next_sm_wrdata_sig <= LED_CODE;

			next_sm_busy_sig <= '1';
			if  if_busypl_sig="10" then
				next_i2c_state_sig <=i2c_led2;
			else
				next_i2c_state_sig <=i2c_wait3;
			end if;


		------------------------------------------------
		-- Write the PHY1 power down code
		--
		------------------------------------------------
		when i2c_led2 =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '1';
			next_sm_regaddr_sig <= REG13_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= LED_CODE;

			next_sm_busy_sig <= '1';
			next_i2c_state_sig <=i2c_wait4;




		------------------------------------------------
		--Wait for falling edge of busy from i/f
		------------------------------------------------
		when i2c_wait4 =>	-- wait for command
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG13_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= LED_CODE;

			next_sm_busy_sig <= '1';
			if  if_busypl_sig="10" then
				next_i2c_state_sig <=i2c_stop;
			else
				next_i2c_state_sig <=i2c_wait4;
			end if;



		------------------------------------------------
		-- rd/wr complete, clock is low on entry
		-- stop = Z data followed by clock high
		------------------------------------------------
		when i2c_stop =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '0';
			next_i2c_state_sig <=i2c_stop;

		------------------------------------------------
		--Catchall
		------------------------------------------------
		when others =>
			next_sm_iniflag_sig <= '0';

			next_sm_wrflag_sig <= '0';
			next_sm_regaddr_sig <= REG0_ADDR;
			next_sm_phyaddr_sig <= PHY0_ADDR;
			next_sm_wrdata_sig <= PWDN_CODE;

			next_sm_busy_sig <= '0';
			next_i2c_state_sig <=i2c_stop;

	end case;
end process;

------------------------------------------------------------------------------------------------






end; -- architecture  i2c
--********************************************************************************************