ULPI interface

Tips for creating a FPGA ULPI USB interface.

There are a number of USB PHYs that have a UTMI+ Low Pin Interface (ULPI) interface that are readily interfaced to an FPGA.  Incidentally ULPI is an acronym within an acronym within a further acronym, where UTMI+ stands for USB 2.0 Transceiver Macrocell Interface and USB is short for the ubiquitous Universal Serial Bus.

There are two reference documents that are essential to understanding this interface and its quirks.

And the second: UTMI+ Low Pin Interface Specification, Revision 1.1 from

http://www.ulpi.org/documents.html

USB Mass Storage Class – Bulk Only Transport 1.0 and can be found at

http://www.usb.org/developers/devclass_docs/

This link also outlines other classes.

The USB 2.0 interface is capable of 3 speeds:

HS (High Speed) - 480 Mbps

FS (Full Speed) - 12 Mbps and

LS (Low Speed) - 1.5 Mbps

The use of High Speed and Full Speed is perhaps unfortunate and can catch out the unwary.

It is useful to be reminded that any interface claiming conformance USB 2.0 does not necessarily mean that such an interface automatically is capable of running at High Speed (480 Mbs).  It is merely a refinement of a standard that includes Low, Fast and now High Speed USB interfaces.

The ULPI interface corresponds to the following pins:

 nRESET I CFG I DIR O NXT O STP I CS I DATA[7:0] I/O

The ULPI/USB device must be initialised. We have chosen a TI TUSB1210 where a low signal applied to nRESET will set the internal registers to their default values. nRESET must be applied for a minimum of 200ns.

The PHY has a number of internal registers associated with various modes and interface speeds. We need only worry about two of the registers if we intend to setup the PHY as a peripheral.

The following diagram illustrates a write to a register:

And the following a read from a register:

A TXCMD byte must be sent preceding any data or write to a register according to the table below.

Transmit command byte (TX CMD)

Byte Name

Command Code data(7:6)

Command Description

Special

00b

 000000b (NOOP)

No operation. 00h is the idle value of the data bus. The Link drives NOOP by default.

 XXXXXXb (RSVD)

Reserved command space. Values other than those above will give undefined behaviour.

Transmit

01b

 000000b (NOPID)

Transmit USB data that does not have a PID, such as chirp and resume signalling. The PHY starts transmitting on the USB beginning with the next data byte.

 00XXXXb (PID)

Transmit USB packet. data(3:0) indicates USB packet identifier PID(3:0).

 XXXXXXb (RSVD)

Reserved Command space. Values other than those above will give undefined behaviour.

RegWrite

10b

 101111b (EXTW)

Extended register write command. 8-bit address available in the next cycle.

 XXXXXXb (REGW)

Register write command with 6-bit immediate address.

11b

 101111b (EXTR)

 XXXXXXb (REGR)

When the DIR signal is asserted and the NXT signal stays low a RXCMD byte is received that generally represents the PHY status.  This is useful to determine the state of the D- and D+ lines to determine if the peripheral has been connected to a host.

 data Name Description and Value 1:0 LineState UTMI+ LineState signals. data(0) = LineState(0) (DP)data(1) = LineState(1) (DM) 3:2 Vbus State Encoded Vbus Voltage state Value VBUS Voltage SessEnd SessValid VbusValid 00 VBUS < VB_SESS_END 1 0 0 01 VB_SESS_END ≤ VBUS < VSESS_VLD 0 0 0 10 VSESS_VLD ≤ VBUS < VA_VBUS_VLD X 1 0 11 VA_VBUS_VLD ≤ VBUS X X 1 5:4 RxEvent Encoded UTMI event signals Value RxActive Rx Error HostDisconnect 00 0 0 0 01 1 0 0 11 1 1 0 10 X X 1 6 ID Set to the value of IdGnd (UTMI+ IdDig). Valid 50ms after IdPullup is set to 1b. 7 Alt_int Asserted when a non-USB interrupt occurs. This bit must be set when an unmasked event occurs on any bit in the Carkit Interrupt Latch register. The Link must read the Carkit Interrupt Latch register to determine the source of the interrupt.

These are the signals we should expect after reset has been released on the PHY

