Core USB 2.0 Device Gateware

The LUNA gateware library provides a flexible base USB Device model, which is designed to provide the basis for creating both application-specific and general-purpose USB hardware.

USB devices are created using two core components:

  • A USBDevice instance, which provides hardware that handles low-level USB communications, and which is designed to be applicable to all devices; and
  • One or more endpoint interfaces, which handle high-level USB communications – and provide the logic the tailors the device to its intended application.

The USBDevice communicates with low-level transciever hardware via the FPGA-friendly USB Transceiver Macrocell Interface (UTMI). Translators can be used to transparently adapt the FPGA interface to other common bus formats; including the common ULPI low-pin-count variant of UTMI.

USB 2.0 architecture diagram

The overall architecture of a LUNA USB 2.0 device, highlighting the USBDevice components, their connections to the endpoint interfaces, and optional bus translator.

Conceptual Components

The USBDevice class contains the low-level communications hardware necessary to implement a USB device; including hardware for maintaining device state, detecting events, reading data from the host, and generating responses.

Token Detector

The Token Detector detects token packets from the host; and is responsible for:

  • Detecting start of frame packets, which are used to maintain consistent timing across USB devices.
  • Detecting the start of USB transactions.
  • Identifying the device and endpoint to which each transaction is addressed.

As each USB transaction starts with a token packet; it is implicitly the Token Detector’s responsiblity to notify endpoint interfaces of imminent incoming data (OUT transactions) and requests for data (IN transactions).

Handshake Detector

The Handshake Detector detects handshake packets from the host; and is responsible for identifying the host’s response to packets from the device – indicating whether the host successfully received a packet sent from the device.

Data Packet Receiver

The Data Packet Receiver is responsible for receiving data packets from the device – including the payloads of both OUT and SETUP transactions – and translating them to a simple data stream.

The Data Receiver handles error detection; and thus validates the checksums of each packet using the Data CRC Unit.

Device State Manager

The Device State Manager is responsible for storing global device state – primarily, the device’s current address and configuration. The device state manager accepts changes to the device’s address/configuration from each endpoint interface; and automatically resets the relevant parameters when a USB reset is received.

Handshake Generator

The Handshake Generator provides a simple, strobe-based interface that allows endpoints to easily emit handshake packets – allowing the device to acknowledge packets (ACK), issue stalls (STALL) , and to rate limit communications (NAK/NYET).

Data Packet Transmitter

The Data Packet Generator is responsible for generating outgoing USB packets from simple data streams; including emitting data packet IDs, sending data, and appending data CRCs. This class automatically appends the required data CRC-16s.

Data CRC Unit

The Data CRC Unit is shared among the packet receiver and packet generator; and handles computing the CRC-16 for USB data streams.

Interpacket Timer

The Interpacket Timer is responsible for maintaining maximum and minimum interpacket delays; ensuring that the device can correctly provide bus turnover times; and knows the window in which handshake packets are expected to arrive.

Reset/Suspend Sequencer

The Reset/Suspend Sequencer is responsible for detecing USB reset and suspend events; and where applicable, participating in the USB reset protocol’s high-speed detection handshake.

The sequencer:

  • Detects USB resets; and communicates to the Device State Manager that it should return the device to an un-addressed, un-configured state.
  • Performs the high speed detection handshake, which allows the device to switch to High Speed operation; and thus is necessary for the device to operate at high speed.
  • Manages the high-speed terminations; as part of the reset-handshake and suspend protocols.
  • Detects the periods of inactivity that indicate the device is being suspended; and automatically disengages high-speed terminations while the device is in suspend.

usb2.device Components

Contains the organizing hardware used to add USB Device functionality to your own designs; including the core USBDevice class.

class luna.gateware.usb.usb2.device.USBDevice(*, bus, handle_clocking=True)

Bases: nmigen.hdl.ir.Elaboratable

Core gateware common to all LUNA USB devices.

