Serwer WWW z elementami grafiki 3D – praktyczne wykorzystanie pakietów Node.js oraz Three.js w systemach wbudowanych (część 2)

 Zachęcamy też do przeczytania pierwszej części artykułu.

W drugiej części artykułu kontynuujemy tematykę praktycznego wykorzystania pakietów Node.js oraz Three.js w urządzeniach wbudowanych pracujących pod kontrolą system operacyjnego Linux. Dotychczas zostały omówione zagadnienia instalacji frameworku Node.js, przygotowania prostego serwera WWW z podziałem na funkcje front-end/back-end, komunikacji z wykorzystaniem socket.io, a także tworzenia i odczytu danych z procesów potomnych. W niniejszym artykule, na przykładzie modułu KAmodL3GD20, zaimplementujemy prostą obsługę żyroskopu w przestrzeni użytkownika z wykorzystaniem interfejsu i2c-dev, a następnie rozbudujemy projekt graficzny strony WWW o elementy grafiki 3D, która w postaci sześciennej kostki będzie odwzorowywała ruch podłączonego modułu żyroskopowego.

Moduł KAmodL3GD20 – konfiguracja jądra Linux i obsługa programowa

W poprzedniej części artykułu, na potrzeby testów odczytu danych z procesu potomnego, przygotowano prosty kod gryo-i2c.c, którego zadaniem było generowanie losowych wartości dla mierzonego kąta obrotu w osiach X, Y oraz Z. W tym podrozdziale zaimplementujemy właściwą obsługę układu żyroskopowego L3GD20 firmy STMicroelectronics, zamontowanego na wygodnej do użycia płytce prototypowej KAmodL3GD20 – rysunek 1.

Rys. 1. Moduł żyroskopowy KAmodL3GD20 (źródło: kamami.pl)

Wykorzystany do praktycznej realizacji projektu procesor i.MX6 ULL z rdzeniem Cortex-A7 został wyposażony w cztery sprzętowe kontrolery magistrali I2C. Konfigurację jądra systemu Linux rozpoczynamy więc od wywołania narzędzia menuconfig, a następnie włączenia sterowników dla sprzętowego kontrolera magistrali:

Do komunikacji z układem L3GD20 wykorzystany zostanie interfejs i2c-dev, który umożliwia uzyskanie dostępu do magistrali z poziomu przestrzeni użytkownika poprzez pliki specjalne urządzeń /dev/i2c-x (gdzie wartość x oznacza kolejny numer porządkowy interfejsu I2C). Interfejs ten, poprzez wygodne API, umożliwia przygotowanie obsługi urządzenia peryferyjnego bezpośrednio w przestrzeni użytkownika – z pominięciem dedykowanych sterowników w jądrze systemu. Rozwiązanie to jest praktyczne na etapie wczesnego projektowania obsługi sprzętu (brak potrzeby rekompilacji jądra lub modułu) lub w sytuacji gdy sterownik wybranego urządzenia peryferyjnego nie został zaimplementowany w systemie. Włączenie interfejsu i2c-dev w jądrze systemu:

Po zakończonym procesie konfiguracji jądra, niezbędna jest również edycja opisu Device Tree, w którym to aktywujemy wybrany kontroler I2C – poprzez edycję pola status – oraz dokonamy konfiguracji funkcji alternatywnych dla wybranych wyprowadzeń procesora. W prezentowanym projekcie wybrano wyprowadzenia numer 3 i 5 gniazda J504 (umiejscowionego na płycie bazowej VisionCB-STD dla modułów VisionSOM), które mogą pełnić alternatywną funkcję linii SDA i SCL dla kontrolera I2C2 (domyślnie linie te są sygnałami TX oraz RX kontrolera UART5). Pełny schemat połączeń przedstawiono na rysunku 2.

Rys. 2. Schemat połączeń modułu KAmodL3GD20 z płytą bazową VisionCB-STD

Bazując na schemacie połączeń z rysunku 2, dokonajmy edycji opisu Device Tree w którym to aktywujemy kontroler magistrali I2C2:

oraz wyprowadzeniom MX6UL_PAD_UART5_TX_DATA i MX6UL_PAD_UART5_RX_DATA przypiszemy alternatywne funkcje linii SCL oraz SDA:

Po zakończonej konfiguracji jądra oraz edycji plików Device Tree, można przystąpić do kompilacji i zaktualizowania obrazu systemu (patrz ramka poniżej).

W niniejszym artykule wykorzystano komputer jednopłytkowy VisionSOM pracujący pod kontrolą dystrybucji Debian. Autor celowo pominął opisy przygotowania komputera do pracy – przygotowanie karty SD z systemem Debian oraz konfiguracja i kompilacja jądra systemu i plików Device Tree została przedstawiona w ramach artykułu „Emulator konsoli NES w systemie Linux na komputerze VisionSOM”. Komplet informacji został również udostępniony na stronie Wiki producenta komputera.

