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:
- 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.
* 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ń.
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
Brak komentarzy.