홈으로 돌아가기

FPGA 상의 USB 컨트롤러: 키보드를 예로 한 HID 디바이스 개발

본 기사는 키보드와 같은 HID 디바이스를 연결하기 위한 FPGA 기반 USB 1.1 컨트롤러 개발을 다룹니다. Verilog에서의 모듈러 아키텍처, 디바이스 초기화 과정, 적시 SOF 패킷 전송의 중요성 및 HID 디스크립터 분석을 다룹니다.

FPGA 상의 USB 컨트롤러 생성: 이론에서 작동하는 키보드까지
Advertisement 728x90

# FPGA에서 USB 1.1 컨트롤러 구현: HID 키보드 통합 실습 가이드

FPGA에서 자체 USB 컨트롤러를 개발하려면 프로토콜과 하드웨어 특성을 철저히 이해해야 합니다. 이 가이드는 키보드를 연결하는 USB 1.1 컨트롤러 구현 과정을 단계별로 안내하며, 주요 모듈, 장치 초기화, HID 디스크립터 처리 등을 다룹니다.

USB 1.1 하드웨어 특징

USB 2.0과 달리 USB 1.1은 D+와 D- 두 개의 디지털 라인만 사용하며, 차동 모드로 동작해 FPGA 핀에 직접 연결할 수 있습니다. 속도는 Low Speed(1.5 Mbps)와 Full Speed(12 Mbps) 두 가지입니다. 장치는 연결 시 D-를 High로 끌어올려 Low Speed를, D+를 High로 끌어올려 Full Speed를 신호합니다.

주요 하드웨어 고려사항:

Google AdInline article slot
  • 호스트 측 데이터 라인에 그라운드 풀다운 저항 필요.
  • FPGA 입력단을 5V 스파이크로부터 보호(예: 3.3V 제너 다이오드 사용).
  • 테스트 시 STM32 BluePill 같은 보드를 HID 장치 에뮬레이션에 활용.

USB 컨트롤러 모듈 구조

컨트롤러는 USB 프로토콜 스택의 각 작업을 담당하는 상호 연결된 모듈들로 구성됩니다.

  • M_DATA — 데이터 송수신 코어 모듈.
  • M_CRC16_USB — 데이터 패킷의 CRC16 체크섬 계산.
  • M_GET_PACKET — 데이터 수신 처리: IN 토큰 송신, 패킷 수신, CRC 확인, ACK 송신.
  • M_RECEIVE_MODULE — 데이터 수신 모듈, 포함:

* M_GET_DATA — 버스에서 원시 데이터 읽기.

* M_MEMORY_BUF_CRC16 — 실시간 CRC16 계산 버퍼.

Google AdInline article slot

* M_BUF_RETRANSLATOR — CRC 확인 성공 시 버퍼 데이터 전달.

  • M_SEND_PACKET — 데이터 전송 관리: OUT 토큰, 데이터 송신, ACK 대기.
  • M_TRANSMIT_MODULE — 데이터, 토큰, SOF 패킷, 핸드셰이크 패킷 전송.
  • M_CRC_5 — 토큰, SOF, 핸드셰이크용 CRC5 계산.
  • M_SEND_DATA — CRC16 포함 데이터 패킷 송신.
  • M_SEND_TOKEN — CRC5 포함 토큰, SOF, 핸드셰이크 송신.
  • M_SEND_END_OF_PACKET — 패킷 끝(EOP) 신호 생성.
  • M_DATA_TRANSFER — 버스 상 비트 전송 물리 계층.
  • M_SOF_SENDER — 클럭 동기화용 주기적 SOF 패킷 송신.
  • M_MAIN_AUTOMAT — 컨트롤러 제어 메인 상태 머신.
  • M_USB_INIT — USB 장치 초기화 처리.
  • M_TRANSACTION — 제어 전송 처리.
  • M_HID_ANALYZER — HID 디스크립터 파싱으로 데이터 형식 이해.
  • MEMORY_BUF (4개 인스턴스) — HID 분석 데이터 버퍼.

장치 초기화 과정

초기화는 D+와 D- 상태로 속도를 감지하며 시작합니다. 이후 메인 상태 머신(M_MAIN_AUTOMAT)이 정확한 순서를 실행합니다.