The USBDevice module contains the low-level communications hardware necessary to implement a USB device; including hardware for maintaining device state, detecting events, reading data from the host, and generating responses.

This class can be instantiated directly, and used to build a USB device, or can be subclassed to create custom device types.

To configure a USBDevice from a CPU or other wishbone master, see USBDeviceController; which can easily be attached using its attach method.

Parameters:
  • bus ([UTMI interface, ULPI Interface]) – The UTMI or ULPI PHY connection to be used for communications.
  • handle_clocking (bool, Optional) – True iff we should attempt to connect up the usb clock domain to the PHY automatically based on the clk signals’s I/O direction. This option may not work for non-simple connections; in which case you will need to connect the clock signal yourself.
connect

Held high to keep the current USB device connected; or held low to disconnect.

Type:Signal(), input
low_speed_only

If high, the device will operate at low speed.

Type:Signal(), input
full_speed_only

If high, the device will be prohibited from operating at high speed.

Type:Signal(), input
frame_number

The current USB frame number.

Type:Signal(11), output
sof_detected

Pulses for one cycle each time a SOF is detected; and thus our frame number has changed.

Type:Signal(), output
# State signals.
suspended

High when the device is in USB suspend. This can be (and by the spec must be) used to trigger the device to enter lower-power states.

Type:Signal(), output
tx_activity_led

Signal that can be used to drive an activity LED for TX.

Type:Signal(), output
rx_activity_led

Signal that can be used to drive an activity LED for RX.

Type:Signal(), output
add_control_endpoint()

Adds a basic control endpoint to the device.

Does not add any request handlers. If you want standard request handlers; add_standard_control_endpoint automatically adds standard request handlers.

Returns:
Return type:Returns the endpoint object for the control endpoint.
add_endpoint(endpoint)

Adds an endpoint interface to the device.

Parameters:endpoint (Elaborateable) – The endpoint interface to be added. Can be any piece of gateware with a EndpointInterface attribute called interface.
add_standard_control_endpoint(descriptors: usb_protocol.emitters.descriptors.standard.DeviceDescriptorCollection)

Adds a control endpoint with standard request handlers to the device.

Parameters:
  • descriptors (DeviceDescriptorCollection) – The descriptors to use for this device.
  • value (Return) –
  • ------------
  • endpoint object created. (The) –

usb2.packet Components

Contains the gatware module necessary to interpret and generate low-level USB packets.

class luna.gateware.usb.usb2.packet.DataCRCInterface

Bases: nmigen.hdl.rec.Record

Record providing an interface to a USB CRC-16 generator.

start

Strobe that indicates that a new CRC computation should be started.

Type:Signal(), input to CRC generator
crc

The current CRC-16 value; updated with each sent or received byte.

Type:Signal(), output from CRC generator
class luna.gateware.usb.usb2.packet.HandshakeExchangeInterface(*, is_detector)

Bases: nmigen.hdl.rec.Record

Record that carries handshakes detected -or- generated between modules.

ack

When connected to a generator, pulsing this strobe will trigger generating of an ACK. When connected to a detector, this strobe will be pulsed when an ACK is detected from the host.

Type:Signal()
nak

When connected to a generator, pulsing this strobe will trigger generating of an NAK. When connected to a detector, this strobe will be pulsed when an NAK is detected from the host.

Type:Signal()
stall

When connected to a generator, pulsing this strobe will trigger generation of a STALL. Unused in a detector, currently.

Type:Signal()
nyet

When connected to a generator, pulsing this strobe will trigger generation of a NYET. Unused in a detector, currently.

Type:Signal()
Parameters:is_detector (bool) – If true, this will be considered an interface to a detector that identifies handshakes. Otherwise, this will be considered an interface to a generator that accepts handshake requests.
class luna.gateware.usb.usb2.packet.InterpacketTimerInterface

Bases: nmigen.hdl.rec.Record

Record providing an interface to our interpacket timer.

