Zurück zur Startseite

USB 1.0 Controller auf SpinalHDL: Implementierung

Der Artikel beschreibt die Implementierung eines USB 1.0 Host-Controllers auf SpinalHDL für RISC-V SoC. Umfasst physische Schicht, Protokoll, HID-Deskriptoren, Hardware-FSM und Treiber. Testbeispiele mit Tastatur, Maus, Gamepad.

SpinalHDL USB 1.0: vom Protokoll zum FPGA
Advertisement 728x90

Implementierung eines USB-1.0-Hostcontrollers in SpinalHDL für RISC-V-SoC

Die Entwicklung eines synthetisierbaren System-on-Chips auf RISC-V-Basis erfordert die Integration moderner Peripherieschnittstellen. Ein USB-1.0-Hostcontroller ermöglicht den Anschluss von HID-Eingabegeräten: Tastaturen, Mäusen, Gamepads. Die Implementierung in SpinalHDL bietet eine Hardware-Protokollbehandlung ohne die Software-Kompromisse von PS/2 oder analogen Joysticks.

Die USB-physische Schicht verwendet ein differentielles Paar D+ und D- sowie die Leitungen VBUS und GND. Der Halb-Duplex-Übertragungsmodus unterscheidet USB von UART: Daten werden bitweise in einer Richtung zur Zeit gesendet, mit strenger Trennung der Host- und Device-Rollen.

USB-1.0-Physische Schicht

Elektrische Kennwerte definieren die Signalebenen: Der Leerlaufzustand auf D+ und D- legt die Geschwindigkeit fest. Low-Speed (1,5 Mbit/s) — D- hoch, Full-Speed (12 Mbit/s) — D+ hoch. NRZI-Codierung: Signalübergang kodiert '1', Fehlen kodiert '0'. Synchronisation durch Bit-Stuffing: Nach sechs gleichen Bits wird ein invertiertes Bit eingefügt.

Google AdInline article slot

Steuersignale:

  • SE0 (Single Ended Zero): beide D+/D- niedrig — für Bus-Reset.
  • J/K-Zustände: differentielle Pegel für Leerlauf und Geschwindigkeit.
  • Chirp: K/J-Austausch zur Geschwindigkeitserkennung von Hubs.

Übertragung beginnt mit SYNC (8 Bits '0'), gefolgt von PID (Packet-ID).

USB-Protokoll: Pakete und Transaktionen

PID definiert den Pakettyp:

Google AdInline article slot
  • Tokens: SETUP (Control-Anfragen), IN (Lesen), OUT (Schreiben), SOF (Start of Frame).
  • Data: DATA0/1 (Toggle-Bits für Integrität).
  • Handshake: ACK (Bestätigung), NAK (Ablehnung), STALL (Fehler).

Transaktionen:

  • Control-Transfer: SETUP + DATA (optional) + IN/OUT + ACK.
  • Interrupt-Transfer: IN/OUT + DATA + ACK — für HID-Reports.
  • Bulk-Transfer: große Blöcke, mit Wiederholung.
  • Isochronous-Transfer: kein Handshake, für Streams.

Prüfsummen: CRC5 für Tokens, CRC16 für Daten. Formeln:

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

Deskriptoren und Geräteinitialisierung

Deskriptoren beschreiben das Gerät:

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.

Initialisierung:

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

Für HID zusätzlich GET_DESCRIPTOR (Report). Tastatur-Report-Beispiel: Modifier-Byte + reserved + 6 Keycodes.

Hardware-Implementierung in SpinalHDL

Der Controller ist als Hierarchie endlicher Zustandsmaschinen aufgebaut:

  • USBMain: Haupt-FSM, steuert die Sequenz.
  • USBSendSE0: SE0-Erzeugung für Reset.
  • USBSendShortToken: kurze Tokens (SOF).
  • USBSendLongToken: vollständige Tokens (Addr+Endp).
  • USBSendData: NRZI-Codierung + Bit-Stuffing.
  • USBReceiver: NRZI-Dekodierung, CRC-Prüfung.

Schnittstellen:

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 integriert in den SoC über APB3. Taktung: 48 MHz für Full-Speed.

Integration in KarnixSoC und Treiber

Anschluss: USB Type A auf dem Karna-Board, Signale vom FPGA geroutet. SpinalHDL-Konfiguration fügt das Modul zur Top-Level hinzu.

C-Treiber für RISC-V:

  • usb10_bus_reset(): SE0 für 20 μs.
  • usb10_in_request(): IN-Token + DATA1 + ACK.
  • usb10_setup_request(): SETUP + DATA + IN.

Initialisierung: usb10_init() erkennt das Gerät, liest Deskriptoren, setzt Adresse.

Test mit HID-Geräten

Anwendung karnix_usb10_test:

  • Gamepad: analoge Achsen, Tasten im Interrupt-Endpoint 1.
  • Maus: X/Y-Delta, Tasten in 4-Byte-Reports.
  • Tastatur: Boot-Protokoll, 8-Byte-Reports (Modifier + Tasten).

Integration in TetRISC-V: Ersetzung von PS/2 durch USB-Eingabe.

Wichtige Punkte:

  • USB 1.0 Full-Speed (12 Mbit/s) implementiert mit FSM ohne MACRO-IP.
  • SpinalHDL generiert RTL für FPGA-Synthese.
  • HID Boot-Protokoll vereinfacht Treiber für Tastatur/Maus.
  • NRZI + Bit-Stuffing erfordern präzises Timing (48-MHz-Takt).
  • CRC5/16-Prüfung verhindert Paketfehler.

— Editorial Team

Advertisement 728x90

Weiterlesen