KursyPoradnikiInspirujące DIYForum

Kurs STM32 F4 – #11 – Komunikacja przez USB

Kurs STM32 F4 – #11 – Komunikacja przez USB

Standardem komunikacyjnym w świecie PC stał się interfejs USB. Można go znaleźć w ogromnej ilości urządzeń takich jak kamery, myszki, pamięci przenośne, czy klawiatury.

Mikrokontrolery nie stanowią tutaj wyjątku i coraz częściej wyposażane są w kontroler USB, którego obsługą zajmiemy się w tym odcinku kursu

Interfejs USB

Uniwersalna Magistrala Szeregowa (ang. Universal Serial Bus) jest standardem komunikacyjnym definiującym kable, złącza oraz protokół transmisji danych. Magistrala USB umożliwia podłączanie, wymianę danych oraz zasilania pomiędzy komputerami i urządzeniami elektronicznymi.

W komunikacji USB zazwyczaj występują dwa urządzenia - Device oraz Host (kontroler magistrali). Hostem jest np. komputer PC, a urządzeniami typu Device są wszystkie pozostałe urządzenia, które możemy podłączyć bezpośrednio do komputera za pomocą magistrali USB. Z tego powodu nie możemy sobie po prostu połączyć dwóch komputerów kablem USB.

Kontroler USB będący na wyposażeniu naszego mikrokontrolera możne zostać skonfigurowany zarówno jako urządzenie host jak i device.

Gotowe zestawy do kursów Forbota

 Komplet elementów  Gwarancja pomocy  Wysyłka w 24h

Zestaw elementów do przeprowadzenia wszystkich ćwiczeń z kursu STM32 F4 można nabyć u naszego dystrybutora! Zestaw zawiera m.in. płytkę Discovery, wyświetlacz OLED, joystick oraz enkoder.

Zamów w Botland.com.pl »

Zastosowania USB

USB znajduje zastosowanie w wielu urządzeniach. Najbardziej popularne są urządzenia pamięci masowej - pendrive'y oraz dyski zewnętrzne. Równie dobrze znane są nam urządzenia wskazujące, takie jak myszki, klawiatury i pady do gier.

Coraz częściej spotykamy także urządzenia audio wyposażone w port USB (radia samochodowe, amplitunery, głośniki komputerowe). Transmisja dźwięku jest w pełni wspierana przez USB.

Communication Device Class

CDC definiuje klasę urządzenia, za jaką może się podawać kontroler USB. Jest ona używana do transmisji danych w sieciach komputerowych. Jedną z możliwości klasy CDC jest stworzenie wirtualnego portu COM w celu imitacji protokołu RS-232.

Spróbujemy teraz wykorzystać tę właściwość tak, aby przesyłać dane pomiędzy płytką Discovery, a komputerem wykorzystując do tego port USB.

Konfiguracja mikrokontrolera STM32F4

Krok 1. Tworzymy projekt i włączamy pobieranie sygnału zegarowego z zewnętrznego kwarcu.
Krok 2. Konfigurujemy przerwanie od przycisku (GPIO_EXTI0).

Krok 3. Uruchamiamy peryferium USB_OTG_FS w trybie Device_Only, ponieważ będziemy łączyć się z komputerem PC "jako urządzenie".

Konfiguracja mikrokontrolera do korzystania z USB

Konfiguracja mikrokontrolera do korzystania z USB.

Krok 4. Konfigurujemy zegary mikrokontrolera. Ponieważ na magistralę USB musi być podany sygnał 48 MHz, pojawiają się pewne ograniczenia dotyczące częstotliwości. Nie możemy przez to ustawić maksymalnej częstotliwości 100 MHz. W tym przykładzie ustawimy tę wartość na 72 MHz.

Konfiguracja zegarów STM32 przy wykorzystaniu USB

Konfiguracja zegarów STM32 przy wykorzystaniu USB.

Krok 5. W zakładce Configuration ustawiamy klasę urządzenia na CDC (Communication Device Class). Dzięki temu nasz mikrokontroler będzie widziany w komputerze jako wirtualny port COM.

Warto zauważyć, że USB pojawiło się również w sekcji Middlewares. Oznacza to, że do projektu zostaną dołączone biblioteki wysokopoziomowe (wyżej niż HAL), do obsługi wybranej klasy USB.

