29 Dec 2020

Temperature Readings with the DS18B20 and OpenEmbedded/Yocto



There are many ways to read a temperature in an electronics project. Probably the easiest way under Linux is with one of those pre-wired waterproof DS18B20 devices. Wire-up the probe to your RaspberryPi, enable a device-tree overlay, and read a file.

Wiring

The datasheet for the DS18B20 has all the information you'll need (and more). The probe has 3 wires: ground (black), DQ data in/out (yellow), and VDD (red). Technically the device doesn't actually need VDD connected, it can siphon enough parasitic power from DQ in normal operation. But since there's already a RaspberryPi in the design, it provides a convenient 5V, and connecting VDD makes the conversion potentially faster and more stable... might as well use it.

The datasheet recommends using a 4.7k pull-up on the DQ line. Grabbing 5V and ground from the RaspberryPi, I've wired up the probe as follows:


The 3-wire bundle comes from the probe, the individual wires run back to the RaspberryPi:


Connected to the RaspberryPi, the 3-wire bundle is my console cable, the individual wires run to the protoboard. The black wire is on ground, the red wire is on +5V. In my case I've decided to use the RaspberryPi's GPIO04, therefore the yellow wire is connected to pin07.



Build

By default the meta-raspberrypi OE/Yocto BSP layer uses the out-of-tree raspberrypi kernel. One of the differences between it and upstream is that the out-of-tree raspberrypi kernel contains all the device-tree overlays specific to the RaspberryPi. To interface with the DS18B20 the 1-wire overlay needs to be enabled in the RaspberryPi's config.txt. In OpenEmbedded/Yocto we use the RPI_EXTRA_CONFIG variable to enable arbitrary configurations in config.txt.

In addition to enabling the 1-wire protocol, we also need to specify the GPIO pin on which we want it to operate. In my specific case, given how I've wired the circuit, I'm using GPIO04, therefore I relay that information as follows:

RPI_EXTRA_CONFIG = "\
# enable 1-wire on gpio 4 \n\
dtoverlay=w1-gpio,gpiopin=4"

If you're building a core-image-minimal, you'll probably also want to add the following to your build:

CORE_IMAGE_EXTRA_INSTALL += " \
        ${MACHINE_EXTRA_RRECOMMENDS} \
        "

Building, flashing, and running the image from OpenEmbedded/Yocto you should see something along the following flash by on the serial console as it boots:

[    5.047539] gpio-4 (onewire@4): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    5.090044] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83

This is good, it means everything is configured properly and the kernel has noticed the temperature probe connected to GPIO04 via 1-wire.

Note that in the case of the DS18B20, each device has a unique 64-bit serial number. So your output should be similar but will be slightly different. The "28" identifies this specific 1-wire device (i.e. the DS18B20), the hex value following the decimal point is the 48-bit unique serial number of my specific device. The last byte is a CRC of the first 56 bits.

Read A File

If everything is working properly and you've seen the previous messages in your system log as the device boots then everything should be set. Any devices that are detected can be found under /sys/bus/w1:

root@raspberrypi3-64:~# cd /sys/bus/w1
root@raspberrypi3-64:/sys/bus/w1# ls
devices            drivers            drivers_autoprobe  drivers_probe      uevent
root@raspberrypi3-64:/sys/bus/w1# cd devices/
root@raspberrypi3-64:/sys/bus/w1/devices# ls
28-01131b62790b  w1_bus_master1
root@raspberrypi3-64:/sys/bus/w1/devices# cd 28-01131b62790b/
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# ls -l
-rw-r--r--    1 root     root          4096 Dec 29 05:35 alarms
lrwxrwxrwx    1 root     root             0 Dec 29 05:35 driver -> ../../../bus/w1/drivers/w1_slave_drive
r
--w-------    1 root     root          4096 Dec 29 05:35 eeprom
-r--r--r--    1 root     root          4096 Dec 29 05:35 ext_power
drwxr-xr-x    3 root     root             0 Dec 29 04:26 hwmon
-r--r--r--    1 root     root          4096 Dec 29 05:35 id
-r--r--r--    1 root     root          4096 Dec 29 05:35 name
drwxr-xr-x    2 root     root             0 Dec 29 05:35 power
-rw-r--r--    1 root     root          4096 Dec 29 05:35 resolution
lrwxrwxrwx    1 root     root             0 Dec 29 05:35 subsystem -> ../../../bus/w1
-r--r--r--    1 root     root          4096 Dec 29 04:28 temperature
-rw-r--r--    1 root     root          4096 Dec 29 04:26 uevent
-rw-r--r--    1 root     root          4096 Dec 29 05:35 w1_slave
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# cat temperature 
23625
root@raspberrypi3-64:/sys/devices/w1_bus_master1/28-01131b62790b# hexdump -C id
00000000  28 0b 79 62 1b 13 01 83                           |(.yb....|
00000008

As you can see, the temperature probe is automatically detected, and Linux handles all the details. Simply reading the "temperature" sysfs entry causes the kernel to ask the device to perform a temperature reading, then fetch the value from the device. Under the hood a lot of details are being handled by the kernel. Note, the reported temperature at this point is 23.625°C.

Notes

If I wanted to switch to, say, GPIO25 instead of GPIO04, all that would be required is to change where the yellow wire connects to the RaspberryPi's 40-pin header (switch from pin07 to pin22) and modify RPI_EXTRA_CONFIG as follows:

RPI_EXTRA_CONFIG = "\
# enable onewire on gpio 25 \n\
dtoverlay=w1-gpio,gpiopin=25"

Build, update the µSD card, apply power… Now when I boot I get:

[    5.113801] gpio-25 (onewire@19): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    5.473042] w1_master_driver w1_bus_master1: Attaching one wire slave 28.01131b62790b crc 83

And everything continues to work as before:

root@raspberrypi3-64:~# cat /sys/bus/w1/devices/28-01131b62790b/temperature 
23500

No comments: