Powrót do strony głównej

Kontroler USB na FPGA: opracowanie dla urządzeń HID na przykładzie klawiatury

Artykuł poświęcony opracowaniu kontrolera USB 1.1 na bazie FPGA do podłączania urządzeń HID, takich jak klawiatura. Omówiona modułowa architektura w Verilog, proces inicjalizacji urządzenia, znaczenie terminowego wysyłania pakietów SOF i analiza deskryptorów HID.

Tworzymy kontroler USB na FPGA: od teorii do działającej klawiatury
Advertisement 728x90

Opracowywanie kontrolera USB 1.1 na FPGA: praktyczny przewodnik do podłączania urządzeń HID

Tworzenie własnego kontrolera USB na bazie FPGA wymaga głębokiego zrozumienia protokołu i aspektów sprzętowych. W tym przewodniku omawiamy implementację kontrolera dla standardu USB 1.1 z podłączeniem klawiatury, w tym kluczowe moduły, inicjalizację urządzenia i obsługę deskryptorów HID.

Aspekty sprzętowe USB 1.1

USB 1.1, w przeciwieństwie do USB 2.0, używa dwóch linii cyfrowych (D+ i D-), działających w przeciwfazie, co pozwala na bezpośrednie podłączenie ich do wyjść cyfrowych FPGA. Istnieją dwa podstandardy: Low Speed (1,5 Mb/s) i Full Speed (12 Mb/s). Aby określić prędkość, urządzenie podaje logiczną jedynkę na linię D- dla Low Speed lub na D+ dla Full Speed podczas podłączania.

Ważne aspekty sprzętowe:

Google AdInline article slot
  • Linie danych muszą być podciągnięte do masy przez rezystory po stronie hosta.
  • Konieczna jest ochrona przed dostaniem się napięcia 5 V na wejścia FPGA, np. przy użyciu diod Zenera na 3,3 V.
  • Do testowania można używać płytek takich jak STM32 BluePill, emulujących urządzenia HID.

Architektura modułu kontrolera USB

Kontroler składa się z kilku powiązanych modułów, z których każdy odpowiada za konkretne zadanie w stosie protokołu USB.

  • M_DATA — główny moduł przesyłania i odbioru danych.
  • M_CRC16_USB — oblicza sumę kontrolną CRC16 dla pakietów z danymi.
  • M_GET_PACKET — zarządza procesem odbioru danych: wysyła token IN, odbiera pakiet, sprawdza CRC i wysyła potwierdzenie (ACK).
  • M_RECEIVE_MODULE — moduł odbioru danych, obejmujący:

* M_GET_DATA — bezpośrednio odczytuje dane z szyny.

* M_MEMORY_BUF_CRC16 — bufor z obliczaniem CRC16 w locie.

Google AdInline article slot

* M_BUF_RETRANSLATOR — retransmituje dane z bufora tylko po udanej weryfikacji CRC.

  • M_SEND_PACKET — zarządza procesem wysyłania danych: token OUT, transmisja danych, oczekiwanie na ACK.
  • M_TRANSMIT_MODULE — przesyła dane, tokeny, pakiety początku ramki (SOF) i pakiety serwisowe.
  • M_CRC_5 — oblicza sumę kontrolną CRC5 dla tokenów, SOF i potwierdzeń.
  • M_SEND_DATA — przesyła pakiety danych z CRC16.
  • M_SEND_TOKEN — przesyła tokeny, SOF i potwierdzenia (wszystko z CRC5).
  • M_SEND_END_OF_PACKET — tworzy sygnał końca pakietu (EOP).
  • M_DATA_TRANSFER — warstwa fizyczna transmisji bitów na szynę.
  • M_SOF_SENDER — okresowo wysyła pakiety SOF do synchronizacji.
  • M_MAIN_AUTOMAT — główny automat skończony, zarządzający stanem kontrolera.
  • M_USB_INIT — wykonuje inicjalizację urządzenia USB.
  • M_TRANSACTION — obsługuje transakcje kontrolne (Control Transfers).
  • M_HID_ANALYZER — analizuje deskryptory HID urządzenia, aby zrozumieć format danych.
  • MEMORY_BUF (4 egzemplarze) — bufory dla danych analizy HID.

Proces inicjalizacji urządzenia

Inicjalizacja zaczyna się od określenia prędkości urządzenia na podstawie stanu linii D+ i D-. Następnie następuje ścisła sekwencja etapów, zaimplementowana w głównym automacie skończonym (M_MAIN_AUTOMAT).