Po ponownym uruchomieniu komputera, poprawność konfiguracji i kompilacji jądra systemu możemy sprawdzić poprzez wyświetlenie listy dostępnych kontrolerów I2C w katalogu /dev:

Różnica w numeracji kontrolerów (w pliku Device Tree aktywowano kontroler I2C2, natomiast w katalogu /dev odnajdujemy kontroler i2c-1) wynika z różnic indeksowania – jądro systemu stosuje numerację zaczynającą się od wartości 0. Poprawnie skonfigurowany system pozwala na przejście do kolejnego etapu – weryfikacji połączeń sprzętowych. Jedną z najszybszych metod na nawiązanie komunikacji z podłączonym do magistrali sprzętem jest wykorzystanie pakietu i2c-tools w skład którego wchodzą między innymi takie narzędzia jak i2cdetect, i2cset oraz i2cget. Instalacja pakietu i2c-tools w dystrybucji Debian, odbywa się w sposób standardowy dla narzędzia apt-get:

Program i2cdetect umożliwia przeskanowanie wybranej magistrali I2C, wskazanej poprzez parametr -y. Wynikiem działania polecenia jest tablica adresów wraz z listą dostępnych na magistrali urządzeń:

Polecenie i2cdetect poprawnie wykryło podłączony do magistrali układ L3GD20 o przypisanym przez producenta adresie 0x6B (wykryte jednocześnie urządzenie o adresie 0x38 z oznaczeniem UU, jest obsługiwane przez sterownik w jądrze i nie jest dostępne w przestrzeni użytkownika). W ramach dodatkowego testu, korzystając z narzędzia i2cget, można wykonać odczyt zawartości  rejestru WHO_AM_I układu L3GD20 – rejestr ten przechowuje ustalony przez producenta numer identyfikacyjny układu – zestawienie wybranych rejestrów żyroskopu L3GD20 przedstawiono na rysunku 3.

Rys. 3. Zestaw wybranych rejestrów układu L3GD20

Polecenie i2cget pozwala na odczyt danych z wybranego układu podrzędnego i określonego rejestru. Pierwszym parametrem polecenia jest numer porządkowy magistrali, następnie adres układu podrzędnego, numer rejestru spod którego będziemy wykonywać odczyt oraz rozmiar odczytywanej danej (domyślnie jeden bajt). Odczyt zawartości rejestru 0x0F (WHO_AM_I) z układu o  adresie 0x6B podłączonego do magistrali i2c_1, może zostać realizowany następująco:

Odczytana wartość 0xD4 jest zgodna z wartością ustaloną przez producenta, tak więc komunikacja z układem L3GD20 przebiega prawidłowo – możemy przystąpić do implementacji obsługi żyroskopu na potrzeby programu i2c-gyro.

Funkcję main() z pliku gyro-i2c.c rozpoczynamy od otworzenia pliku urządzenia /dev/i2c-1, a następnie za pomocą wywołania ioctl (fd, I2C_SLAVE, adres), ustawienia adresu urządzenia peryferyjnego z którym będzie realizowana dalsza wymiana komunikatów – listing 1.

Listing 1. Otworzenie pliku urządzenia /dev/i2c-1 oraz ustawienie adresu I2C_SLAV

W następnej kolejności, poprzez zapis rejestrów sterujących CTRL_REG[x], wykonamy inicjalizację układu L3GD20. Do tego celu przygotowano funkcję gyro_init(), której zadaniem jest wysłanie na magistralę 6. bajtów danych – adresu rejestru CTRL_REG1 oraz kolejnych wartości wpisywanych odpowiednio do rejestrów CTRL_REG1…CTRL_REG5. W celu optymalizacji funkcji gyro_init() do postaci pojedynczego wywołania write(), wykorzystano wbudowany w układ mechanizm automatycznego zwiększania wartości adresu po każdym zapisie bajtu danych – włączenie tej funkcji wymaga ustawienia najstarszego bitu w adresie rejestru. W ramach funkcji inicjalizacji włączono pomiary w osiach X, Y oraz Z, ustawiono układ do pracy w trybie odpytywania (wymagający sprawdzenia bitu gotowości w rejestrze STATUS_REG), ustawiono zakres pomiarowy na wartość 250 dps oraz blokową aktualizację danych (wartości pomiarowe dla osi X, Y i Z przechowywane są w postaci 16-bitowej – włączenie funkcji Block Data Update zapewnia, że dane przechowywane w starszej i młodszej części rejestru pochodzą z jednej próbki pomiaru). Kod funkcji gyro_init() został przedstawiony na listingu 2.

Zagadnienia związane z obsługą modułu żyroskopu są jedynie tematem uzupełniającym główną tematykę artykułu (pomimo tego, że w drugiej części artykułu stanowią jego obszerny element). Po szczegółowe informacje związane z programową obsługą układu L3GD20, Autor odsyła do dokumentacji układu.
Listing 2. Inicjalizacja układu L3GD20 poprzez zapis rejestrów CTRL_REG[X]

O autorze