Pierwsze kroki z Raspberry Pi: obsługa magistrali 1-Wire
W poprzednio opublikowanych częściach cyklu artykułów poświęconych komputerowi jednopłytkowemu Raspberry Pi zaprezentowane zostały sposoby sprzętowej i programowej obsługi interfejsów UART, I2C oraz portów GPIO. W systemach wbudowanych pełniących głównie funkcje kontrolne i pomiarowe (rejestratory temperatury, sterowniki dostępu, itp.) bardzo często mamy również do czynienia z interfejsem 1-Wire opracowanym przez firmę Dallas Semiconductor. Interfejs ten swoją popularność zawdzięcza głównie dużej liczbie urządzeń peryferyjnych obsługujących wymieniony standard (czujniki temperatury, elektroniczne moduły dostępu iButton , sterowniki ładowania akumulatorów, itd.), jak i również łatwej implementacji programowej (urządzenie nadzorujące transmisję nie musi posiadać sprzętowego kontrolera magistrali – programista sam może napisać proste procedury realizujące wymianę danych).
Prezentację multimedialną przygotowaną przez firmę Maxim, ilustrująca działanie magistrali 1-Wire można obejrzeć pod adresem. |
W niniejszym artykule, na przykładzie niezwykle popularnych czujników temperatury DS18B20, zaprezentowany zostanie sposób programowej obsługi magistrali 1-Wire za pomocą komputera jednopłytkowego Raspberry Pi . W pierwszym podrozdziale artykułu przedstawiony zostanie skrócony opis podstaw teoretycznych ukazujący sposób wymiany danych na magistrali. Opis ten, chociaż nie jest niezbędny do realizacji przykładów programowych, może być niezwykle przydatny przy detekcji i diagnozowaniu problemów występujących przy próbie nawiązania komunikacji z urządzeniami peryferyjnymi (detekcji zwłaszcza przy wykorzystaniu analizatora stanów logicznych). W kolejnym podrozdziale przedstawiony zostanie sposób przygotowania systemu Linux do obsługi magistrali 1-Wire – zarówno poprzez załadowanie odpowiednich modułów jądra systemu, jak i jego samodzielną konfigurację i kompilację. Po prawidłowym przygotowaniu systemu zaprezentowana zostanie prosta aplikacja konsolowa realizująca odczyt temperatury z wszystkich podłączonych do zestawu Raspberry Pi czujników temperatury.
Magistrala 1-Wire – teoria
Magistrala 1-Wire jest przedstawicielem typowego asynchronicznego interfejsu szeregowego. Jak łatwo wywnioskować komunikacja na magistrali odbywa się za pomocą jednej linii danych oraz linii masy, która stanowi poziom odniesienia dla sygnału. W tzw. trybie pasożytniczym (ang. parasite power ) urządzenia peryferyjne nie potrzebują podłączenie osobnej linii zasilania – moc dostarczana jest przez wbudowany w układy peryferyjne kondensator gromadzący energię z linii danych. Takie rozwiązanie redukuję liczbę przewodów magistrali, jednak wpływa negatywnie na zasięg transmisji, zwiększając obciążenie prądowe linii danych.
Komunikacja na magistrali odbywa się dwukierunkowo w trybie master – slave (istnieje również możliwość konfiguracji sieci w trybie multimaster, jednak wymaga to zastosowania procedur arbitrażu). W typowej konfiguracji rolę mastera (urządzenia przeprowadzającego i nadzorującego transmisję) pełni układ mikroprocesora/mikrokontrolera – w naszym przypadku masterem będzie komputer Raspberry Pi. Urządzeniami slave są wszystkie układy peryferyjne dołączane do magistrali. Ponieważ urządzenia slave nie zapewniają możliwości konfiguracji adresu (jak ma to miejsce np. w przypadku układów z magistralą I2C), każdy z układów musi zawierać fabrycznie zdefiniowany unikatowy numer seryjny. Standard 1-Wire definiuje dla każdego z urządzeń peryferyjnych 64-bitowy kod identyfikacyjny zapisany w nieulotnej pamięci ROM. W ramach 64-bitowego adresu możemy wydzielić 48-bitowy numer seryjny, 8-bitowy kod rodziny oraz 8-bitową sumę CRC. Dla czujników temperatury DS18B20, dla których przypisano kod rodziny 0x28, ramka adresowa ma postać przedstawioną na rysunku 1.
Rys. 1. 64-bitowy adres czujnika temperatury DS18B20
Wszystkie urządzenia podłączone do magistrali posiadają wyjścia typu otwarty dren, co wymusza zastosowania na linii danych rezystora podciągającego do napięcia zasilania (o wartości typowo 4,7k?). Przykładowy schemat połączeń dla dwóch układów typu slave został przedstawiony na rysunku 2.
Rys. 2. Schemat połączeń magistrali 1-Wire
Całość wymiany danych na magistrali 1-Wire możemy zrealizować za pomocą czterech prostych sekwencji, opierających się na mechanizmie slotów czasowych:
- inicjalizacja magistrali,
- nadanie logicznej jedynki,
- nadanie logicznego zera,
- odczyt bitu danych.
Bazując na powyższych czterech operacjach możemy zrealizować kompletne funkcje przesyłania i odczytu całego bajta danych, adresowania urządzeń, itd., stąd też w dalszej części tego podrozdziału skupimy się wyłącznie na bardzo krótkiej analizie tych najprostszych transakcji.
Głównym zadaniem sekwencji inicjalizacji jest zresetowanie magistrali i wykrycie podłączonych do niej urządzeń. W cyklu tym układ mastera wymusza na magistrali poziom niski o czasie trwania 480-960 µs. Po zwolnieniu magistrali (co jest równoznaczne z ustawieniem poziomu wysokiego poprzez zewnętrzny rezystor podciągający) układ mastera oczekuje na impuls obecności (ang. presence pulse ) ze strony układów slave . Impuls obecności, reprezentowany przez stan niski na magistrali, powinien trwać od 15 do 60 µs.
Rys. 3. Sekwencja inicjalizacji (źródło: „Linux. Podstawy i aplikacje dla systemów embedded ” Łukasz Skalski)
Wystawienie przez przynajmniej jeden układ slave impulsu obecności, jest sygnałem dla mastera , że może sukcesywnie przeprowadzać kolejne operacje zapisu/odczytu. Zapis logicznej jedynki polega na ustawieniu przez układ mastera stanu niskiego na linii danych magistrali na okres 15 µs, a następnie zwolnieniu magistrali do końca czasu trwania szczeliny czasowej (maksymalnie 105 µs). W przypadku zapisu logicznego zera, stan niski na magistrali powinien trwać od 60 do 120 µs. Odstęp przed transmisją kolejnego bitu powinien wynosić minimum 1 µs.
Rys. 4. Transmisja bitu (źródło: „Linux. Podstawy i aplikacje dla systemów embedded ” Łukasz Skalski)
Jak wspomniano, 1-Wire zapewnia komunikację dwukierunkową, tak więc do pełnego przedstawienia wymiany danych na magistrali, brakuje już tylko krótkiego przedstawienia odczytu bitu danych z urządzenia slave .
Żądanie odczytu bitu danych jest sygnalizowane przez układ master poprzez wystawienie na magistrali impulsu o czasie trwania 1 µs. Następnie poziom na magistrali ustawia układ slave – jeżeli transmitowana jest logiczna jedynka, układ master nie przedłuża impulsu, jeżeli natomiast logiczne zero, slave przedłuża impuls do czasu minimum 15 µs od momentu rozpoczęcia transmisji. Przed upływem 15 µs master rozpoczyna próbkowanie stanu magistrali.
Rys. 5. Odczyt bitu danych (źródło: „Linux. Podstawy i aplikacje dla systemów embedded” Łukasz Skalski)
Przykładowe przebiegi sygnałów na magistrali 1-Wire, zarejestrowane za pomocą analizatora Saleae Logic8 Analyzer oraz oprogramowania Logic pokazano na rysunku 6.
Rys. 6. Analiza magistrali 1-Wire za pomocą analizatora Saleae