always @(posedge clk)
begin
    if (rst)
    begin
        State_main <= S_IDLE;
        SOF_En <= 1'b0;
        FullSpeedConnect <= 1'b0;
        // ... reset pozostałych sygnałów
    end
    else
    begin
        case (State_main)
            S_IDLE:
                // Oczekiwanie na podłączenie i określenie prędkości
                if (Dm & !Dp) // Low Speed
                begin
                    FullSpeedConnect <= 1'b0;
                    ResetTime <= 15_000; // 10 ms przy 1.5 MHz
                    // ... ustawienie timerów dla Low Speed
                    State_main <= S_POWER_RISE;
                end
                else if(Dp & !Dm) // Full Speed
                begin
                    FullSpeedConnect <= 1'b1;
                    ResetTime <= 120_000; // 10 ms przy 12 MHz
                    // ... ustawienie timerów dla Full Speed
                    State_main <= S_POWER_RISE;
                end
            S_POWER_RISE:
                // Oczekiwanie 100 ms na stabilizację zasilania urządzenia
                if (WaiteCount == PowerRiseTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_USB_RESET;
                end
            S_USB_RESET:
                // Reset urządzenia (0 na D+ i D- przez 10 ms)
                if (WaiteCount == ResetTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_INIT_SOF_SENDER;
                end
            S_INIT_SOF_SENDER:
                // Natychmiastowe rozpoczęcie wysyłania pakietów SOF po resecie
                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:
                // Odzyskiwanie po resecie (10 ms)
                if (WaiteCount == ResetTime || SKIP_POWER_RISE)
                begin
                    WaiteCount <= 0;
                    State_main <= S_USB_INIT;
                end
            S_USB_INIT:
                // Wykonanie sekwencji transakcji kontrolnych
                if (InitComplite)
                begin
                    State_main <= S_REQUEST;
                end
                else if (InitFail)
                    State_main <= S_FAIL;
            // ... stany dla odpytywania urządzenia (S_REQUEST, S_WAIT itd.)
        endcase
    end
end

Krytycznie ważny moment: wysyłanie pakietów SOF (Start Of Frame) musi rozpocząć się natychmiast po fazie resetu (S_USB_RESET), a nie po okresie odzyskiwania. SOF służą do synchronizacji urządzenia z hostem. Dla Full Speed jest to pakiet z numerem ramki i CRC5, dla Low Speed — po prostu sygnał EOP (dwa takty z zerem na obu liniach). Opóźnienie w wysyłaniu SOF może prowadzić do nieprawidłowego działania niektórych urządzeń.

Google AdInline article slot

Analiza deskryptorów HID i odpytywanie urządzenia

Po udanej inicjalizacji, która obejmuje przypisanie adresu urządzeniu (innego niż 0), kontroler przechodzi do stanu odpytywania (S_REQUEST). Moduł M_HID_ANALYZER bada deskryptory urządzenia, otrzymane przez transakcje kontrolne, aby określić format i rozmiar pakietów danych. Na przykład, dla klawiatury trzeba wyodrębnić informacje o liczbie raportów (reports), ich rozmiarze i identyfikatorach.

Typowy cykl odpytywania urządzenia HID:

  • Wysłanie tokenu IN na adres urządzenia i punkt końcowy (Endpoint) 1.
  • Odbieranie pakietu danych.
  • Sprawdzenie CRC16.
  • Wysłanie potwierdzenia ACK w przypadku sukcesu.
  • Wyodrębnienie użytecznych danych (np. kodów skanowania klawiszy), pomijając bajty serwisowe na początku pakietu.
  • Oczekiwanie na zadany interwał (np. 24 ms) przed kolejnym odpytywaniem.

Jeśli urządzenie odpowiada NAK (Not Acknowledged), host powtarza zapytanie później. Przy braku odpowiedzi lub błędach, kontroler może przejść do stanu oczekiwania lub wykonać ponowną inicjalizację.

Co jest ważne

  • Terminowa wysyłka SOF: Rozpoczęcie pakietów Start Of Frame zaraz po resecie urządzenia jest kluczowe dla stabilnej pracy, szczególnie z różnorodnymi urządzeniami HID.
  • Ochrona wejść FPGA: Konieczna jest ochrona przed podwyższonym napięciem na liniach danych, ponieważ standard USB używa poziomów 3,3 V/5 V.
  • Analiza deskryptorów: Prawidłowa praca z urządzeniami HID jest niemożliwa bez parsowania deskryptorów do zrozumienia struktury danych.
  • Obsługa błędów: Kontroler musi poprawnie obsługiwać NAK, STALL i przekroczenia czasu, zapewniając odporność połączenia.
  • Podział odpowiedzialności: Architektura modułowa ułatwia debugowanie i pozwala na ponowne użycie komponentów w innych projektach.

— Editorial Team

Advertisement 728x90

Czytaj dalej