Ustawienie trybu CDC w kontrolerze USB

Ustawienie trybu CDC w kontrolerze USB.

Krok 6. Generujemy projekt pod nazwą 08_USB.

Obsługa USB na STM32 F4 w praktyce

Na początku musimy się wyposażyć w sterowniki do obsługi wirtualnego portu COM. W tym celu kompilujemy pusty projekt i wgrywamy go na płytkę discovery. Następnie podłączamy ją do komputera za pomocą gniazda USB USER.

Gniazdo micro USB

Gniazdo USB USER, do którego należy podłączyć kabel micro USB.

Po podłączeniu kabla micro USB prawdopodobnie otrzymamy komunikat o nierozpoznanym urządzeniu. Jeśli jednak system w jakiś sposób sobie z tym poradzi, w menedżerze urządzeń nasza płytka będzie widnieć jako na przykład USB Serial Device.

USB Serial Device

Kontroler USB wykryty przez system.

Jeśli tak jest, musimy pobrać sterownik do wirtualnego portu COM ze strony ST. Po rozpakowaniu archiwum postępujemy z instrukcją opisaną w pliku readme.


Jeżeli wszystko wykonaliśmy poprawnie, po podłączeniu kabla micro USB nasza płytka powinna zostać rozpoznana jako STMicroelectronics Virtual Com Port. Zapamiętujemy, który numer został przypisany do nowo stworzonego portu COM. W moim wypadku jest to COM16.

Poprawnie wykryty Virtual COM Port widoczny w menedżerze urządzeń.

Poprawnie wykryty Virtual COM Port widoczny w menedżerze urządzeń.

Transmisja danych przez USB

Obsługa USB różni się nieco od tego, z czym spotkaliśmy się w przypadku poprzednich peryferii. Przyglądając się strukturze projektu zaimportowanego do Workbencha widzimy, że pojawiło się bardzo dużo plików dotyczących USB.

Struktura projektu wykorzystującego USB

Struktura projektu z USB.

Najbardziej interesujący będzie dla nas plik usbd_cdc_if.c (universal serial bus driver communication device class interface), który stanowi interfejs użytkownika dla klasy CDC kontrolera USB. W nim znajdują się funkcje, z których będziemy korzystać do obsługi USB.

Krok 1. W pliku main dodajemy nagłówek usbd_cdc_if.h zawierający funkcje główne do USB:

Krok 2. Deklarujemy tablicę DataToSend, w której będziemy przechowywać ramkę danych do wysłania. Dodatkowo przydadzą nam się zmienne do zliczania wysłanych wiadomości oraz do ustalania ich rozmiaru:

Krok 3. W pętli głównej sprawdzamy, czy przycisk został wciśnięty i dokonujemy bardzo trywialnej eliminacji efektu drgania styków.

Krok 4. Jeżeli przycisk faktycznie został wciśnięty, zwiększamy licznik wysłanych wiadomości, tworzymy nową wiadomość i transmitujemy za pomocą funkcji CDC_Transmit_FS. Parametry wywołania tej funkcji, to wskaźnik na tablicę z danymi oraz długość łańcucha do przesłania.

Krok 5. Kompilujemy program i wgrywamy go na płytkę.
Krok 6. Uruchamiamy program RealTerm. Ustawiamy tryb wyświetlania danych na ANSI.

Zmiana trybu wyświetlania danych w programie RealTerm na Ansi

Zmiana trybu wyświetlania danych w programie RealTerm na Ansi.

Port ustawiamy na ten, na którym pojawił się nasz Virtual COM Port. Następnie wybieramy przycisk Change. Nie przejmujemy się wartością Baud.

Zmiana portu w programie RealTerm

Zmiana portu w programie RealTerm.

Błąd otwierania portu w programie RealTerm

Błąd otwierania portu w RealTerm.

Niestety nie wiem co jest przyczyną takiego stanu rzeczy i po wielu dniach prób przy ogromnej ilości konfiguracji nie udało mi się tego rozszyfrować. W moim przypadku błąd ten występuje prawie zawsze, jeżeli program uruchomiony jest w debugerze, co jest mocno uciążliwe. Aby poprawnie otworzyć port należy:

  1. odłączyć płytkę od zasilania,
  2. wyłączyć program RealTerm,
  3. podłączyć płytkę do zasilania,
  4. uruchomić RealTem.

