Pora na trzeci artykuł z cyklu o Jetson TK1, którego tematem są interfejsy komunikacyjne. Zaczniemy od prostej kontroli stanu pinów GPIO. Następnie przejdziemy przez interfejs UART, a zakończymy na magistrali I2C.
Poznanie tych interfejsów w praktyce jest ważne, a nawet niezbędne, jeśli chcemy wykorzystać opisywaną platformę przy budowie robotów.
Piny ogólnego przeznaczenia mogą być kontrolowane poprzez mechanizm sysfs systemu Linux. Sysfs jest to wirtualny system plików zapewniony przez jądro linuxa, który umożliwia korzystanie z niskopoziomowych urządzeń oraz interfejsów z poziomu przestrzeni użytkownika.
Zaczniemy od prostego wykorzystania tego mechanizmu: z poziomu powłoki tekstowej ustawimy logiczną jedynkę na pinie PGIO_PH1 (pin numer 57). Nie będę tutaj opisywał całej funkcjonalności mechanizmu sysfs. Opowiem o podstawowych mechanizmach, które mogą być przydatne w robotyce. Na początku musimy przejść w tryb superużytkownika:
Shell
1
ubuntu@tegra-ubuntu:~$sudo su
Zbliżenie złącza oraz sygnałów IO (po lewej GND / pin 2, zaś po prawej PGIO_PH1 / pin 50).
Tak jak już zostało wspomniane sysfs działa z wykorzystaniem wirtualnych plików, więc przejdziemy do odpowiedniej lokalizacji i poprosimy jądro Linuxa o to, by wyeksportowało kontrolę nad pinem numer 57 do przestrzeni użytkownika, czyli:
Shell
1
2
root@tegra-ubuntu:/home/ubuntu# cd /sys/class/gpio
Aby mieć pewność możemy zmierzyć miernikiem - na pinie 57 mamy napięcie około 1.8V (jest to napięcie zasilania procesora Tegra K1). Następnie, aby udowodnić, że to my mamy kontrolę nad tym pinem ustawiamy stan niski i ponownie mierzymy napięcie:
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@tegra-ubuntu:/sys/class/gpio/gpio57# echo 0 > value
Szybkie i łatwe! Mechanizm sysfs umożliwia zaawansowaną kontrolę wejść/wyjść ogólnego przeznaczenia, ale jest to odpowiednio bardziej skomplikowane i nie będzie w pełni opisane w tym artykule.
Warto zauważyć, że w internecie jest wiele gotowych bibliotek implementujących mechanizm sysfs w C++, dla przykładu biblioteka libgpio. Aby ją zainstalować potrzebne są następujące kroki:
Program ma za zadanie wczytać znak z klawiatury i w zależności od tego czy będzie to "1" czy "0" ustawić odpowiedni stan na pinie numer 57 oraz wyjść jeżeli będzie to znak "q". Można go rozbudowywać, ale to już zależy od konkretnego zastosowania i kreatywności programisty.
Komunikacja UART z Jetson TK1
W procesorze TK1 dostępne są 4 niezależne instancje interfejsu UART (ciekawskich zapraszam do schematu Jetson TK1):
UART1 - złącze J3A2 (piny 41 oraz 44), rejestrowany w systemie jako /dev/ttyTHS0
UART2 - złącze J3A2 (piny 65 oraz 68), rejestrowany w systemie jako /dev/ttyTHS1
UART3 - brak wyprowadzeń, rejestrowany w systemie jako /dev/ttyTHS2
UART4 - wyprowadzony w postaci interfejsu RS232 na złącze J1A2 (typu dsub DB9), rejestrowany w systemie jako /dev/ttyS0
Ważną sprawą przy wykorzystaniu UARTu w Jetsonie są poziomy napięć.
Jak już wcześniej wspomniano procesor TK1 zasilany jest napięciem 1.8V, dlatego możemy mieć problemy przy próbie połączenia z urządzeniem zasilanym innym napięciem. Aby tego uniknąć należy wykorzystać prosty dwukierunkowy konwerter poziomów logicznych.
Jeżeli chodzi o wykorzystanie prawdziwych UARTów, to wszystko jest już praktycznie gotowe - nie trzeba nawet nadawać uprawnień do czytania i pisania plików ttyTHSx, ponieważ domyślnie użytkownik ubuntu należy do grupy dialout, która ma dostęp do tych plików. Nic tylko programować!
Zabawa interfejsem RS232 wyprowadzonym na UART4 może przysporzyć kłopotów.
Jest on rejestrowany w linuxie jako interfejs ttyS0, który jest wykorzystywany przez getty jako standardowa konsola poprzez mechanizm serwisów włączanych przy starcie systemu. Aby jednorazowo odzyskać kontrolę nad tym interfejsem należy zastopować odpowiedni serwis:
Shell
1
ubuntu@tegra-ubuntu:~$sudo service ttyS0 stop
Aby permanentnie wyrzucić serwis z grona serwisów startowych wystarczy wykorzystać właściwy mechanizm, czyli stworzyć odpowiedni plik przykrywający ten standardowy:
Teraz już można się cieszyć swobodnym dostępem do interfejsu RS232.
Wysokopoziomowe wykorzystanie interfejsu UART można przeprowadzić z wykorzystaniem mechanizmu termios wbudowanego w linuxa. Najpierw jednak połączymy sygnał UART_RX z UART_TX, by przetestować poprawność działania na przykładzie poniższego programu:
Program ma za zadanie wczytać znak z klawiatury i w zależności od tego czy będzie to "1" czy "0" wysłać go poprzez UART, a skoro sami połączyliśmy UART_TX oraz UART_RX, to od razu zgłosi się przerwanie zgłaszające gotowość danych. Jeżeli zostanie wysłany znak "q", to przy odebraniu go program wyczyści wszystkie zasoby i wyjdzie.
Po lewej UART2_RXD / pin 65, zaś po prawej UART2_TXD / pin 68.
Jetson TK1 - Interfejs I2C
W procesorze TK1 jest dostępnych sześć różnych szyn I2C. Z tego cztery są wyprowadzone na złącza J3A1 oraz J3A2. Należy jednak zwracać szczególną uwagę pod jaką nazwą rejestrowana jest konkretna szyna w jądrze Linuxa oraz na poziomy napięć konkretnych szyn.
Poniżej przedstawiono podstawowe informacje o wszystkich dostępnych dla robotyka interfejsach I2C w płytce deweloperskiej Jetson TK1.
Tabelka przedstawiająca wszystkie wyprowadzone interfejsy I2C.
Aby nie tracić czasu od razu zaczynamy zabawę z płytką od instalacji pakietu:
Na początku sprawdzamy zainstalowane w linuksie szyny I2C:
Shell
1
2
3
4
5
6
7
ubuntu@tegra-ubuntu:~$sudo i2cdetect-l
i2c-0i2c Tegra I2C adapter I2C adapter
i2c-1i2c Tegra I2C adapter I2C adapter
i2c-2i2c Tegra I2C adapter I2C adapter
i2c-3i2c Tegra I2C adapter I2C adapter
i2c-4i2c Tegra I2C adapter I2C adapter
i2c-5i2c Tegra I2C adapter I2C adapter
Na razie wszystko gra i już na obecnym etapie możemy podejrzeć jakie urządzenia są podłączone do danej szyny I2C procesora za pomocą komendy:
C
1
2
3
4
5
6
7
8
9
10
ubuntu@tegra-ubuntu:~$sudo i2cdetect-y-r0
0123456789abcdef
00:--------------------------
10:------------------------UU------
20:--------------------------------
30:--------------------------------
40:------------------------UU------
50:------------56------------------
60:--------------------------------
70:----------------
Gdzie ostatni parametr komendy oznacza skanowany numer szyny. Na powyższym listingu widać, że domyślnie na płytce do szyny 0 dołączone są 3 urządzenia i są nimi (ciekawscy mogą odnaleźć je na schemacie elektrycznym płytki):
kodek audio o adresie 0x1c,
sensor temperatury o adresie 0x4c,
pamięć EEPROM o adresie 0x56.
Oprócz tego domyślnie do szyny o numerze 4 dołączony jest również moduł zarządzania zasilaniem o adresie 0x40. Możemy teraz podejrzeć wartości wszystkich dostępnych rejestrów urządzenia za pomocą programu i2cdump:
Dobrze! Podstawy komunikacji I2C w Linuksie mamy za sobą.
Teraz czas na bardziej zaawansowane użycie tego interfejsu i pokażę to z wykorzystaniem modułu cyfrowego akcelerometru z wyjściem cyfrowym, którego sercem jest układ LIS35DE.
Układ jest zasilany napięciem od 2.16V do 3.6V, dlatego zachodzi konieczność użycia szyny GEN2_I2C, czyli i2c-1. Po podłączeniu sprawdzimy, czy układ jest wykrywany w Linuksie.
Shell
1
2
3
4
5
6
7
8
9
10
ubuntu@tegra-ubuntu:~$sudo i2cdetect-y-r1
0123456789abcdef
00:--------------------------
10:--------------------------1d----
20:--------------------------------
30:--------------------------------
40:--------------------------------
50:--------------------------------
60:--------------------------------
70:----------------
Jak widać moduł jest wykrywany pod adresem 0x1d. Mamy wszystko, by zrealizować cykliczne czytanie wartości przyspieszenia z czujnika. Można byłoby zrealizować to poprzez skrypt basha z wykorzystaniem wyżej przedstawionych narzędzi.
Jednak nie będziemy mieli wtedy pełnej kontroli nad częstotliwością odczytu. Z tego względu najlepiej jest wykorzystać wbudowane mechanizmy Linuksa do komunikacji z urządzeniami I2C.
Zbliżenie złącza oraz sygnałów IO (od lewej GND /pin 14, 3V3 / pin 16, GEN2_I2C_SCL / pin 18 oraz na końcu GEN2_I2C_SDA / pin 20).
W tym celu proponuję ściągnąć przygotowany przeze mnie program do odczytu wartości przyspieszenia z modułu KAmodMEMS2:
Program ma za zadanie połączyć się z płytką oraz cyklicznie, co 10 milisekund, odczytać i wyświetlić wartość przyspieszenia w osi x.
Obsługa interfejsu I2C wymaga jeszcze słowa komentarza odnośnie adresowania urządzeń I2C. Muszę przyznać, że z tymi adresami w Linuksie jest małe zamieszanie i dużo czasu spędziłem zanim zrozumiałem o co chodzi.
Programy wchodzące w skład paczki i2c-tools podają adres bez uwzględnienia najmniej ważnego bitu (LSb), który jest ustawiany na 0 lub 1 w zależności czy jest to akcja czytania, czy zapisania do urządzenia. Dlatego przeczytaliśmy wartość 0x1d.
Przy wykorzystywaniu niskopoziomowego mechanizmu opartego o mechanizm sysfs musimy się posługiwać pełnymi adresami docelowymi, czyli 0x3a przy zapisie oraz 0x3b przy odczycie wartości z danego rejestru.
Podsumowanie
Ktoś może zauważyć, że w tym wszystkim zabrakło miejsca dla SPI i muszę przyznać, że sam byłem zawiedziony, że Jetson nie ma łatwego dostępu do tego interfejsu. W chwili obecnej L4T ma domyślnie wyłączony moduł SPI. Aby go włączyć należałoby przekompilować jądro. Można znaleźć w sieci opis tej procedury, wydaje mi się jednak, że łatwiejszym rozwiązaniem będzie wykorzystanie urządzenia z interfejsem I2C.
To już koniec podstawowej wersji artykułu. Za pomocą przedstawionych mechanizmów można zintegrować porządnie działający system robotyczny, co postaram się pokazać w następnej, czwartej części. CUDAownego budowania robotów!
Autor kursu: Daniel (danioto) Koguciuk Redakcja: Damian (Treker) Szymański
Dołącz do 20 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY na bazie Arduino i Raspberry Pi.
To nie koniec, sprawdź również
Przeczytaj powiązane artykuły oraz aktualnie popularne wpisy lub losuj inny artykuł »
Dołącz do 20 tysięcy osób, które otrzymują powiadomienia o nowych artykułach! Zapisz się, a otrzymasz PDF-y ze ściągami (m.in. na temat mocy, tranzystorów, diod i schematów) oraz listę inspirujących DIY z Arduino i RPi.
Trwa ładowanie komentarzy...