Volver al inicio

Controlador USB 1.0 en SpinalHDL: Implementación

El artículo describe la implementación de un controlador host USB 1.0 en SpinalHDL para SoC RISC-V. Cubre capa física, protocolo, descriptores HID, FSM de hardware y driver. Ejemplos de pruebas con teclado, ratón, gamepad.

SpinalHDL USB 1.0: del protocolo a FPGA
Advertisement 728x90

Implementación de un controlador host USB 1.0 en SpinalHDL para SoC RISC-V

Desarrollar un system-on-chip sintetizable basado en RISC-V requiere integrar interfaces periféricas modernas. Un controlador host USB 1.0 permite conectar dispositivos de entrada HID: teclados, ratones, mandos. Implementarlo en SpinalHDL proporciona manejo de protocolo en hardware sin los compromisos de software de PS/2 o joysticks analógicos.

La capa física USB utiliza un par diferencial D+ y D-, junto con las líneas VBUS y GND. El modo de transmisión semidúplex distingue al USB del UART: los datos se envían bit a bit en una dirección a la vez, con estricta separación de roles entre host y dispositivo.

Capa física USB 1.0

Las características eléctricas definen los niveles de señal: el estado inactivo en D+ y D- establece la velocidad. Baja velocidad (1.5 Mbps) — D- alto, velocidad completa (12 Mbps) — D+ alto. Codificación NRZI: la transición de señal codifica '1', la ausencia codifica '0'. Sincronización mediante bit stuffing: se inserta un bit invertido después de seis bits idénticos.

Google AdInline article slot

Señales de control:

  • SE0 (Single Ended Zero): ambos D+/D- bajos — para reinicio del bus.
  • Estados J/K: niveles diferenciales para inactivo y velocidad.
  • Chirp: intercambio K/J para detectar velocidad del hub.

La transmisión comienza con SYNC (8 bits '0'), seguido de PID (Packet ID).

Protocolo USB: Paquetes y transacciones

PID define el tipo de paquete:

Google AdInline article slot
  • Tokens: SETUP (solicitudes de control), IN (lectura), OUT (escritura), SOF (inicio de fotograma).
  • Data: DATA0/1 (bits de alternancia para integridad).
  • Handshake: ACK (reconocimiento), NAK (rechazo), STALL (error).

Transacciones:

  • Transferencia de control: SETUP + DATA (opcional) + IN/OUT + ACK.
  • Transferencia de interrupción: IN/OUT + DATA + ACK — para informes HID.
  • Transferencia bulk: bloques grandes, con reintento.
  • Transferencia isócrona: sin handshake, para flujos.

Checksums: CRC5 para tokens, CRC16 para datos. Fórmulas:

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

Descriptores e inicialización del dispositivo

Los descriptores describen el dispositivo:

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.

Inicialización:

  • Reinicio del bus (SE0 >10 μs).
  • GET_DESCRIPTOR (Device).
  • SET_ADDRESS.
  • GET_DESCRIPTOR (Configuration).
  • SET_CONFIGURATION.

Para HID, agregar GET_DESCRIPTOR (Report). Ejemplo de informe de teclado: byte de modificador + reservado + 6 códigos de tecla.

Implementación en hardware con SpinalHDL

El controlador se construye como una jerarquía de máquinas de estados finitos:

  • USBMain: FSM principal, gestiona la secuencia.
  • USBSendSE0: generación de SE0 para reinicio.
  • USBSendShortToken: tokens cortos (SOF).
  • USBSendLongToken: tokens completos (addr+endp).
  • USBSendData: codificación NRZI + bit stuffing.
  • USBReceiver: decodificación NRZI, verificación CRC.

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 se integra en el SoC mediante APB3. Reloj: 48 MHz para velocidad completa.

Integración en KarnixSoC y controlador

Conexión: USB Type A en la placa Karna, señales enrutadas desde FPGA. La configuración de SpinalHDL agrega el módulo al nivel superior.

Controlador en C para RISC-V:

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

Inicialización: usb10_init() detecta el dispositivo, lee descriptores, establece dirección.

Pruebas con dispositivos HID

Aplicación karnix_usb10_test:

  • Mando: ejes analógicos, botones en endpoint de interrupción 1.
  • Ratón: delta X/Y, botones en informes de 4 bytes.
  • Teclado: protocolo boot, informes de 8 bytes (modificadores + teclas).

Integración en TetRISC-V: reemplazando PS/2 con entrada USB.

Puntos clave:

  • USB 1.0 velocidad completa (12 Mbps) implementado con FSM sin MACRO-IP.
  • SpinalHDL genera RTL para síntesis en FPGA.
  • Protocolo boot HID simplifica controladores para teclado/ratón.
  • NRZI + bit stuffing requieren temporización precisa (reloj de 48 MHz).
  • Verificación CRC5/16 previene errores de paquete.

— Editorial Team

Advertisement 728x90

Leer después