One significant aspect of reset is the toggling of DIR and a receipt of a RXCMD byte from the PHY.  Once that is detected then we may move forward. The IDLE state is where the Link places 0x00 onto the Data lines. We use a registered DIR signal (so that it is delayed by one clock) as an enable for the driving of data from the FPGA.

We must then initialise the peripheral.  High-speed capable devices initially attach as full-speed devices where DP is pulled up to Vbus through a 1.5k resistor.

Line State is decoded as follows in LS and FS modes:

 LineState[1:0] DP (D+) DM (D-) State 00 SE0 0 0 USB Reset 01 J (FS idle) 1 0 J State 10 K (LS idle) 0 1 K State 11 SE1 1 1 SE1

Line State is decoded as follows in HS mode:

 LineState[1:0] DP (D+) DM (D-) State 00 SE0 0 0 HS Squelch asserted 01 J 1 0 HS Squelch de-asserted 10 K 0 1 Invalid State 11 SE1 1 1 Invalid State

In HS Chirp state:

 LineState[1:0] DP (D+) DM (D-) State 00 SE0 0 0 HS Squelch asserted 01 J 1 0 HS Squelch de-asserted and HS receiver = 1 10 K 0 1 HS Squelch de-asserted and HS receiver = 0 11 SE1 1 1 Invalid State

The lesser bit LineState[0] represent DP (D+), and LineState[1] represent DM (D-).

The sequence of events:

Apply reset for more than 200ns.  The PHY will pull DIR high to ensure the Link will not drive data lines.

Wait for DIR to go low.

Wait for a RXCMD, ie a toggle of the DIR pin.

Send x”45” to FUNC_CTRL (x”04”) where this sets the peripheral device in the Fast Speed mode by making D+ high and D- low ( LineState “01” – J).

The PHY should respond with a RXCMD showing a LineState of J (“01”, FS Idle).

Attaching peripheral to the host

An outline of the High Speed initialisation and handshake process is shown in Figure 4

1. 1If the peripheral is attached to the Host, or now becomes attached to the Host, the Host should wait 100 ms for a stable LineState of “01” and then drive both D+ and D- low. This is the SE0 level and the PHY should produce a RXCMD to confirm a LineState  SE0 (“00”)..

1. 2In order to signal to the Host the peripheral is capable of High Speed the device must signal a “K” (a LineState of “10”) chirp for a minimum of 1.0ms by writing x”54” to FUNC_CTRL (x”04”), then writing a NOPID TXCMD and data of x”00”. After, say 1.5ms, we drive STP to a “1” for a single clock to end the chirp.

1. 3The Host then sends a sequence of alternating J and K signals and once the peripheral detects these J and K signals it can then set the PHY to receive and transmit High Speed serial data.

1. 4This can be accomplished by writing x”41” to FUNC_CTRL (x”04”).

1. 5We have a peripheral in HS mode.

An excerpt from the UTMI document is below to describe the initialisation process.

#### Hi-Speed Detection Handshake (Chirp)

Hi-Speed Detection Handshake, or Chirp, is shown below though not to scale, and not all RX CMD updates are shown. Bus turnaround cycles are also not shown, and must occur for one cycle after every assertion and de-assertion of dir. The following sequence of events must be followed.

1. FS/LS Detect – The host detects a peripheral attachment as low speed if D- is high and as full speed if D+ is high. If a host detects a low speed peripheral, it does not follow the remainder of this protocol.

2. Host Drives – If a host detects a full speed peripheral, it resets the peripheral by writing to the Function Control register and setting XcvrSelect = 00b (HS) and TermSelect = 0b which drives SE0 on the bus (D+ and D- connected to ground via 45Ω). The host also sets OpMode = 10b for correct chirp transmit and receive11. The start of SE0 is labelled T0. The peripheral PHY asserts dir and informs the Link of the LineState change using an RX CMD.

3. Peripheral Responds – After detecting SE0 for no less than 2.5us, if the peripheral is Hi-Speed capable, the peripheral Link sets XcvrSelect to 00b (HS) and OpMode to 10b (chirp), and follows this immediately with a TX CMD (NOPID), transmitting a chirp K for no less than 1ms. and the chirp K must end it no more than 7ms after reset time T0. If the peripheral is in Low Power Mode, it must wake up its clock within 5.6ms, leaving 200us for the Link to start transmitting the chirp K, and 1.2ms for the chirp K to complete (worst case with 10% slow clock).

