Tech Articles

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.

 

The first: Universal Serial Bus Specification Revision 2.0 that can be obtained from http://www.usb.org/developers/docs/usb20_docs/

 

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

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

 

Since we later discuss a memory stick so this article outlines a command used in this article.

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:

 

 

Figure 1 TXCMD register write

       

And the following a read from a register:

 

 

Figure 2 Register Read

 

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 Payload data(5:0)

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.

RegRead

11b

101111b

(EXTR)

 

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

 

 

XXXXXXb

(REGR)

 

 

 

Register read command with 6-bit immediate address.

 

 

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.

 

 

Receive Command Byte (RX CMD)

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

 

 

 

 

Figure 3- ULPI signals after reset

 

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.

 

The peripheral must start as a FS device by pulling DP high through an internal resister controlled by FUNC_CTRL register. First we must disable OTG features by writing x”00” to the OTG_CTRL (x”0a) register.  A TXCMD byte of x”8a” is sent then a data byte of x”00” as per Figure 1.

 

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.

 

 

Figure 4 High Speed Initialisation and handshake

 

 

 

 

 

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.

 

 

Figure 5 Receiving data from Host (DIR initially low)

 

 

Figure 6 Receiving data from Host (DIR already high)

 

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

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 01 00 00 40 00 DD 94

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4b 12 01 00 02 00 00 00 40 44 86 0b 80 00 01 01 02 03 01 38 e6

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

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 -> function

transaction

IN

“1001” (x”9”)

Address + endpoint number in function -> host

transaction

SOF

“0101” (x”5”)

Start of frame marker and frame number

SETUP

“1101” (x”d”)

Address + endpoint number in host -> function

transaction 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/control

endpoint (see Section 8.5.1)

Reserved

“0000” (x”0”)

Reserved PID

Table 1 : Packet Identifier types

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:

  1. 1When there has been no activity on either D+ or D- lines, the peripheral must leave the High Speed state and enter the Fast Speed state with an active pullup on the D+ signal by writing x”45” to FUNC_CTRL (x”04”) register. 

  2. 2If after 500µs the Linestate[1:0] is “00” then the host is applying a reset to the peripheral and continue as stage 3 in the initialisation process.  Note: if the line is anything other than “00” then the peripheral should be placed in Suspend mode. 

 

 

 

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:

  1. 1SetAddress 

  2. 2GetDescriptor (Device) 

  3. 3GetDescriptor (Configuration) 

  4. 4GetDescriptor (String Language Ids) 

  5. 5GetDescriptor (String 3) 

  6. 6SetConfiguration 

 

 

Transaction

Host

 

Device

 

Set Address

Setup transaction

Setup

 

 

2D 00 10

Data0

 

 

C3 00 05 01 00 00 00 00 00 EB 25

 

 

ACK

42

IN transaction

IN

 

 

69 00 10

 

 

DATA1

4B 00 00

ACK

 

 

D2

Get Descriptor (Device)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 01 00 00 12 00 E0 F4

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 12 01 00 02 00 00 00 40 44 86 0B 80 00 01 01 02 03 01 38 E6

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (Config 1)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 02 00 00 FF 00 E9 A4

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

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

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

D2

Get Descriptor (String 3 -1)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 03 03 09 04 FF 00 96 0A

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

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

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (String Language IDs)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 03 00 00 FF 00 D4 64

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 04 03 09 04 78

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (String 2)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 02 03 09 04 FF 00 97 DB

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

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

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (Device)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 01 00 00 12 00 E0 F4

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 12 01 00 02 00 00 00 40 44 86 0B 80 00 01 01 02 03 01 38 E6

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (Config 2)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 02 00 00 09 00 AE 04

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 09 02 20 00 01 01 00 80 FA E2 FB

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

D2

Get Descriptor (Config 3)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 02 00 00 20 00 B1 94

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

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

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

D2

Get Descriptor (String Language IDs 2)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 03 00 00 02 00 94 F4

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 04 03 BC 8E

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (String Language IDs 3)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 00 03 00 00 04 00 97 54

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 04 03 09 04 09 78

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (String 3 - 2)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 03 03 09 04 02 00 D6 9A

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 22 03 A6 EE

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Get Descriptor (String 3 - 3)

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 80 06 03 03 09 04 22 00 CF 5A

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

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

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

42

Set Configuration

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 00 09 01 00 00 00 00 00 27 25

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 00 00

ACK

 

 

D2

Get Max LUN

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 A1 FE 00 00 00 00 01 00 6A 1F

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 00 40 BF

ACK

 

 

D2

OUT transaction

OUT

 

 

E1 01 E8

DATA1

 

 

4B 00 00

 

 

ACK

D2

Clear  Feature

Setup transaction

Setup

 

 

2D 01 E8

Data0

 

 

C3 02 01 00 00 82 00 00 00 06 95

 

 

ACK

42

IN transaction

IN

 

 

69 01 E8

 

 

DATA1

4B 00 00

ACK

 

 

D2

 

 

 

 

  1. 1.SetAddress 

 

    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