See [USB2.0: 7.1.18] and the USBInterpacketTimer gateware for more information.

start

Strobe that indicates when the timer should be started. Usually started at the end of an Rx or Tx event.

Type:Signal(), input to timer
tx_allowed

Strobe that goes high when it’s safe to transmit after an Rx event.

Type:Signal(), output from timer
tx_timeout

Strobe that goes high when the transmit-after-receive window has passed.

Type:Signal(), output from timer
rx_timeout

Strobe that goes high when the receive-after-transmit window has passed.

Type:Signal(), output from timer
attach(*subordinates)

Attaches subordinate interfaces to the given timer interface.

Parameters:subordinates ([InterpacketTimerInterface, Signal]) – Each InterpacketTimerInterface is provided will be fully connected to a given timer interface. Each Signal provided will be interpreted as a timer reset, and added to the list of all resets.
class luna.gateware.usb.usb2.packet.TokenDetectorInterface

Bases: nmigen.hdl.rec.Record

Record providing an interface to a USB token detector.

pid

The Packet ID of the most recent token.

Type:Signal(4), detector output
address

The address associated with the relevant token.

Type:Signal(7), detector output
endpoint

The endpoint indicated by the most recent token.

Type:Signal(4), detector output
new_token

Strobe asserted for a single cycle when a new token packet has been received.

Type:Signal(), detector output
ready_for_response

Strobe asserted for a single cycle one inter-packet delay after a token packet is complete. Indicates when the token packet can be responded to.

Type:Signal(), detector output
frame

The current USB frame number.

Type:Signal(11), detector output
new_frame

Strobe asserted for a single cycle when a new SOF has been received.

Type:Signal(), detector output
is_in

High iff the current token is an IN.

Type:Signal(), detector output
is_out

High iff the current token is an OUT.

Type:Signal(), detector output
is_setup

High iff the current token is a SETUP.

Type:Signal(), detector output
is_ping

High iff the current token is a PING.

Type:Signal(), detector output
class luna.gateware.usb.usb2.packet.USBDataPacketCRC(initial_value=65535)

Bases: nmigen.hdl.ir.Elaboratable

Gateware that computes a running CRC-16.

By default, this module has no connections to the modules that use it.

These are added using add_interface; this module supports an arbitrary number of connection interfaces; see add_interface() for restrictions.

rx_data

Receive data input; can be carried directly from a UTMI interface.

Type:Signal(8), input
rx_valid

Receive validity signal; can be carried directly from a UTMI interface.

Type:Signal(), input
tx_data

Transmit data input; can be carried directly from a UTMI interface.

Type:Signal(8), input
tx_valid

When high, the tx_data input is used to update the CRC.

Type:Signal(), input
Parameters:initial_value ([int, Const]) – The initial value of the CRC shift register; the USB default is used if not provided.
add_interface(interface: luna.gateware.usb.usb2.packet.DataCRCInterface)

Adds an interface to the CRC generator module.

Each interface can reset the CRC; and can read the current CRC value. No arbitration is performed; it’s assumed that no more than one interface will be computing a running CRC at at time.

Parameters:interface (DataCRCInterface) – The interface to be added; accepts control signals from other modules, and brings CRC output to them. This method can be called multiple times to generate multiplpe CRCs.
class luna.gateware.usb.usb2.packet.USBDataPacketDeserializer(*, utmi, max_packet_size=64, create_crc_generator=False)

Bases: nmigen.hdl.ir.Elaboratable

Gateware that captures USB data packet contents and parallelizes them.

data_crc

Connection to the CRC generator.

Type:DataCRCInterface
new_packet

Strobe that pulses high for a single cycle when a new packet is delivered.

Type:Signal(), output
packet_id

The packet ID of the captured PID.

Type:Signal(4), output
packet

Packet data for a the most recently received packet.

Type:Signal(max_packet_size), output
length

The length of the packet data presented on the packet[] output.

