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.
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:
- 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:
- 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
Aún no hay comentarios.