Mikrokontroler STM32 jako konwerter USB na 2xRS232

Mikrokontrolery STM32 z wbudowanym interfejsem USB device doskonale nadają się do implementacji w nich konwerterów USB/RS232 (zarówno dla Windows jak i Linuksa) – przykład takiego rozwiązania przedstawiamy w artykule.

Uwaga! Projekty przygotowano w wersji dla Linuksa oraz Windows. Wersje źródłowe są dostępne na końcu artykułu.

Prezentowane rozwiązanie udostępnia 2 wirtualne porty szeregowe, które mogą być używane niezależnie w tym samym czasie. W projekcie nie są obsługiwane linie RTS, DTR itp., nie mniej jednak można je łatwo dodać (poza linią CTS, której nie obsługuje klasa USB CDC). Schemat elektryczny proponowanego rozwiązania pokazano na rys. 1, a schemat aplikacji blokowy na rys. 2.

 

Rys. 1. Schemat elektryczny konwertera

 

Rys. 2. Budowa aplikacji

W projekcie można używać jednego lub 2 wirtualnych portów szeregowych, w zależności od definicji zawartych w nagłówku converter.h. Najważniejszy element tego pliku, służący do konfiguracji, pokazano na list. 1.

List. 1. Parametry konfigurujące projekt

 

 

 

Jeżeli definicja USE_VCOMx jest ustawiona na 1, wówczas wybrany wirtualny COM będzie widoczny w komputerze. Definicja VCOMx_USART_NUM mówi zaś, z którym fizycznym portem szeregowym procesora dany wirtualny port ma się komunikować. Aby można było jednocześnie transmitować dane do dwóch USART-ów sprzężono je z USB za pomocą buforów kołowych a cała transmisja odbywa się na przerwaniach, co pokazano na rys. 3.

Rys. 3. Model transmisji danych przez konwerter

Od strony USB i biblioteki vCOM są widoczne dwa wirtualne urządzenia vcom1 i vcom2. Gdy odbieramy dane przez wybrany vcom z komputera, wówczas przepisujemy je do nadawczego bufora kołowego (przypisanego po danego portu USART) i włączamy przerwanie od nadawania danych przez USART. W przerwaniu tym sprawdzamy, czy w buforze nadawczym są dane – jeśli tak, wówczas je odczytujemy i wysyłamy – jeśli nie, wówczas blokujemy przerwanie.
Podobnie jest w przypadku odbioru danych przez USART – jeśli zostanie wygenerowane przerwanie odbiorcze, wówczas wpisujemy odebrane dane do bufora odbiorczego. W momencie gdy przez dany vcom można przesłać kolejne dane do hosta jest wywoływana odpowiednia funkcja podpięta do danego obiektu vcom. Następuje w niej sprawdzenie, czy mamy dane w buforze odbiorczym portu USART, z którym dany vcom współpracuje. Jeśli są jakieś dane, wówczas odczytujemy tyle, ile da się przesłać w jednej paczce do hosta i wysyłamy je.
Główny element konwertera to plik converter.c. W jego nagłówku znajdują się wszystkie potrzebne ustawienia – mapowanie elementów vcom na poszczególne porty USART, numery portów i pinów interfejsów USART itp.
Zainicjowanie biblioteki USB jest wykonywane przy starcie systemu. Nie zagłębiając się w nią zbyt mocno powiem, że używamy tu gotowego automatu do tworzenia konfiguracji dzięki czemu stworzenie deskryptora konfiguracji i potrzebnych struktur używanych przez bibliotekę USB jest bardzo proste. Zainicjowanie USB odbywa się za pomocą funkcji pokazanej na list. 2.

List. 2. Funkcja inicjująca interfejs USB w mikrokontrolerach STM32

 

 

 

Następuje w niej utworzenie i zainstalowanie konfiguracji (wywołanie pierwszych 4 funkcji) a następnie dodatkowo zmiana niektórych pól deskryptora urządzenia i zainstalowanie stringów – ciągów znakowych unicode opisujących urządzenie.
Tak stworzona konfiguracja dla dwóch obiektów vcom ma 4 interfejsy: 2 interfejsy CCI (Communication Class Interface) pełniące funkcję notyfikacyjną i 2 interfejsy CDI (Communication Data Interface) służące do transmisji danych. Każdy interfejs typu CCI posiada jeden punkt końcowy (endpoint) typu interrupt (przerwaniowy) natomiast interfejs CDI posiada 2 punkty końcowe typu bulk (masowe) – jeden typu IN i jeden OUT służące do przesyłu danych Tx i Rx danego obiektu vcom. Z tego wynika, że na jeden wirtualny port szeregowy przypadają 3 punkty końcowe. Mikrokontrolery STM32 z wbudowanymi interfejsami USB posiadają ich 8, więc łatwo obliczyć, że można na tym procesorze zaimplementować max. 2 wirtualne COM-y. Zajmą one 7 punktów końcowych – 3 na 2 porty + zerowy punkt zawsze używany do transmisji kontrolnej.
Inicjalizacja portu USART następuje zaś – zgodnie z ideą klasy CDC – dopiero w czasie działania konwertera, gdy nadejdzie od hosta żądanie otwarcia portu. W tym momencie wywoływana jest przez bibliotekę CDC odpowiednia funkcja podpięta do obiektu vcom. Następuje w niej sparsowanie przesłanych przez hosta parametrów pracy portu USART. W tej aplikacji zaimplementowałem ustawianie takich parametrów jak: prędkość transmisji, liczba bitów stopu i typ parzystości. Następnie wywoływana jest napisana do tego celu prosta funkcja inicjująca port USART, przedstawiona na list. 3.