Type:Signal(range(0, max_packet_length +1)), output
Parameters:
  • utmi (UTMIInterface, or equivalent) – The UTMI bus to observe.
  • max_packet_size (int) – The maximum packet (payload) size to be deserialized, in bytes.
  • create_crc_generator (bool) – If True, a submodule CRC generator will be created. Excellent for testing.
class luna.gateware.usb.usb2.packet.USBDataPacketGenerator(standalone=False)

Bases: nmigen.hdl.ir.Elaboratable

Module that converts a FIFO-style stream into a USB data packet.

Handles steps such as PID generation and CRC-16 injection.

As a special case, if the stream pulses last (with valid=1) without pulsing first, we’ll send a zero-length packet.

data_pid

The data packet number to use. The potential PIDS are: 0 = DATA0, 1 = DATA1, 2 = DATA2, 3 = MDATA; the interface is designed so that most endpoints can tie the MSb to zero and then perform PID toggling by toggling the LSb.

Type:Signal(2), input
crc

Interface to our data CRC generator.

Type:DataCRCInterface
stream

Stream input for the raw data to be transmitted.

Type:USBInStreamInterface
tx

UTMI-subset transmit interface

Type:UTMITransmitInterface
Parameters:standalone (bool) – If True, this unit will include its internal CRC generator. Perfect for unit testing or debugging.
class luna.gateware.usb.usb2.packet.USBDataPacketReceiver(*, utmi, standalone=False, speed=None)

Bases: nmigen.hdl.ir.Elaboratable

Gateware that converts received USB data packets into a data-stream packets.

It’s important to note that packet payloads are mostly directly carried over from UTMI. Since USB data is received -prior- to its CRC, one cannot know if a packet is valid until after it has been compeltely received. As a result, this interface will generate data of unknown validity, followed by a strobe on either packet_complete or crc_mismatch. The receiving interface must be prepared to handle crc_mismatch by discarding the received data.

data_crc

Connection to the CRC generator.

Type:DataCRCInterface
timer

Connection to our interpacket timer.

Type:InterpacketTimerInterface
stream

Stream that carries captured packet data.

Type:USBOutDataStream, output
active_pid

The PID of the data currently being received.

Type:Signal(4), output
packet_id

The packet ID of the most recently captured PID. Becomes valid simultaneous to a strobe on packet_complete or crc_mismatch.

Type:Signal(4), output
packet_complete

Strobe that pulses high when a new packet is delivered with a valid CRC.

Type:Signal(), output
crc_mismatch

Strobe that pulses high when the given packet has a CRC mismatch; and thus the data received this far should be discarded.

Type:Signal(), output
ready_for_response

Strobe that indicates that an inter-packet delay has passed since packet_complete, and thus we’re now ready to respond with a handshake.

Type:Signal(), output
Parameters:
  • utmi (UTMIInterface, or equivalent) – The UTMI bus to observe.
  • max_packet_size (int) – The maximum packet (payload) size to be deserialized, in bytes.
  • standalone (bool) – Debug value. If True, a submodule CRC generator will be created.
  • speed (USBSpeed) – USBSpeed signal or constant that specifies our speed in standalone mode.
class luna.gateware.usb.usb2.packet.USBHandshakeDetector(*, utmi)

Bases: nmigen.hdl.ir.Elaboratable

Gateware that detects handshake packets.

detected

Strobes that indicate which handshakes we’re detecting.

Type:HandshakeExchangeInterface
Parameters:utmi ([UTMIInterface, UTMITranslator]) – The UTMI interface to listen on.
ACK_PID = 2
NAK_PID = 10
NYET_PID = 6
STALL_PID = 14
class luna.gateware.usb.usb2.packet.USBHandshakeGenerator

Bases: nmigen.hdl.ir.Elaboratable

Module that generates handshake packets, on request.

Attributes:

issue_ack: Signal(), input
Pulsed to generate an ACK handshake packet.
issue_nak: Signal(), input
Pulsed to generate a NAK handshake packet.
issue_stall: Signal(), input
Pulsed to generate a STALL handshake.
tx: UTMITransmitInterface
Interface to the relevant UTMI interface.
class luna.gateware.usb.usb2.packet.USBInterpacketTimer

Bases: nmigen.hdl.ir.Elaboratable

Module that tracks inter-packet timings, enforcing spec-mandated packet gaps.

Ports other than speed are added dynamically via :method:add_interface`.

speed

The device’s current operating speed. Should be a USBSpeed enumeration value – 0 for high, 1 for full, 2 for low.

Type:Signal(2), input
add_interface(interface: luna.gateware.usb.usb2.packet.InterpacketTimerInterface)

Adds a connection to a user of this module.

This module performs no multiplexing; it’s assumed only one interface will be active at a time.

Parameters:interface (InterpacketTimerInterface) – The InterPacketTimer interface to add to our module.
class luna.gateware.usb.usb2.packet.USBTokenDetector(*, utmi, filter_by_address=True)

Bases: nmigen.hdl.ir.Elaboratable

Gateware that parses token packets and generates relevant events.

interface

The interface that contains token detection events, and information about detected tokens.

Type:TokenDetectorInterface
speed

Carries a USBSpeed constant identifying the device’s current operating speed.

Type:Signal(2), input
address

If :parameter:filter_by_address is true, this is an input that filters our event detector so it only reports tokens directed at a given address. If filter_by_address is false, this is an output that contains the address of the most recent token.

Type:Signal(7), input -or- output
Parameters:
  • utmi (UTMIInterface) – The UTMI bus to observe.
  • filter_by_address (bool) – If true, this detector will only report events for the address supplied in the address[] field.
SOF_PID = 5
TOKEN_SUFFIX = 1

usb2.reset Components

Gateware that handles USB bus resets & speed detection.

class luna.gateware.usb.usb2.reset.USBResetSequencer

Bases: nmigen.hdl.ir.Elaboratable

Gateware that detects reset signaling on the USB bus.

low_speed_only

If set, the device will be forced to operate as a low-speed device.

Type:Signal(), input
prevent_high_speed

If set, the device will be prohibited from entering high-speed states; and will thus act like it’s a full speed device (low_speed_only = 0).

Type:Signal(), input
bus_busy

Hold-off signal that indicates that driving the bus should be delayed.

Type:Signal(), input
vbus_connected

Indicates that the device is connected to VBUS. When this is de-asserted, the device will be held in perpetual bus reset, and reset handshaking will be disabled.

Type:Signal(), input
line_state

The UTMI linestate signals; used to read the current state of the USB D+ and D- lines.

Type:Signal(2), input
bus_reset
Strobe; pulses high for one cycle when a bus reset is detected. This signal indicates that the
device should return to unaddressed, unconfigured, and should not longer be in High Speed mode.
Type:Signal(), output
suspended

Held high while the USB device should be in suspend. This technically indicates that the device should drop down to consuming suspend current (<= 2.5mA), but very few devices are compliant with this requirement. Either way, a polite device might reduce its power consumption while in suspend.

Type:Signal(), output
current_speed

A USBSpeed value that indicates the current operating speed. Used both to drive our device’s knowledge of operating speed and to drive our PHY’s speed selection.

Type:Signal(2), output
operating_mode

The current UTMI operating mode. Used to select whether we’re driving the USB bus directly; or whether we’re letting the PHY handle NRZI/bit-stuffing.

Type:Signal(2), output
termination_select

Determines the bus termination mode. In LS/FS, this determines the presence of our presence-detect pull-up. In HS mode, this determines whether the USB high-speed termination is present (0), or whether we’re in chirp mode (1).

Type:Signal(), output, default=1
tx

– Our UTMI transmit interface; used to drive chirp signaling onto the bus.

Type:UTMITransmitInterface, output stream