Wednesday 21 August 2013

Device Trees and You!

Linux is pretty awesome, and the fact that I have a board the size of a credit card that can run a full Linux OS is incredibly awesome.  This awesome does come with a bit of a price though.  A stock Beaglebone Black comes with a pre-built version of Angstrom Linux which allows you to boot the Black and setup some software packages like a webserver or a database.  What it doesn't do out of the box is talk to the 1-wire device, the DS18B20 temperature probe I'm using.  To do that you need to define a Device Tree Overlay.  This file, when compiled into your kernel image, will tell the hardware what GPIO pin the signal from the 1-wire device is coming in on.  Here is the .dts file I found on a very helpful site called Hipstercircuits.

 /dts-v1/;  
 /plugin/;  
 / {  
      compatible = "ti,beaglebone", "ti,beaglebone-black";  
      part-number = "BB-W1";  
      version = "00A0";  
      /* state the resources this cape uses */  
      exclusive-use =  
           /* the pin header uses */  
           "P9.22",  
           /* the hardware IP uses */  
           "gpio0_2";  
      fragment@0 {  
         target = <&am33xx_pinmux>;  
         __overlay__ {  
                          dallas_w1_pins: pinmux_dallas_w1_pins {  
                               pinctrl-single,pins = < 0x150 0x37 >;  
                          };  
         };  
      };  
      fragment@1 {  
         target = <&ocp>;  
         __overlay__ {  
               onewire@0 {  
                    compatible   = "w1-gpio";  
                    pinctrl-names  = "default";  
                    pinctrl-0    = <&dallas_w1_pins>;  
                    status     = "okay";  
                    gpios = <&gpio1 2 0>;  
               };  
      };  
      };  
 };  

This file tells the Black that I want the 1-wire input to come in on the P9 Header on pin 22, if you look at the picture in my last post of the Black you can see a green wire going into a header, that's the data line from the DS18B20 going into the 22nd pin on that Header.  There are quite a few GPIO lines on the Beaglebone Black, some of them are reserved by the system already on startup so you need to know which ones are free, I took the .dts file above straight from Hipstercircuits and assumed the person who posted it had done the necessary research to identify that pin 22 wasn't already in use.

If you keep reading the post on Hipstercircuits you'll see they compile the .dts file into a binary .dtbo file, copy it into /lib/firmware on the Black and then enable it with the following command

echo BB-W1:00A0 > /sys/devices/bone_capemgr.9/slots

NOTE: on my Beaglebone Black my /sys/devices did not have a bone_capemgr.9 but a bone_capemgr.8.  I believe that is because I don't currently have a display connected, make sure the path under /sys/devices is correct for you before issuing the command above.

Since I didn't want to have to do this everytime the board booted, and as it seems like the Kernel currently has a bug that prevents loading userland .dtbo files we need to add our device tree to the Kernel by compiling our own.  If you've never compiled a Kernel, it's gotten a lot easier.  You'll need access to a Linux box, I used a Linux Mint 14 machine with no problems and only had to install one program, lzop, to finish the compile with no errors.

To compile the kernel follow the steps on this page, wiki.replicape.com.  Once you can compile a kernel with no errors you need to add the .dts file from above and follow the steps on this Hipstercircuts post.  In my case I had named my .dts file BB-W1-00A0.dts, in device tree language BB-W1 is the name and 00A0 is the version.  So in the section for editing /arch/arm/boot/dts/am335x-bone-common.dtsi you would use BB-W1 for both board-name and part-number and 00A0 for the version.  The manufacturer bit doesn't matter, I used Dallas.  Finally you need to add your compiled .dtbo file to the package which is done by editing kernel/firmware/Makefile and adding


fw-shipped-$(CONFIG_CAPE_BEAGLEBONE) += \
    BB-W1-00A0.dtbo

to the end of the Makefile fw-shipped section.   Recompile your kernel and then follow the instructions on the Kernel compile page for copying the new kernel to the Beaglebone Black.

NOTE: your rootfs/lib/modules/3.8.13-XXXXX-XXXXXXXX will have a different number than the one listed in the compile page, just do an ls -al in rootfs/lib/modules/ and find the version you compiled, mine had two directories, one with a -dirty flag so I left that one alone.  Once you've copied and rebooted your board and hopefully succesfully reconnected do a uname -a and you should see the kernel version report the current date as the compile time, if not you may have mistyped something.  Make sure your uImage symlink in /boot is pointing to your uImage-3.8.13 file.  It should have the date you compiled it as it's datestamp.  When that's done, you should be able to access the device and read a temperature.


root@beaglebone:~# python temp.py 
Temperature is 23.562 degrees

temp.py is a really basic program that simply reads from the 1-wire device that now shows up and translates the value read into a readable temperature.


import time

w1="/sys/bus/w1/devices/28-00000449da30/w1_slave"

while True:
    raw = open(w1, "r").read()
    print "Temperature is "+str(float(raw.split("t=")[-1])/1000)+" degrees"
    time.sleep(1)

NOTE: Your device address will probably differ from the one above, just look at /sys/bus/w1/devices and if you've only got one probe attached whatever address shows up will be your probe.  1-Wire allows multiple devices to be connected to the same pin, so theoretically I could add more probes to the same GPIO and they would show up with their own specific address, accessing the temps from those probes is as simple as changing the w1 variable to point to the new address.  I don't plan on adding more then one probe to CrankBrew so this is a moot point, but for those of you planning on monitoring multiple fermentations this would work really well.

No comments:

Post a Comment