Aczkolwiek zdarza się, że i po tym zabiegu port nie może zostać otworzony... Jeżeli komuś udało się rozwiązać tę zagadkę, będę wdzięczny za wszelkie informacje w komentarzu!

Krok 7. Jeżeli udało nam się otworzyć port COM i mamy nawiązane połączenie, możemy przetestować działanie programu wciskając niebieski przycisk na płytce Discovery. W terminalu powinny się pojawiać kolejne wiadomości.

Wiadomości odbierane w RealTerm

Wiadomości odbierane w RealTerm.

Świetnie! Umiemy już wysyłać dane z mikrokontrolera za pomocą USB!

Odbieranie danych przez USB

Nawiązując do doświadczenia z poprzednich artykułów oczekiwalibyśmy jakiejś funkcji typu USB_Rx_Cplt_Callback(), która wywoływałaby się przy każdym odebraniu danych i moglibyśmy ją sobie sami zaimplementować. Niestety, odbieranie danych jest nieco bardziej skomplikowane. Żeby zrozumieć podstawy działania tego mechanizmu, musimy zajrzeć do pliku usbd_cdc_if.c. 

Pierwsza sekcja która będzie nas interesować, to definicje stałych odpowiadających za rozmiar buforów wysyłanych/odbieranych danych.

Druga interesująca nas sekcja zawiera deklaracje buforów, do których będą przekazywane dane przed wysłaniem/po odbiorze.

Czytając komentarze dowiadujemy się, że jest to tylko sugerowane rozwiązanie, a użytkownik może postąpić wedle uznania. Aby jednak nie zagłębiać się za bardzo w całą bibliotekę, pozostawimy wszystko tak jak jest, zmieniając jedynie rozmiar buforów na 40.

Funkcja będąca naszym Callbackiem zaczyna się w linii 254.

Funkcja ta wywoływana jest przy każdym odebraniu danych. W tablicy Buf będzie się znajdował odebrany ciąg znaków, a zmienna Len zawierać będzie informację o ilości odebranych znaków.

Mamy już ogólny pogląd na to jak można odbierać dane przez USB. Czas na implementację!

Krok 1. W pliku main.c dodajemy dwie nowe zmienne - tablicę do przechowywania odebranych danych oraz flagę informującą o odebraniu danych.

Krok 2. W dalszej części pętli głównej dodajemy kolejny warunek. Jeżeli flaga odbioru zostanie ustawiona, odebrane znaki mają zostać przepisane do bufora nadawczego i wysłane z powrotem przez USB do komputera.

Krok 3. W funkcji wywoływanej po odebraniu danych ustawiamy flagę ReceivedDataFlag i przepisujemy odebrane dane do naszej tablicy. Wykorzystamy do tego funkcję strlcpy, która jest udoskonaloną wersją strncpy - zabezpiecza przed przepełnieniem buforu i sama dodaje znak końca napisu '\0'.

Ponieważ funkcja strlcpy sama dodaje znak '\0' na końcu, należy przekopiować size+1 znaków. Funkcja CDC_Receive_FS z dodanymi liniami kodu będzie wyglądać następująco:

Krok 4. Kompilujemy program i wgrywamy na płytkę. Jeżeli wykonaliśmy wszystko poprawnie, po wysłaniu danych przez zakładkę Send powinniśmy otrzymać wiadomość, z dopiskiem "Odebrano:".

Wysyłanie danych do mikrokontrolera z programu RealTerm

Wysyłanie danych do mikrokontrolera z programu RealTerm.

Podsumowanie

W dzisiejszym odcinku dowiedzieliśmy się jak korzystać z klasy CDC kontrolera USB będącego na wyposażeniu mikrokontrolera STM32. Umiemy już nadawać i odbierać dane, wykorzystując w tym celu stworzony port COM. W następnym odcinku zajmiemy się wgrywaniem programu do naszego STM'a bez wykorzystania programatora. Jeżeli macie jakiekolwiek pytania, uwagi lub problemy, to piszcie w komentarzach!

Nawigacja kursu

Autor kursu: Bartek (Popeye) Kurosz
Redakcja: Damian (Treker) Szymański

Załączniki

Projekt USB (zip, 1 MB)

Projekt tworzony w artykule.

komunikacja, kurs, kursSTM32F4, programowanie, stm32, USB

Trwa ładowanie komentarzy...