Gerätetreiber und device tree (DT)

  • Mit Einführung des Kernels 3.18.3 wird nun auch das für Linux (im Linix-Kernel-Handbuch) empfohlene Device-Model (Gerätemodel) für den Raspberry Pi genutzt. Dies ist eine Umsetzung der so genannten objektorientierten Programmierung (ooP), wodurch sich, richtig angewendet, sowohl die Effektivität der Programmierung erhöhen lässt, als auch die Verständlichkeit des Codes verbessert wird. Geräte werden Klassen zugeordnet und können angesprochen werden, ohne ihren genauen physischen Aufbau zu kennen. Der Kernel kann nun durch einen Gerätebaum (device tree) effektiv ergänzt werden, ohne dabei den Kernel selbst verändern zu müssen. Das embedded Linux des Arietta G25 Boards nutzt diese Technik ebenfalls. Sie ist also nicht auf den Raspberry Pi beschränkt sondern der Standard bei komplexen Geräten, welche z.B. die SoC-Technologie (System on a Chip) nutzen. Ich möchte hier am Beispiel des Raspberry Pi und des Betriebssystem Raspian die Nutzung des device tree erläutern. Dabei greife ich auf die readme-Datei auf der Bootpartition und auf die Dokumentation für den Raspberry Pi zurück.

    Der Gerätebaum (device tree)


    Der device tree, abgekürzt auch DT, wird beim Raspberry Pi in der /boot/config.txt angesprochen. Der DT ist bei Raspbian standardmäßig aktiviert. Um Geräte auf die bisherige Weise, also über das Laden von Modulen und das Aktivieren über das auskommentieren in der Blacklist nutzen zu können, ist es möglich, jedoch nicht empfohlen den DT zu deaktivieren. Dazu ist in der /boot/config.txt folgende Zeile anzugeben.

    Code
    device_tree=


    Nach jeder Änderung der Datei ist ein Neustart erforderlich, um diese wirksam werden zu lassen.


    Geräte aktivieren


    Der device tree dient grundsätzlich dazu, dass Geräte, welche DT unterstützen, in der Lage sind, beim Startvorgang des Betriebssystems erkannt zu werden und die Treiber automatisch geladen werden. In den Spezifikationen für Erweiterungen für die "+"-Modelle des Raspberry Pi wie z.B. neue Austeckplatinen als HAT (Hardware on Top), ist dazu ein EEPROM vorgesehen, der die entsprechenden Informationen enthält, um den DT zu steuern. Fehlen diese Informationen kann man Geräte auch manuell in der /boot/config.txt aktivieren. Dazu gibt es auf der Bootpartition einige Dateien, die die Informationen für die jeweiligen Standardgeräte beinhalten. Die Informationen werden in einem C-ähnlichen Format als so genannte Device Tree Sources (.dts) bereitgestellt. Kompiliert und damit nutzbar werden sie als Device Tree Blob bezeichnet und haben die Dateiendung .dtb. Soll ein Gerät aktiviert werden müssen diese Daten in den Arbeitsspeicher geladen werden.


    Standardmäßig sind z.B. die optionalen Schnittstellen wie I²C, I²S und SPI. Befindet sich kein EEPROM mit den notwendigen Informationen auf der Erweiterung kann man diese Schnittstellen manuell mit der Richtlinie dtparam aktivieren.


    Code
    dtparam=i2c=on  #aktiviert die I²C-Schnittstelle
    
    
    dtparam=i2s=on #aktiviert die I²S-Schnittstelle
    
    
    dtparam=spi=on #aktiviert die SPI-Schnittstelle



    Überlagerungen (overlays)


    Overlays werden mit der "dtoverlay"-Richtlinie geladen. Als Beispiel nutze ich hier das für (IR)-Fernbedienungen benötigte lirc-pi Modul. Durch folgenden Eintrag in der config.txt wird das Modul mit seinen Standardeinstellungen geladen.


    Code
    dtoverlay=lirc-rpi


    Die Datei /boot/overlays/lirc-rpi-overlay.dtb wird in den Speicher geladen und das Modul ist dadurch verfügbar. Standardmäßig liegt nun auf Pin 17 der Ausgang und auf Pin 18 der Eingang für eine Fernbedienung. Jetz kommt ein weiterer Vorteil vom DT zur Geltung. Über Parameter können die Pins geändert werden.


    Code
    dtoverlay=lirc-rpi,gpio_out_pin=17,gpio_in_pin=13


    sorgt z.B. dafür, dass die Ausgabe über den Pin 13 erfolgt. Die Benutzung von Parametern kann auch bei anderen Overlays genutzt werden.

    Parameterreferenz für Overlays


    (Übersetzung in Bearbeitung)



    File: <The base DTB>
    Info: Describes the base Raspberry Pi hardware
    Load: <loaded automatically>
    Params:
    i2c_arm (default "off") Set to "on" to enable the ARM's i2c interface
    i2c_vc (default "off") Set to "on" to enable the i2c interface usually reserved for the VideoCore processor
    i2c An alias for i2c_arm
    i2s (default "off") Set to "on" to enable the i2s interface
    spi (default "off") Set to "on" to enable the spi interfaces
    act_led_trigger (default "mmc")
    Choose which activity the LED tracks.
    Use "heartbeat" for a nice load indicator.
    act_led_activelow (default "off")
    Set to "on" to invert the sense of the LED
    act_led_gpio (default "16" on a non-Plus board, "47" on a Plus)
    Set which GPIO pin to use for the activity LED
    (in case you want to connect it to an external
    device)


    Es wird empfohlen, nur die Schnittstellen und Treiber zu laden, die gebraucht werden, da sich je nach Revision und Version des Raspberry Pi einige davon gegenseitig behindern können.


    File: hifiberry-amp-overlay.dtb
    Info: Describes the HifiBerry Amp and Amp+ audio cards
    Load: dtoverlay=hifiberry-amp
    Params: <None>


    File: hifiberry-dac-overlay.dtb
    Info: Describes the HifiBerry DAC audio card
    Load: dtoverlay=hifiberry-dac
    Params: <None>



    File: hifiberry-dacplus-overlay.dtb
    Info: Describes the HifiBerry DAC+ audio card
    Load: dtoverlay=hifiberry-dacplus
    Params: <None>



    File: hifiberry-digi-overlay.dtb
    Info: Describes the HifiBerry Digi audio card
    Load: dtoverlay=hifiberry-digi
    Params: <None>



    File: iqaudio-dac-overlay.dtb
    Info: Describes the IQaudio DAC audio card
    Load: dtoverlay=iqaudio-dac
    Params: <None>



    File: iqaudio-dacplus-overlay.dtb
    Info: Describes the IQaudio DAC+ audio card
    Load: dtoverlay=iqaudio-dacplus
    Params: <None>



    File: lirc-rpi-overlay.dtb
    Info: Configures lirc-rpi (Linux Infrared Remote Control for Raspberry Pi)
    Consult the module documentation for more details.
    Load: dtoverlay=lirc-rpi,<param>=<val>,...
    Params: gpio_out_pin (default "17") GPIO pin for output
    gpio_in_pin (default "18") GPIO pin for input
    gpio_in_pull (default "down") Pull up/down/off on the input pin
    sense (defaults to "-1") Override the IR receive auto-detection
    logic:
    "1" = force active high
    "0" = force active low
    "-1" = use auto-detection
    softcarrier (default "on") Turn the software carrier "on" or "off".
    invert (default "off") "on" = invert the output pin.
    debug (default "off") "on" = enable additional debug messages.



    File: pfc8523-rtc-overlay.dtb
    Info: Configures the pfc8523 Real Time Clock
    Load: dtoverlay=pfc8523-rtc
    Params: <none>



    File: pps-gpio-overlay.dtb
    Info: Configures the pps-gpio (pulse-per-second time signal via GPIO).
    Load: dtoverlay=pps-gpio,<param>=<val>
    Params: gpiopin (default "18") GPIO input pin



    File: w1-gpio-overlay.dtb
    Info: Configures the w1-gpio Onewire interface module.
    Use this overlay if you *don't* need a pin to drive an external pullup.
    N.B. The parasitic power feature is not yet functional using DT.
    Load: dtoverlay=w1-gpio,<param>=<val>
    Params: gpiopin (default "4") GPIO pin for I/O



    File: w1-gpio-pullup-overlay.dtb
    Info: Configures the w1-gpio Onewire interface module.
    Use this overlay if you *do* need a pin to drive an external pullup.
    N.B. The parasitic power feature is not yet functional using DT.
    Load: dtoverlay=w1-gpio-pullup,<param>=<val>,...
    Params: gpiopin (default "4") GPIO pin for I/O
    pullup (default "5") GPIO pin for external pullup

    Fehlerbehebung


    Treten Probleme bei der Verwendung des DT auf kann durch folgenden Eintrag in die /boot/config.txt ein Protokoll erstellt werden:


    Code
    dtdebug=on


    Nach einem Neustart kann das Protokoll mit


    Code
    sudo vcdbg log msg


    aufgerufen werden.


    Weiterführende Literatur


    Dies soll nur eine kurze Einführung in das Thema des DT auf dem Raspberry Pi sein. Eine ausführliche englische Beschreibung findet Ihr unter folgendem Link:


    http://www.raspberrypi.org/doc…figuration/device-tree.md


    Habt Ihr weiter Fragen, scheut Euch nicht, die im Forum zu stellen!

  • Hallo,


    bedeutet die Änderung auch, dass man 1Wire jetzt auch auf einem anderen Pin konfigurieren kann? (z.B. mit dtoverlay=w1-gpio-pullup,gpiopin=17)


    Danke,
    Tomasz

  • Vor kernel version 3.18 konnte man auch schon jeden GPIO Pin für 1-wire verwenden. GPIO#4 war nur der voreingestellte Pin. Einen anderen Pin konnte man in der /boot/cmdline.txt einstellen, und zwar so:


    Code
    bcm2708.w1_gpio_pin=#GPIO


    Dieses Feature war nur schlecht dokumentiert - im Forum der Raspberry Pi Foundation bin ich einst fündig geworden, dass man den Pin auch umstellen kann :thumbs1:.

  • Sinn macht es dann auch, den 'dtc' (= device tree compiler) zu installieren.


    Dann kann man ausführbare Dateien (xxx.dtb) zurück in den Quellcode (xxx.dts) 'discompilieren':

    Code
    dtc -I dtb xxx.dtb -O dts -o xxx.dts


    ggf. editieren und wieder ausführbar (als xxx.dtb) machen:

    Code
    dtc -I dts xxx.dts -O dtb -o xxx.dtb


    Gruß, mmi

  • Hallöle ...
    also ich hab' jetzt gestern erst mal einen kompletten Update/Upgrade allerdings auch rpi-update meines TestPi Nr. 1 gemacht und habe jetzt folgende OS-Version:

    Code
    pi@raspberrypi ~/linux $ uname -a
    Linux raspberrypi 3.18.5+ #1 PREEMPT Fri Feb 6 23:35:59 CET 2015 armv6l GNU/Linux
    pi@raspberrypi ~/linux $


    Das ist ein Modell B ... dazu ist schon mal anzumerken, dass ein aktueller B+ sich mit einer anderen OS-Version meldet:


    Auf dem B+ wo ich grad teste hab ich nach nem u/u/r ein

    Code
    Linux rasppitrainee 3.18.9+ #767 PREEMPT Sat Mar 7 21:41:13 GMT 2015 armv6l GNU/Linux


    Zudem habe ich keinerlei Änderung an der /boot/cmdline.txt vorgenommen habe.
    Das "alte" Szenario mit /etc/modules funktioniert, zumindest was SPI betrifft, anstandslos (gerade vorhin mit einem 2,4 GHz Transmitter getestet).
    Ein i2cetect gibt ebenfalls schlüssige Werte aus (ist nichts angeschlossen):


    Also für mich heisst das: noch mal Schwein gehabt und um diesen (in meinen Augen) Unsinn herumgekommen ;) ...


    cheers,
    -ds-


  • Also für mich heisst das: noch mal Schwein gehabt und um diesen (in meinen Augen) Unsinn herumgekommen ;) ...


    Servus Dirk,


    naja, das ist nur eine Übergangsphase, über lang oder kurz wird es Dich auch noch erwischen. ;)


    Unsinn? Wenn es nur den RPi 1 gäbe und somit auch nur eine ARM Architektur, hättest Du sicher recht.
    Aber bei den zahlreichen Odroiden, Cubies, usw. mit verschiedensten SoC's von Samsung, Broadcom, Allwinner, und wie sie alle heissen in der mittlerweile umfangreichen ARM Familie? Immer wieder andere Adressen, Register ... - am Ende aber doch oft dasselbe Ziel (i2c, SPI, UART, W1, GPIO, usw.).


    Grundsätzlich identische Abläufe mit unterschiedlichen Hardwareparametern, die fangen die device trees ab. Man sollte damit viel schneller passende und künftig trotz der Vielfalt einheitliche Kernel bekommen. Es werden weniger "typspezifische" Entwickler für angepasste (gepatchte) Kernel gebraucht. So gesehen, sicher eine sinnvolle "Erfindung" im heutigen Hardwarechaos.


    Eigentlich braucht man sich keine grossen Gedanken machen, für den RPi ist ja alles passend vorkonfiguriert, gut dokumentiert und man aktiviert einfach, was man braucht. Da wird es mit dem bald kommenden "systemd" in Raspbian viel heißere Diskussionen und wohl auch Probleme geben, da ist zumindest Lernwille und Umdenken gefragt - es macht aber nach gewisser Einarbeitungszeit auch Spaß und ist absolut zeitgemäß. ;)


    Viel Spaß mit Deinem neuen, alten Kernel - hier läuft:
    Linux itx1 3.18.9-2-ARCH #1 PREEMPT Wed Mar 11 19:55:21 MDT 2015 armv6l GNU/Linux
    Ätsch! :thumbs1:


    Bye-bye, mmi

  • Ja hey mmi, alter Weggefährte ...


    nun, der "Unsinn" bezieht sich auf die Einträge in der cmdline.txt ...
    Ich kann nicht beurteilen, was hinter dieser devicetree Geschichte en detail steckt - damit habe ich mich nicht weiter auseinandergesetzt. Auf Treiber-/Modulebene mag das duchaus Sinn machen ...
    Aber so was hat m.E. in der cmdline.txt nix verloren ... das bisherige Konzept mit den Modulen ist imho da völlig ausreichend und ich bin sicher dass das auch ausreichen würde ...


    Aber sei's drum ... watt mutt datt mutt ;)


    cheers und liebe Grüsse,
    -ds-


  • der "Unsinn" bezieht sich auf die Einträge in der cmdline.txt ...


    Aber so was hat m.E. in der cmdline.txt nix verloren ... das bisherige Konzept mit den Modulen ist imho da völlig ausreichend und ich bin sicher dass das auch ausreichen würde ...


    So was hat wirklich nichts in der cmdline.txt verloren. Deswegen stehen die Einträge auch in der config.txt wo sie hingehören. Zudem war Raspbian eines der wenigen Systeme, die DT nicht benutzt haben, da hat die Foundation einfach gepennt. DT brauchst Du heutzutage einfach, weil sonst Deine Kernelmodule wegen der großen Vielfalt der Hardware immer dicker werden. Zudem ist dass hinzufügen eines Treibers damit bedeutend einfacher.


    Also auch wenn der Übergang holprig ist, DT ist eine gute Sache! Wer anderer Meinung ist hat dann irgendwann Pech, da es der Standard bei Linuxsystemen sein wird, also keiner mehr drum rum kommt.

  • Sorry ... ich meinte natürlich die config.txt ...
    Und wie schon erwähnt, funktioniert auf meinem B das SPI anstandslos, obwohl ich folgende Konfiguration habe:

    Code
    pi@raspberrypi ~ $ uname -a
    Linux raspberrypi 3.18.5+ #1 PREEMPT Fri Feb 6 23:35:59 CET 2015 armv6l GNU/Linux
    pi@raspberrypi ~ $



    Code
    pi@raspberrypi ~ $ cat /boot/cmdline.txt 
    dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
    pi@raspberrypi ~ $


    also überhaupt nix mit devicetree sondern nur eben in der /etc/modules


    cheers,
    -ds-

    • Official Post
    Quote from raspiprojekt

    Also auch wenn der Übergang holprig ist, DT ist eine gute Sache! Wer anderer Meinung ist hat dann irgendwann Pech, da es der Standard bei Linuxsystemen sein wird, also keiner mehr drum rum kommt.


    Ungefähr so wie python3 der aktuelle Standard für python ist?. Und obwohl es eine gute Sache will es die mehrheit nicht, weswegen der python 2 support erstmal um 5 Jahre verlängert wurde. Ich sehe mich noch lange ohne dt rumwerkeln. ;).

    Der Unterschied zwischen Genie und Wahnsinn definiert sich im Erfolg.


  • Ungefähr so wie python3 der aktuelle Standard für python ist?. Und obwohl es eine gute Sache will es die mehrheit nicht, weswegen der python 2 support erstmal um 5 Jahre verlängert wurde. Ich sehe mich noch lange ohne dt rumwerkeln. ;).


    Von "altgewohntem" und "liebgewonnenem" trennt man sich immer schwer. Ging mir bei "systemd" auch so. Aber soll man deswegen die optimierte Nutzung weiterentwickelter Hardware einfach links liegen lassen? Wenn ich mir "systemd" ansehe, was war das am Anfang für ein Theater. Von vielen der damaligen Kritiker kommen heute Lobeshymnen. Das wird mit den device trees nicht anders sein - wetten? ;)
    Mit den Python-Versionen würde ich es nicht vergleichen, daß ist etwa so ie zwischen C und C++.


    Gruß, mmi

  • Vorsicht!


    Ich habe gerade die Änderungen zur /boot/config.txt wie hier im Tutorial (oben) http://www.forum-raspberrypi.d…reiber-und-device-tree-dt gemacht bei meinem Mod.2, da ich i2c und spi "enableln" wollte. Danach ging mein "Official" Raspberry Touchscreen gar nicht mehr, weder System noch X; GSD war Pi noch über SSH noch erreichbar.


    Ich machte die Änderungen im /boot/config.txt rückgängig, danach war alles wieder OK!


    Hat jemand eine Erklärung dafür? Hier mein "uname -a" >> Linux raspi01 4.1.15-v7+ #830 SMP Tue Dec 15 17:02:45 GMT 2015

  • Hallo,


    Entschuldigung wenn ich nach solanger Zeit diese Thema noch mal aufgreife. Nach einem "update/upgrade" habe ich beim hochfahren des Raspi (Raspi 2) ein "Failed" entdeckt.




    root@raspberrypi:/home/pi# cat /etc/os-release:


    PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
    NAME="Raspbian GNU/Linux"
    VERSION_ID="8"
    VERSION="8 (jessie)"
    ID=raspbian
    ID_LIKE=debian
    HOME_URL="http://www.raspbian.org/"
    SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
    BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
    root@raspberrypi:/home/pi#


    root@raspberrypi:/home/pi# uname -a:


    Linux raspberrypi 4.4.26-v7+ #915 SMP Thu Oct 20 17:08:44 BST 2016 armv7l GNU/Linux



    root@raspberrypi:/home/pi# systemctl status systemd-modules-load:


    ergab folgende Meldung:


    ● systemd-modules-load.service - Load Kernel Modules
    Loaded: loaded (/lib/systemd/system/systemd-modules-load.service; static)
    Active: failed (Result: exit-code) since Mo 2016-11-07 11:02:51 CET; 18min ago
    Docs: man:systemd-modules-load.service(8)
    man:modules-load.d(5)
    Process: 120 ExecStart=/lib/systemd/systemd-modules-load (code=exited, status=1/FAILURE)
    Main PID: 120 (code=exited, status=1/FAILURE)


    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'fuse'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'i2c_dev'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'wire'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'w1_gpio'
    Nov 07 11:02:51 raspberrypi systemd[1]: systemd-modules-load.service: main process exited, code=exited, status=1/FAILURE
    Nov 07 11:02:51 raspberrypi systemd[1]: Failed to start Load Kernel Modules.
    Nov 07 11:02:51 raspberrypi systemd[1]: Unit systemd-modules-load.service entered failed state.
    Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.


    und



    root@raspberrypi:/home/pi# journalctl _PID=120


    ergab das:


    -- Logs begin at Mo 2016-11-07 11:02:49 CET, end at Mo 2016-11-07 11:22:21 CET. --
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'fuse'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'i2c_dev'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'wire'
    Nov 07 11:02:49 raspberrypi systemd-modules-load[120]: Inserted module 'w1_gpio'
    Nov 07 11:02:51 raspberrypi systemd-modules-load[120]: Inserted module 'w1_therm'
    Nov 07 11:02:51 raspberrypi systemd-modules-load[120]: Failed to find module 'spi-bcm2708'
    root@raspberrypi:/home/pi#


    root@raspberrypi:/home/pi# vcdbg log msg


    001139.623: Read command line from file 'cmdline.txt'
    dwc_otg.lpm_enable=0 console=tty1 root=/dev/sda1 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
    001400.117: Loading 'kernel7.img' to 0x8000 size 0x4088d8
    001403.768: Kernel trailer DTOK property says yes
    001403.784: Kernel trailer DDTK property says yes
    001407.286: Loading 'bcm2709-rpi-2-b.dtb' to 0x4108d8 size 0x3bfc
    001485.393: dtparam: pwr_led_gpio=35
    001494.751: dtparam: uart0_clkrate=48000000
    001507.933: dtparam: i2c_arm=on
    001517.159: dtparam: i2s=on
    001524.383: dtparam: spi=on
    001531.778: dtparam: spi-bcm2708=on
    001534.871: Unknown dtparam 'spi-bcm2708' - ignored
    001552.357: Loaded overlay 'w1-gpio'
    001552.405: dtparam: audio=on
    001657.831: dtparam: arm_freq=900000000
    001700.279: dtparam: core_freq=250000000
    001711.575: dtparam: cache_line_size=64
    001733.101: Device tree loaded to 0x2efebe00 (size 0x41ee)
    001736.318: gpioman: gpioman_get_pin_num: pin SDCARD_CONTROL_POWER not defined
    003535.068: vchiq_core: vchiq_init_state: slot_zero = 0xee880000, is_master = 1
    003539.538: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
    003544.761: TV service:host side not connected, dropping notification 0x00000002, 0x00000002, 0x00000023


    Kann mir da jemand helfen. :s :helpnew:


    :danke_ATDE:


  • Funktioniert das compilen und decompilen mit den .dtbo Files genauso ? Sprich genügt es in den angeführten Kommandos dtb durch dtbo zu ersetzen oder muss noch etwas anderes bedacht werden ?


    Tante Edit sagt:
    Nach diversem Rumprobieren hat folgendes funktioniert:


    Code
    dtc -@ -I dtb xxx.dtbo -O dts -o xxx.dts