RISC-V SoC를 위한 SpinalHDL에서의 USB 1.0 호스트 컨트롤러 구현
RISC-V 기반의 합성 가능한 시스템온칩을 개발하려면 현대적인 주변 인터페이스를 통합해야 합니다. USB 1.0 호스트 컨트롤러는 HID 입력 장치인 키보드, 마우스, 게임패드를 연결할 수 있게 해줍니다. SpinalHDL에서 이를 구현하면 PS/2나 아날로그 조이스틱의 소프트웨어적 타협 없이 하드웨어 수준의 프로토콜 처리가 가능합니다.
USB 물리 계층은 D+와 D-의 차동 쌍과 함께 VBUS 및 GND 선을 사용합니다. 하프 듀플렉스 전송 모드는 USB를 UART와 구분 짓는데, 데이터는 한 방향으로 한 번에 비트 단위로 전송되며 호스트와 디바이스의 역할이 엄격히 분리됩니다.
USB 1.0 물리 계층
전기적 특성은 신호 레벨을 정의하며, D+와 D-의 아이들 상태가 속도를 설정합니다. 저속(1.5 Mbps) — D- high, 고속(12 Mbps) — D+ high. NRZI 인코딩: 신호 전환이 '1'을, 없음이 '0'을 인코딩합니다. 비트 스터핑을 통한 동기화: 6개의 동일한 비트 후 반전 비트를 삽입합니다.
제어 신호:
- SE0 (Single Ended Zero): D+/D- 모두 low — 버스 리셋용.
- J/K 상태: 아이들과 속도를 위한 차동 레벨.
- Chirp: 허브 속도 감지를 위한 K/J 교환.
전송은 SYNC(8비트 '0')로 시작하며, 그 뒤에 PID(Packet ID)가 옵니다.
USB 프로토콜: 패킷과 트랜잭션
PID는 패킷 유형을 정의합니다:
- 토큰: SETUP(제어 요청), IN(읽기), OUT(쓰기), SOF(프레임 시작).
- 데이터: DATA0/1(무결성을 위한 토글 비트).
- 핸드셰이크: ACK(승인), NAK(거부), STALL(오류).
트랜잭션:
- 제어 전송: SETUP + DATA(선택) + IN/OUT + ACK.
- 인터럽트 전송: IN/OUT + DATA + ACK — HID 보고용.
- 벌크 전송: 대용량 블록, 재시도 포함.
- 아이소크로너스: 핸드셰이크 없음, 스트림용.
체크섬: 토큰용 CRC5, 데이터용 CRC16. 공식:
// CRC5 for address/kontsa
crc5_next = crc5_reg ^ data_in;
// Polinom: x^5 + x^2 + 1 (0b001101)
디스크립터와 디바이스 초기화
디스크립터는 디바이스를 설명합니다:
- 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.
초기화:
- 버스 리셋(SE0 >10 μs).
- GET_DESCRIPTOR (Device).
- SET_ADDRESS.
- GET_DESCRIPTOR (Configuration).
- SET_CONFIGURATION.
HID의 경우 GET_DESCRIPTOR (Report) 추가. 키보드 보고 예: 수정자 바이트 + 예약 + 6 키코드.
SpinalHDL에서의 하드웨어 구현
컨트롤러는 유한 상태 기계의 계층 구조로 구축됩니다:
- USBMain: 메인 FSM, 시퀀스 관리.
- USBSendSE0: 리셋을 위한 SE0 생성.
- USBSendShortToken: 짧은 토큰(SOF).
- USBSendLongToken: 전체 토큰(addr+endp).
- USBSendData: NRZI 인코딩 + 비트 스터핑.
- USBReceiver: NRZI 디코딩, CRC 검사.
인터페이스:
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은 APB3를 통해 SoC에 통합됩니다. 클럭킹: 고속을 위한 48 MHz.
KarnixSoC와 드라이버 통합
연결: Karna 보드의 USB Type A, FPGA에서 신호 라우팅. SpinalHDL 구성으로 최상위 레벨에 모듈 추가.
RISC-V용 C 드라이버:
- usb10_bus_reset(): 20 μs 동안 SE0.
- usb10_in_request(): IN 토큰 + DATA1 + ACK.
- usb10_setup_request(): SETUP + DATA + IN.
초기화: usb10_init()으로 디바이스 감지, 디스크립터 읽기, 주소 설정.
HID 디바이스 테스트
애플리케이션 karnix_usb10_test:
- 게임패드: 아날로그 축, 인터럽트 엔드포인트 1의 버튼.
- 마우스: X/Y 델타, 4바이트 보고의 버튼.
- 키보드: 부트 프로토콜, 8바이트 보고(수정자 + 키).
TetRISC-V 통합: PS/2를 USB 입력으로 대체.
핵심 사항:
- FSM으로 MACRO-IP 없이 구현한 USB 1.0 고속(12 Mbps).
- SpinalHDL이 FPGA 합성을 위한 RTL 생성.
- HID 부트 프로토콜로 키보드/마우스 드라이버 간소화.
- NRZI + 비트 스터핑은 정밀한 타이밍(48 MHz 클럭) 필요.
- CRC5/16 검증으로 패킷 오류 방지.
— Editorial Team
아직 댓글이 없습니다.