4. Host Responds – If the host does not detect the peripheral chirp, it must continue the assertion of SE0 until the end of reset. If the host detects the peripheral chirp K for no less than 2.5us, then no more than 100us after the bus leaves the chirp K state, the host sends a TX CMD (NOPID) with an alternating sequence of chirp K’s and J’s. Each individual chirp K or J must last no less than 40us and no longer than 60us.

5. HS Idle – The peripheral must detect a minimum of chirp K-J-K-J-K-J. Each individual chirp K and J must be detected for at least 2.5us. After seeing that minimum sequence, the peripheral Link sets TermSelect = 0b and OpMode = 00b. The peripheral is now in Hi-Speed mode and sees !squelch (01b) on LineState. When the peripheral sees squelch (10b) on LineState, it knows the host has completed chirp and waits for Hi-Speed USB traffic to begin. After transmitting the chirp sequence, the host changes OpMode to 00b and begins sending USB packets.

We now receive High Speed SOFs every 125us.

The USB 2.0 reference document states in section 9.1.1.3 states “After the device has been powered, it must not respond to any bus transactions until it has received a reset from the bus. After receiving a reset, the device is then addressable at the default address.”  However, if you attach a peripheral to a Windows 7 machine after initialisation to High Speed, you will see a SETUP PID and a Get Descriptor (Device) transaction.  The devices we have seen respond with the full transaction though some start off replying with NAKs.

As already intimated, on a Windows machine a peripheral will receive a SETUP PID as per either of the two diagrams below.  Generally for High Speed it will be the latter.

A convenient USB peripheral is a USB memory stick.  This is a generic no-name device but its Vendor ID gives it away as being a NetCom Technology (HK) Ltd.  For identifying Vendor IDs these can be found at:

http://www.usb.org/developers/tools/

If I connect this device to a host I get the following transaction:

 Transaction Host Direction Device Data Get Descriptor (Device) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 01 00 00 40 00 DD 94 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4b 12 01 00 02 00 00 00 40 44 86 0b 80 00 01 01 02 03 01 38 e6 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42

The PID here is a Packet Identifier and Packet ID should not be confused with Product ID.

A Packet ID is just 4 bits, where the Data[3:0] denotes the packet being sent. Data[7:4] are the complement of this. The first PID sent after connecting the cable should be a Start of Frame (SOF) token and be seen as x”a5”.

 PID Type PID Name PID[3:0] Description Token OUT “0001” (x”1”) Address + endpoint number in host -> functiontransaction IN “1001” (x”9”) Address + endpoint number in function -> hosttransaction SOF “0101” (x”5”) Start of frame marker and frame number SETUP “1101” (x”d”) Address + endpoint number in host -> functiontransaction for setup to a control endpoint Data DATA0 “0011” (x”3”) Data packet PID even DATA1 “1011” (x”b”) Data packet PID odd Handshake ACK “0010” (x”2”) Receiver accepts error free data packet NAK “1010” (x”a”) Rx device cannot accept data or Tx device cannot send data STALL “1110” (x”e”) Endpoint is stalled Special PRE “1100” (x”c”) Host-issued preamble. Enables downstream bus traffic to LS devices. ERR “1100” (x”c”) (Handshake) Split Transaction Error Handshake (reuses PRE value) SPLIT “1000” (x”8”) High-speed Split Transaction Token (see Section 8.4.2) PING “0100” (x”4”) High-speed flow control probe for a bulk/controlendpoint (see Section 8.5.1) Reserved “0000” (x”0”) Reserved PID

It’s worth noting that data is sent LSB first.

 Sync PID Frame No. CRC5 EOP 8 bits 11 bits 5 bits

SOF Packet

SOF packets are sent by the Host every 1 ms on Full Speed links. On High Speed links each 1 ms period is split into 8 microframes and a SOF is sent at the beginning of each microframe.  Each of these microframe SOFs within this 1 ms period will have the same Frame Number.

The Host must now reset the peripheral by stopping any further communication including stop sending any further SOFs.  Where there has been 3.0ms of IDLE state without taffic the device must enter Full Speed Idle mode where the High Speed terminations are removed and the pullup on D- is enabled.

