Back to Home

USB 1.0 Controller on SpinalHDL: Implementation

The article describes the implementation of a USB 1.0 host controller on SpinalHDL for RISC-V SoC. Covers physical layer, protocol, HID descriptors, hardware FSM and driver. Testing examples with keyboard, mouse, gamepad.

SpinalHDL USB 1.0: from protocol to FPGA
Advertisement 728x90

# Implementing a USB 1.0 Host Controller in SpinalHDL for RISC-V SoC

Developing a synthesizable system-on-chip based on RISC-V requires integrating modern peripheral interfaces. A USB 1.0 host controller enables connecting HID input devices: keyboards, mice, gamepads. Implementing it in SpinalHDL provides hardware protocol handling without the software compromises of PS/2 or analog joysticks.

The USB physical layer uses a differential pair D+ and D-, along with VBUS and GND lines. The half-duplex transmission mode distinguishes USB from UART: data is sent bit by bit in one direction at a time, with strict host and device role separation.

USB 1.0 Physical Layer

Electrical characteristics define signal levels: the idle state on D+ and D- sets the speed. Low-speed (1.5 Mbps) — D- high, full-speed (12 Mbps) — D+ high. NRZI encoding: signal transition encodes '1', absence encodes '0'. Synchronization via bit stuffing: an inverted bit is inserted after six identical bits.

Google AdInline article slot

Control signals:

  • SE0 (Single Ended Zero): both D+/D- low — for bus reset.
  • J/K states: differential levels for idle and speed.
  • Chirp: K/J exchange to detect hub speed.

Transmission starts with SYNC (8 bits '0'), followed by PID (Packet ID).

USB Protocol: Packets and Transactions

PID defines the packet type:

Google AdInline article slot
  • Tokens: SETUP (control requests), IN (read), OUT (write), SOF (start of frame).
  • Data: DATA0/1 (toggle bits for integrity).
  • Handshake: ACK (acknowledgment), NAK (reject), STALL (error).

Transactions:

  • Control Transfer: SETUP + DATA (optional) + IN/OUT + ACK.
  • Interrupt Transfer: IN/OUT + DATA + ACK — for HID reports.
  • Bulk Transfer: large blocks, with retry.
  • Isochronous: no handshake, for streams.

Checksums: CRC5 for tokens, CRC16 for data. Formulas:

// CRC5 for address/kontsa
crc5_next = crc5_reg ^ data_in;
// Polinom: x^5 + x^2 + 1 (0b001101)

Descriptors and Device Initialization

Descriptors describe the device:

Google AdInline article slot
  • Device Descriptor: bLength=18, bDescriptorType=1, idVendor, idProduct.
  • Configuration Descriptor: bConfigurationValue, maxPower.
  • Interface/Endpoint: bInterfaceClass (HID=3), bEndpointAddress, bmAttributes (interrupt).
  • HID Descriptor: bcdHID, bCountryCode, Report Descriptor.

Initialization:

  • Bus Reset (SE0 >10 μs).
  • GET_DESCRIPTOR (Device).
  • SET_ADDRESS.
  • GET_DESCRIPTOR (Configuration).
  • SET_CONFIGURATION.

For HID, add GET_DESCRIPTOR (Report). Keyboard report example: modifier byte + reserved + 6 keycodes.

Hardware Implementation in SpinalHDL

The controller is built as a hierarchy of finite state machines:

  • USBMain: main FSM, manages the sequence.
  • USBSendSE0: SE0 generation for reset.
  • USBSendShortToken: short tokens (SOF).
  • USBSendLongToken: full tokens (addr+endp).
  • USBSendData: NRZI encoding + bit stuffing.
  • USBReceiver: NRZI decoding, CRC check.

Interfaces:

import spinal.core._
case class USB_IO() extends Bundle {
  val dpp = in Bool()
  val dpn = in Bool()
  val txen = out Bool()
  val txdp = out Bool()
  val txdn = out Bool()
}

Apb3USB10Ctrl integrates into the SoC via APB3. Clocking: 48 MHz for full-speed.

Integration into KarnixSoC and Driver

Connection: USB Type A on the Karna board, signals routed from FPGA. SpinalHDL configuration adds the module to the top level.

C driver for RISC-V:

  • usb10_bus_reset(): SE0 for 20 μs.
  • usb10_in_request(): IN token + DATA1 + ACK.
  • usb10_setup_request(): SETUP + DATA + IN.

Initialization: usb10_init() detects the device, reads descriptors, sets address.

Testing with HID Devices

Application karnix_usb10_test:

  • Gamepad: analog axes, buttons in interrupt endpoint 1.
  • Mouse: X/Y delta, buttons in 4-byte reports.
  • Keyboard: boot protocol, 8-byte reports (modifiers + keys).

Integration into TetRISC-V: replacing PS/2 with USB input.

Key Points:

  • USB 1.0 full-speed (12 Mbps) implemented with FSM without MACRO-IP.
  • SpinalHDL generates RTL for FPGA synthesis.
  • HID boot protocol simplifies drivers for keyboard/mouse.
  • NRZI + bit stuffing require precise timing (48 MHz clk).
  • CRC5/16 verification prevents packet errors.

— Editorial Team

Advertisement 728x90

Read Next