List. 3. Funkcja inicjująca port USART

Funkcję tę podzielono na sekcje ilustrujące co należy zrobić, aby uruchomić port USART w procesorze STM32.
Została ona stworzona, gdyż mimo że standardowe biblioteki producenta napisane są w sposób bardzo przemyślany, to skonfigurowanie USART-a zajmuje kilka linii i wymaga dokonania ustawień w kontrolerach różnych peryferiów.
W pierwszej sekcji następuje zidentyfikowanie numeru portu, który inicjujemy – 1, 2 lub 3. W tym samym miejscu uzupełniamy zmienne funkcji oraz – co ważniejsze – następuje tu zerowanie USART-a i zainicjowanie taktującego go zegara w kontrolerze RCC. Jest to bardzo ważna czynność, gdyż w procesorze STM32 każde peryferiom ma wyłączany zegar i po włączeniu procesora wszystkie interfejsy są wyłączone.
W drugiej sekcji następuje skonfigurowanie linii GPIO. Aby USART mógł komunikować się ze światem zewnętrznym należy skonfigurować odpowiednio linie GPIO, gdyż domyślnie po zerowaniu procesora wszystkie są skonfiurowane jako uniwersalne linie wejściowe. Należy je ustawić w tryb: GPIO_Mode_AF_PP dla linii Tx i GPIO_Mode_IN_FLOATING dla Rx.
W trzeciej sekcji następuje skonfigurowanie portu USART i włączenie go w jego własnym kontrolerze. Dokonuje się tego przy pomocy funkcji bibliotecznych. Wypełniamy odpowiednią strukturę z parametrami pracy interfejsu i wywołujemy funkcję inicjującą. Następnie wydajemy polecenie włączenia portu.
W ostatniej sekcji – jeśli nam jest to potrzebne (a w tej aplikacji jest potrzebne) – następuje skonfigurowanie i włączenie przerwania portu USART w kontrolerze NVIC a następnie włączenie przerwania w jego własnym kontrolerze. Konfigurujemy priorytety danego kanału po czym włączamy generowanie danego przerwania przy nadawaniu i odbieraniu.

Sterowniki
Obecnie konwerter działa z systemem operacyjnym Linux. Jako sterownik używany jest moduł CDC_ACM. Bardzo dobrze przemyślana idea budowy sterowników pod tym systemem operacyjnym sprawia, że nie ważne, czy urządzenie udostępnia jeden wirtualny port szeregowy czy większą ich liczbę, pamięć masową, urządzenie interfejsu HID itp. O ile liczba punktów końcowych na to pozwala sterowniki zawsze będą je właściwie obsługiwać.
Po podłączeniu prezentowanego konwertera do komputera wykrywane są 2 urządzenia: /dev/ttyACM0 i /dev/ttyACM1, co można sprawdzić w katalogu /dev/ lub w terminalu komendą dmesg wyświetlającą log systemowy – pod jego koniec powinno widoczne być coś podobnego do:

Plików tych można używać jak normalnych portów szeregowych na Linuksie. Jeżeli pliki urządzeń nie są tworzone, wówczas albo nie mamy załadowanego modułu CDC_ACM albo moduł nie rozpoznaje numerów VendorID i ProductID naszego urządzenia – można wtedy ręcznie podać te numery sterownikowi. Takich urządzeń można oczywiście podpiąć do komputera więcej – będziemy wtedy mieli więcej urządzeń ttyACMx.
Ze względu na specyficzną ideę budowania sterowników w Windows sprawa jest bardziej skomplikowana – sterownik, który jest używany przy firmowym ST demo USB działa tu (po ustawieniu odpowiednich VendorID i ProductID) tylko z pojedynczym wirtualnym portem szeregowym używając systemowego usbser.sys – przy dwóch trzeba niestety zmodyfikować sterownik.

 
Piotr Wojtowicz
piotreklc60@gmail.com

Do pobrania

Autor: