Jak w Linuksie działa Device Tree?

Szkolenie „Linux w systemach embedded”

W dniach 25…29 listopada 2013 r. organizuję szkolenie dla wszystkich zainteresowanych rozwijaniem projektów opartych o Embedded Linux. Kurs daje solidną wiedzę i bazę do pogłębiania jej. Uczestnicy będą w stanie zaplanować, rozpocząć i rozwijać własny projekt. Praktyczne ćwiczenia są prowadzone na zestawie BeagleBone Black. Uczestnicy stopniowo implementują kolejne elementy systemu Linux i aplikacji. Po szkoleniu wszyscy uczestnicy otrzymują komputery na własność. Pozwala to samodzielnie rozwijać wiedzę a nawet budować prototypy własnych projektów.

Marcin Bis

Szczegóły, program, ceny.

Co to właściwie jest Device Tree?

Plik tekstowy.

Zawiera strukturę, która opisuje sprzęt.

Nie ogranicza się do Linuksa. Jest to dość stary standard.

Jest skomplikowany (przynajmniej dla ludzi przyzwyczajonych do starego sposobu – kodu C).

W Linuksie, dla ARM, znajduje się w arch/arm/boot/dts. Są tam:

  • .dts – pliki dla konkretnych urządzeń,
  • .dtsi – „biblioteki” dla konkretnych SoC-ów.

Kompilator (scripts/dtc) tworzy z nich wersję binarną (Blob) – .dtb. Ten właśnie plik musi być załadowany przez Bootloader.

 

Co nam daje Device Tree?

Rys 6. Pierwsza zaleta – development jest prostszy 

Rys 6. Pierwsza zaleta – development jest prostszy

 

Firma nie musi już rozwijać 3 różnych wersji jądra dla 3 różnych wersji produktu (albo jednego obrazu z obsługą wszystkich wariantów sprzętu). Wystarczy jeden uniwersalny obraz (mniejszy) i oddzielne Device Tree dla każdego wariantu sprzętu. Ilość kodu specyficznego dla danej wersji urządzenia jest dużo mniejsza.

 

 Rys 7. Druga zaleta – lepsza separacja naszych zmian

Rys 7. Druga zaleta – lepsza separacja naszych zmian

 

Device Tree może być modyfikowane w czasie pracy systemu. Pozwala to odseparować nasze zmiany od sterowników. W przykładzie: przechowujemy adres MAC w specjalnych rejestrach procesora (pamięć nieulotna, programowalne jede raz). Możemy zmodyfikować kod sterownika urządzenia Ethernet tak, aby ustawił adres z tych rejestrów. Zamiast tego stworzymy własny moduł, który wczyta adres i ustawi go w Device Tree. Takie rozwiązanie wydaje się bardziej skomplikowane, ale nie modyfikujemy kodu oryginalnego sterownika, więc łatwiej możemy aktualizować wersję jądra. Nowy sterownik może na przykład wspierać DMA.

 

Przykład 1 – port szeregowy

Skupmy się na Beagle Bone Black. Użyjemy jądra w wersji 3.12. W chwili pisania tego tekstu, najnowszą wersją było 3.12-rc7.

Przykład definicji portu szeregowego. Plik-biblioteka am33xx.dtsi.

Port szeregowy jest wyłączony w tej konfiguracji ponieważ jest to plik biblioteki. Musimy znaleźć konkretne urządzenie zbudowane na tym SoC-u. Definicja dla Beagle Bone Black znajduje się w pliku am335x-boneblack.dts, który z kolei załącza am335x-bone-common.dtsi. Definicję urządzenia znajdziemy w tym ostatnim pliku:

Plik Device Tree kompilowany dla Beagle Bone Black zawiera więc tylko informację o tym, jak ustawić multipleksację PIN-ów, oraz wskazuje, ze port szeregowy jest aktywny w tym zestawie. Wrócimy za chwilę do multipleksacji.

Port szeregowy jest prostym urządzeniem podłączonym bezpośrednio do procesora. Nie korzysta z żadnych magistral, które pozwoliłyby go automatycznie wykryć i skonfigurować (USB, PCI). Próba wykrywania portu szeregowego polegałaby na zapisywaniu jakichś wartości pod losowe adresy, co jest bardzo złym pomysłem (może nawet prowadzić do fizycznego uszkodzenia SoC-a). W Linuksie takie urządzenia nazywają się „platform devices”. Są one definiowane a nie wykrywane.

Jądro używa pojęcia magistrali (bus) do organizowania urządzeń i pasujących do nich sterowników. Na przykład, w działającym systemie, /sys/bus/usb/devices – zawiera listę urządzeń wykrytych przez kontroler USB, a /sys/bus/usb/drivers – listę załadowanych sterowników. Analogicznie w systemie wbudowany znajdziemy /sys/bus/platform/{devices|drivers}. Lista urządzeń odpowiada Device Tree.

Sterownik portu szeregowego dla tej architektury: drivers/tty/serial/omap-serial.c:

Zawiera listę urządzeń, do których pasuje. Jest ona dołączana podczas rejestrowania sterownika w systemie.

Pozwoli to automatycznie skojarzyć sterownik z kompatybilnym z nim urządzeniem. Następnie uruchamiana jest funkcja, wskaźnik do której przekazano w elemencie .probe:

Odczytana w ten sposób częstotliwość zegara, jest następnie ustawiana.

W analogiczny sposób, sterownik odczytuje numer przerwania i adresy rejestrów:

A także informacje o zegarach, numery kanałów DMA oraz dodatkowe atrybuty.

 

Skąd mam wiedzieć co umieścić w Device Tree?

Podstawowym źródłem informacji jest oczywiście kod danego sterownika. Bywa on jednak skomplikowany i nieprzejrzysty. Dla ułatwienia pracy architektom systemu, którzy przygotowują Device Tree dla sprzętu, w kodzie źródłowym jądra, zajdują się listy atrybutów poszczególnych sterowników: Documentation/devicetree/bindings/.

Na przykład dla omawianego tu portu szeregowego – Documentation/devicetree/bindings/serial/omap_serial.txt:

Multipleksacja

Raz jeszcze dla BeagleBone Black. W am335x-bone-common.dtsi, mamy:

Wartości typu MUX_MODE0 zdefiniowane są z kolei w odpowiednim pliku nagłówkowym (am33xx.dtsi):

Znaczenie poszczególnych pól, znajdziemy raz jeszcze w dokumentacji.

 

Przykład 2 – podłączamy termometr I2C

Dołączamy termometr I2C do Beagle Bone Black. Niech będzie to układ kompatybilny z LM75. Linux zawiera odpowiedni sterownik. Magistrala I2C0 (pierwsza) jest na stałe podłączona do układu kontrolującego zasilanie. Nie możemy jej użyć. Skorzystamy z I2C2.

Należy zmodyfikować Device Tree dla naszego urządenia:

Aby ustawić multipleksację, należy sięgnąć do dokumentacji zestawu. Z dokumentu BeagleBone Black System Reference Manual, dowiemy się że magistrala I2C2 wyprowadzona jest na jednym ze złącz.

 

Rys 8. Fragment dokumentacji multipleksacji pin-ów wyprowadzonych na złączu P9 BeagleBone Black 

Rys 8. Fragment dokumentacji multipleksacji pin-ów wyprowadzonych na złączu P9 BeagleBone Black

 

Pozostaje tylko skompilować odpowiedni sterownik (make ARCH=arm menuconfig):

Po kompilacji jądra i Device Tree …

… i uruchomieniu nowego systemu, można korzystać z funkcji dostarczanych przez sterownik.

Aktualna temperatura:

Podsumowanie

Device Tree jest sposobem opisu urządzeń w Linuksie dla ARM. Pozwala w elegancki i standardowy sposób zdefiniować urządzenia, które nie mogą być automatycznie wykryte (czyli większość stosowanych w systemach wbudowanych). Jest stosowany we wszystkich nowych urządzeniach obsługiwanych przez Linux.

 

Szkolenie

25…29 listopada 2013r. organizuję szkolenie dla wszystkich zainteresowanych rozwijaniem projektów opartych o Embedded Linux. Kurs daje solidną wiedzę i bazę do pogłębiania jej. Uczestnicy będą w stanie zaplanować, rozpocząć i rozwijać własny projekt. Praktyczne ćwiczenia są prowadzone na zestawie BeagleBone Black. Uczestnicy stopniowo implementują kolejne elementy systemu Linux i aplikacji.

Po szkoleniu uczestnicy zatrzymują urządzenia. Pozwala to samodzielnie rozwijać wiedzę a nawet budować prototypy własnych projektów.

Szczegóły, program, ceny.

Zapraszam – Marcin Bis

 

Marcin Bis od 2007 roku zajmuje się zastosowaniami Linuksa w systemach embedded, przede wszystkim w rozwiązaniach przemysłowych działających w czasie rzeczywistym (real time applications). Konsekwentnie zdobywa doświadczenie praktyczne, uczestnicząc w projektach z dziedziny automatyki przemysłowej, domowej, multimediów, urządzeń sieciowych i wielu innych, zarówno w Polsce i za granicą. Swoją wiedzą i doświadczeniami dzieli się na konferencjach, prowadzi także szkolenia pod marką bis-linux.com. Zajmuje się zagadnieniami związanymi z projektowaniem urządzeń, portowaniem i uruchamianiem Linuksa, sterownikami urządzeń a także doborem komponentów OpenSource i wreszcie aplikacjami i skryptami składającymi się na gotowy system.

Jest ponadto autorem pierwszej w języku polskim książki o zastosowaniach Linuksa w systemach embedded, która ukazała się nakładem Wydawnictwa BTC w roku 2011 („Linux w systemach embedded”).

O autorze