OpenCores
URL https://opencores.org/ocsvn/opb_usblite/opb_usblite/trunk

Subversion Repositories opb_usblite

[/] [opb_usblite/] [trunk/] [pcores/] [opb_usblite_v1_00_a/] [hdl/] [vhdl/] [usb_init.vhdl] - Rev 2

Compare with Previous | Blame | View Log

--
--  USB 2.0 Initialization, handshake and reset detection.
--
--  This entity provides the following functions:
--
--    * USB bus attachment: At powerup and after a RESET signal, switch to
--      non-driving mode, wait for 17 ms, then attach to the USB bus. This
--      should ensure that the host notices our reattachment and initiates
--      a reset procedure.
--
--    * High speed handshake (if HSSUPPORT enabled): attempt to enter
--      high speed mode after a bus reset.
--
--    * Monitor the linestate for reset and/or suspend signalling.
--
--  The low-level interface connects to an UTMI compliant USB PHY such as
--  the SMSC GT3200. The UTMI interface must be configured for 60 MHz operation
--  with an 8-bit data bus.
--
 
library ieee;
use ieee.std_logic_1164.all, ieee.numeric_std.all;
 
entity usb_init is
 
    generic (
 
        -- Support high speed mode.
        HSSUPPORT : boolean := false );
 
    port (
 
        -- 60 MHz UTMI clock.
        CLK :           in std_logic;
 
        -- Synchronous reset; triggers detach and reattach to the USB bus.
        RESET :         in std_logic;
 
        -- High for one clock if a reset signal is detected on the USB bus.
        I_USBRST :      out std_logic;
 
        -- High when attached to the host in high speed mode.
        I_HIGHSPEED :   out std_logic;
 
        -- High when suspended.
        -- Reset of this signal is asynchronous.
        -- This signal may be used to drive (inverted) the UTMI SuspendM pin.
        I_SUSPEND :     out std_logic;
 
        -- High to tell usb_packet that it must drive a continuous K state.
        P_CHIRPK :      out std_logic;
 
        -- Connect to the UTMI Reset signal.
        PHY_RESET :     out std_logic;
 
        -- Connect to the UTMI LineState signal.
        PHY_LINESTATE : in std_logic_vector(1 downto 0);
 
        -- Cconnect to the UTMI OpMode signal.
        PHY_OPMODE :    out std_logic_vector(1 downto 0);
 
        -- Connect to the UTMI XcvrSelect signal (0 = high speed, 1 = full speed).
        PHY_XCVRSELECT : out std_logic;
 
        -- Connect to the UTMI TermSelect signal (0 = high speed, 1 = full speed).
        PHY_TERMSELECT : out std_logic );
 
end entity usb_init;
 
architecture usb_init_arch of usb_init is
 
    -- Time from bus idle until device suspend (3 ms).
    constant TIME_SUSPEND : unsigned(19 downto 0) := to_unsigned(180000, 20);
 
    -- Time from start of SE0 until detection of reset signal (2.5 us + 10%).
    constant TIME_RESET :   unsigned(7 downto 0)  := to_unsigned(165, 8);
 
    -- Time to wait for good SE0 when waking up from suspend (6 ms).
    constant TIME_SUSPRST:  unsigned(19 downto 0) := to_unsigned(360000, 20);
 
    -- Duration of chirp K from device during high speed detection (1 ms + 10%).
    constant TIME_CHIRPK :  unsigned(19 downto 0) := to_unsigned(66000, 20);
 
    -- Minimum duration of chirp J/K during high speed detection (2.5 us + 10%).
    constant TIME_FILT :    unsigned(7 downto 0)  := to_unsigned(165, 8);
 
    -- Time to wait for chirp until giving up (1.1 ms).
    constant TIME_WTFS :    unsigned(19 downto 0) := to_unsigned(66000, 20);
 
    -- Time to wait after reverting to full-speed before sampling the bus (100 us).
    constant TIME_WTRSTHS : unsigned(19 downto 0) := to_unsigned(6000, 20);
 
    -- State machine
    type t_state is (
        ST_INIT, ST_FSRESET, ST_FULLSPEED, ST_SUSPEND, ST_SUSPRESET,
        ST_SENDCHIRP, ST_RECVCHIRP, ST_HIGHSPEED, ST_HSREVERT );
    signal s_state :        t_state := ST_INIT;
 
    -- Timers.
    signal s_timer1 :       unsigned(7 downto 0);
    signal s_timer2 :       unsigned(19 downto 0) := to_unsigned(0, 20);
 
    -- Count J/K chirps.
    signal s_chirpcnt :     unsigned(2 downto 0);
 
    -- High if the device is operating in high speed (or suspended from high speed).
    signal s_highspeed :    std_logic := '0';
 
    -- High if the device is currently suspended.
    -- Reset of this signal is asynchronous.
    signal s_suspend :      std_logic := '0';
 
    -- Input registers.
    signal s_linestate :    std_logic_vector(1 downto 0);
 
    -- Output registers.
    signal s_reset :        std_logic := '1';
    signal s_opmode :       std_logic_vector(1 downto 0) := "01";
    signal s_xcvrselect :   std_logic := '1';
    signal s_termselect :   std_logic := '1';
    signal s_chirpk :       std_logic := '0';
 