always @(posedge clk)
begin
    if (rst)
    begin
        State_main <= S_IDLE;
        SOF_En <= 1'b0;
        FullSpeedConnect <= 1'b0;
        // ... 기타 신호 리셋
    end
    else
    begin
        case (State_main)
            S_IDLE:
                // 연결 및 속도 감지 대기
                if (Dm & !Dp) // Low Speed
                begin
                    FullSpeedConnect <= 1'b0;
                    ResetTime <= 15_000; // 1.5 MHz에서 10 ms
                    // ... Low Speed 타이머 설정
                    State_main <= S_POWER_RISE;
                end
                else if(Dp & !Dm) // Full Speed
                begin
                    FullSpeedConnect <= 1'b1;
                    ResetTime <= 120_000; // 12 MHz에서 10 ms
                    // ... Full Speed 타이머 설정
                    State_main <= S_POWER_RISE;
                end
            S_POWER_RISE:
                // 전원 안정화 대기 100 ms
                if (WaiteCount == PowerRiseTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_USB_RESET;
                end
            S_USB_RESET:
                // 장치 리셋 (D+와 D- 10 ms간 0)
                if (WaiteCount == ResetTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_INIT_SOF_SENDER;
                end
            S_INIT_SOF_SENDER:
                // 리셋 직후 SOF 패킷 시작
                if (Eof1) State_main <= S_WAITE_SOF;
                else SOF_En <= 1'b1;
            S_WAITE_SOF:
                if (!Eof1) State_main <= S_USB_RESET_RECOWERY;
            S_USB_RESET_RECOWERY:
                // 리셋 후 복구 (10 ms)
                if (WaiteCount == ResetTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_USB_INIT;
                end
            S_USB_INIT:
                // 제어 전송 시퀀스 실행
                if (InitComplite)
                begin
                    State_main <= S_REQUEST;
                end
                else if (InitFail)
                    State_main <= S_FAIL;
            // ... 폴링 상태 (S_REQUEST, S_WAIT 등)
        endcase
    end
end

중요 팁: 리셋 단계(S_USB_RESET) 직후 SOF(Start of Frame) 패킷을 즉시 송신하세요. 복구 단계가 아닌 바로 시작해야 합니다. SOF는 장치와 호스트 동기화를 유지합니다. Full Speed는 CRC5 포함 프레임 번호 사용, Low Speed는 두 라인에서 두 사이클 0(EOP)만 보냅니다. SOF 지연 시 일부 장치 호환성 문제가 발생할 수 있습니다.

Google AdInline article slot

HID 디스크립터 파싱과 장치 폴링

초기화 완료(주소 할당 포함) 후 컨트롤러는 폴링(S_REQUEST)으로 전환합니다. M_HID_ANALYZER 모듈은 제어 전송으로 가져온 디스크립터를 분석해 데이터 패킷 형식과 크기를 파악합니다. 키보드의 경우 리포트 수, 크기, ID를 추출합니다.

일반적인 HID 폴링 루프:

  • 장치 주소와 엔드포인트 1로 IN 토큰 송신.
  • 데이터 패킷 수신.
  • CRC16 검증.
  • 정상 시 ACK 송신.
  • 페이로드 추출(키 스캔 코드 등), 선행 헤더 바이트 생략.
  • 다음 폴링 전 폴링 간격(예: 24 ms) 대기.

장치가 NAK(Not Acknowledged) 응답 시 나중에 재시도. 응답 없거나 오류 발생 시 대기 또는 재초기화로 후퇴.

주요 요약

  • 제때 SOF 패킷: 리셋 직후 Start of Frame 즉시 송신—안정적인 HID 동작 핵심.
  • FPGA 입력 보호: USB 3.3V/5V 혼합 환경에서 적절한 회로로 데이터 라인 보호.
  • 디스크립터 파싱: 데이터 구조 매핑을 위한 디스크립터 분석 없이는 HID 동작 불가.
  • 오류 처리: NAK, STALL, 타임아웃 우아하게 처리해 안정적 연결 유지.
  • 모듈화 설계: 모듈 분리로 디버깅과 프로젝트 재사용 용이.

— Editorial Team

Advertisement 728x90

다음 읽기