Where the host pulls down both D+ and D- then this is a Reset. Where the Host releases both lines allowing a LineState of “01” then the peripheral is placed in Suspend mode. It is unfortunate that the ULPI reference document makes little mention of the Reset procedure.

The Reset procedure:

We should expect the following transactions from a Scandisk memory stick as per USB Simply Buffered (USB) - Device Enumeration by Shakthi Kannan.

The steps involved in USB device enumeration are as follows:

 Transaction Host Device Set Address Setup transaction Setup $\underset{\to }{}$ 2D 00 10 Data0 $\underset{\to }{}$ C3 00 05 01 00 00 00 00 00 EB 25 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 00 10 $\underset{←}{}$ DATA1 4B 00 00 ACK $\underset{\to }{}$ D2 Get Descriptor (Device) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 01 00 00 12 00 E0 F4 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 12 01 00 02 00 00 00 40 44 86 0B 80 00 01 01 02 03 01 38 E6 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (Config 1) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 02 00 00 FF 00 E9 A4 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 09 02 20 00 01 01 00 80 FA 09 04 00 00 02 08 06 50 00 07 05 82 02 00 02 00 07 05 01 02 00 02 00 8C 69 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK D2 Get Descriptor (String 3 -1) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 03 03 09 04 FF 00 96 0A $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 22 03 31 00 30 00 4A 00 32 00 31 00 34 00 30 00 30 00 30 00 30 00 30 00 30 00 33 00 36 00 38 00 42 00 B3 51 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (String Language IDs) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 03 00 00 FF 00 D4 64 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 04 03 09 04 78 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (String 2) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 02 03 09 04 FF 00 97 DB $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 3E 03 55 00 53 00 42 00 20 00 46 00 6C 00 61 00 73 00 68 00 20 00 44 00 69 00 73 00 6B 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20  00 20 00 20 00 20 00 20 00 20 00 3E BB ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (Device) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 01 00 00 12 00 E0 F4 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 12 01 00 02 00 00 00 40 44 86 0B 80 00 01 01 02 03 01 38 E6 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (Config 2) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 02 00 00 09 00 AE 04 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 09 02 20 00 01 01 00 80 FA E2 FB ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK D2 Get Descriptor (Config 3) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 02 00 00 20 00 B1 94 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 09 02 20 00 01 01 00 80 FA 09 04 00 00 02 08 06 50 00 07 05 82 02 00 02 00 07 05 01 02 00 02 00 8C 69 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK D2 Get Descriptor (String Language IDs 2) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 03 00 00 02 00 94 F4 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 04 03 BC 8E ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (String Language IDs 3) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 00 03 00 00 04 00 97 54 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 04 03 09 04 09 78 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (String 3 - 2) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 03 03 09 04 02 00 D6 9A $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 22 03 A6 EE ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Get Descriptor (String 3 - 3) Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 80 06 03 03 09 04 22 00 CF 5A $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 22 03 31 00 30 00 4A 00 32 00 31 00 34 00 30 00 30 00 30 00 30 00 30 00 30 00 33 00 36 00 38 00 42 00 B3 51 ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK 42 Set Configuration Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 00 09 01 00 00 00 00 00 27 25 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 00 00 ACK $\underset{\to }{}$ D2 Get Max LUN Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 A1 FE 00 00 00 00 01 00 6A 1F $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 00 40 BF ACK $\underset{\to }{}$ D2 OUT transaction OUT $\underset{\to }{}$ E1 01 E8 DATA1 $\underset{\to }{}$ 4B 00 00 $\underset{←}{}$ ACK D2 Clear  Feature Setup transaction Setup $\underset{\to }{}$ 2D 01 E8 Data0 $\underset{\to }{}$ C3 02 01 00 00 82 00 00 00 06 95 $\underset{←}{}$ ACK 42 IN transaction IN $\underset{\to }{}$ 69 01 E8 $\underset{←}{}$ DATA1 4B 00 00 ACK $\underset{\to }{}$ D2

1. 1.1.SETUP

The first packet we receive after a reset is an x”2d”, a setup packet of the following format:

 PID (d) !PID(2) Function Address Endpoint CRC 4 4 7 4 5

The first Token packet is “2d 00 10” where the Host provides the device a temporary address of b“000_0000”.

1. 1.2.DATA0

The next packet starts with “c3” indicating a DATA0 packet.

 PID (3) !PID(c) SETUP Data CRC 4