begin
 
    I_USBRST    <= s_reset;
    I_HIGHSPEED <= s_highspeed;
    I_SUSPEND   <= s_suspend;
    P_CHIRPK    <= s_chirpk;
    PHY_RESET   <= s_reset;
    PHY_OPMODE  <= s_opmode;
    PHY_XCVRSELECT <= s_xcvrselect;
    PHY_TERMSELECT <= s_termselect;
 
    -- Synchronous process.
    process is
        variable v_clrtimer1 : std_logic;
        variable v_clrtimer2 : std_logic;
    begin
	wait until rising_edge(CLK);
 
        -- By default, do not clear the timers.
        v_clrtimer1 := '0';
        v_clrtimer2 := '0';
 
	-- Register linestate input.
	s_linestate <= PHY_LINESTATE;
 
        -- Default assignments to registers.
        s_reset     <= '0';
        s_chirpk    <= '0';
 
        if RESET = '1' then
 
            -- Reset PHY.
            s_reset      <= '1';
	    s_opmode     <= "01";
            s_xcvrselect <= '1';
            s_termselect <= '1';
 
            -- Go to ST_INIT state and wait until bus attachment.
            v_clrtimer1  := '1';
            v_clrtimer2  := '1';
            s_highspeed  <= '0';
            s_state      <= ST_INIT;
 
	else
 
            case s_state is
 
                when ST_INIT =>
                    -- Wait before attaching to bus.
                    s_opmode     <= "01";   -- non-driving
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    v_clrtimer1  := '1';
                    if s_timer2 = to_unsigned(0, s_timer2'length) - 1 then
                        -- Timer2 overflows after ~ 17 ms; attach to bus.
                        v_clrtimer2 := '1';
                        s_state     <= ST_FULLSPEED;
                    end if;
 
                when ST_FSRESET =>
                    -- Waiting for end of reset before full speed operation.
                    s_highspeed  <= '0';
                    s_opmode     <= "00";   -- normal
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    v_clrtimer1  := '1';
                    v_clrtimer2  := '1';
                    if s_linestate /= "00" then
                        -- Reset signal ended.
                        s_state     <= ST_FULLSPEED;
                    end if;
 
                when ST_FULLSPEED =>
                    -- Operating in full speed.
                    s_highspeed  <= '0';
                    s_opmode     <= "00";   -- normal
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    if s_linestate /= "00" then
                        -- Bus not in SE0 state; clear reset timer.
                        v_clrtimer1 := '1';
                    end if;
                    if s_linestate /= "01" then
                        -- Bus not in J state; clear suspend timer.
                        v_clrtimer2 := '1';
                    end if;
                    if s_timer1 = TIME_RESET then
                        -- Bus has been in SE0 state for TIME_RESET;
                        -- this is a reset signal.
                        s_reset     <= '1';
                        if HSSUPPORT then
                            s_state     <= ST_SENDCHIRP;
                        else
                            s_state     <= ST_FSRESET;
                        end if;
                    elsif s_timer2 = TIME_SUSPEND then
                        -- Bus has been idle for TIME_SUSPEND;
                        -- go to suspend state.
                        s_state     <= ST_SUSPEND;
                    end if;
 
                when ST_SUSPEND =>
                    -- Suspended; waiting for resume signal.
                    -- Possibly our clock will be disabled; wake up
                    -- is initiated by the asynchronous reset of s_suspend.
                    s_opmode     <= "00";   -- normal   
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    v_clrtimer1  := '1';
                    v_clrtimer2  := '1';
                    if s_linestate /= "01" then
                        -- Bus not in J state; resume.
                        if HSSUPPORT and s_highspeed = '1' then
                            -- High speed resume protocol.
                            if s_linestate = "10" then
                                -- Bus in K state; resume to high speed.
                                s_state     <= ST_HIGHSPEED;
                            elsif s_linestate = "00" then
                                -- Bus in SE0 state; start reset detection.
                                s_state     <= ST_SUSPRESET;
                            end if;
                        else
                            -- Resume to full speed.
                            s_state     <= ST_FULLSPEED;
                        end if;
                    end if;
 
                when ST_SUSPRESET =>
                    -- Wake up in SE0 state; wait for proper reset signal.
                    s_opmode     <= "00";   -- normal   
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    if s_linestate /= "00" then
                        -- Bus not in SE0 state; clear reset timer.
                        v_clrtimer1 := '1';
                    end if;
                    if s_timer1 = TIME_RESET then
                        -- Bus has been in SE0 state for TIME_RESET;
                        -- this is a reset signal.
                        s_reset     <= '1';
                        v_clrtimer2 := '1';
                        s_state     <= ST_SENDCHIRP;
                    end if;
                    if s_timer2 = TIME_SUSPRST then
                        -- Still no proper reset signal; go back to sleep.
                        s_state     <= ST_SUSPEND;
                    end if;
 
                when ST_SENDCHIRP =>
                    -- Sending chirp K for a duration of TIME_CHIRPK.
                    s_highspeed  <= '0';
                    s_opmode     <= "10";   -- disable bit stuffing
                    s_xcvrselect <= '0';    -- high speed
                    s_termselect <= '1';    -- full speed
                    s_chirpk     <= '1';    -- send chirp K
                    v_clrtimer1  := '1';
                    if s_timer2 = TIME_CHIRPK then
                        -- end of chirp K
                        v_clrtimer2 := '1';
                        s_chirpcnt  <= "000";
                        s_state     <= ST_RECVCHIRP;
                    end if;
 
                when ST_RECVCHIRP =>
                    -- Waiting for K-J-K-J-K-J chirps.
                    -- Note: DO NOT switch Opmode to normal yet; there
                    -- may be pending bits in the transmission buffer.
                    s_opmode     <= "10";   -- disable bit stuffing
                    s_xcvrselect <= '0';    -- high speed
                    s_termselect <= '1';    -- full speed
                    if ( s_chirpcnt(0) = '0' and s_linestate /= "10" ) or
                       ( s_chirpcnt(0) = '1' and s_linestate /= "01" ) then
                        -- Not the linestate we want.
                        v_clrtimer1 := '1';
                    end if;
                    if s_timer2 = TIME_WTFS then
                        -- High speed detection failed; go to full speed.
                        v_clrtimer1 := '1';
                        v_clrtimer2 := '1';
                        s_state     <= ST_FSRESET;
                    elsif s_timer1 = TIME_FILT then
                        -- We got the chirp we wanted.
                        if s_chirpcnt = 5 then
                            -- This was the last chirp;
                            -- we got a successful high speed handshake.
                            v_clrtimer2 := '1';
                            s_state     <= ST_HIGHSPEED;
                        end if;
                        s_chirpcnt  <= s_chirpcnt + 1;
                        v_clrtimer1 := '1';
                    end if;
 
                when ST_HIGHSPEED =>
                    -- Operating in high speed.
                    s_highspeed  <= '1';
                    s_opmode     <= "00";   -- normal
                    s_xcvrselect <= '0';    -- high speed
                    s_termselect <= '0';    -- high speed
                    if s_linestate /= "00" then
                        -- Bus not idle; clear revert timer.
                        v_clrtimer2 := '1';
                    end if;
                    if s_timer2 = TIME_SUSPEND then
                        -- Bus has been idle for TIME_SUSPEND;
                        -- revert to full speed.
                        v_clrtimer2 := '1';
                        s_state     <= ST_HSREVERT;
                    end if;
 
                when ST_HSREVERT =>
                    -- Revert to full speed and wait for 100 us.
                    s_opmode     <= "00";   -- normal
                    s_xcvrselect <= '1';    -- full speed
                    s_termselect <= '1';    -- full speed
                    if s_timer2 = TIME_WTRSTHS then
                        v_clrtimer2 := '1';
                        if s_linestate = "00" then
                            -- Reset from high speed.
                            s_reset     <= '1';
                            s_state     <= ST_SENDCHIRP;
                        else
                            -- Suspend from high speed.
                            s_state     <= ST_SUSPEND;
                        end if;
                    end if;
 
            end case;
 
	end if;
 
        -- Increment or clear timer1.
        if v_clrtimer1 = '1' then
            s_timer1 <= to_unsigned(0, s_timer1'length);
        else
            s_timer1 <= s_timer1 + 1;
        end if;
 
        -- Increment or clear timer2.
        if v_clrtimer2 = '1' then
            s_timer2 <= to_unsigned(0, s_timer2'length);
        else
            s_timer2 <= s_timer2 + 1;
        end if;
 
    end process;
 
    -- Drive the s_suspend flipflop (synchronous set, asynchronous reset).
    process (CLK, PHY_LINESTATE) is
    begin
        if PHY_LINESTATE /= "01" then
            -- The bus is not in full speed idle state;
            -- reset the s_suspend flipflop.
            s_suspend   <= '0';
        elsif rising_edge(CLK) then
            if s_state = ST_SUSPEND then
                -- Bus is idle and FSM is in suspend state;
                -- enable the s_suspend flipflop.
                s_suspend   <= '1';
            end if;
        end if;
    end process;
 
end architecture usb_init_arch;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.