Bare Metal: DS18B20
- 6 minutes read - 1179 wordsI’ve been working through Google’s Comprehensive Rust and, for the past couple of weeks, the Bare Metal Rust standalone course that uses the (excellent) micro:bit v2 that has a Nordic Semiconductor nRF52833 (an ARM Cortex-M4; interestingly its USB interface is also implemented using an ARM Cortex M0).
There’s a wealth of Rust tutorials for microcontrollers and I bought an ESP32-C3-DevKit-RUST-1 for another tutorial and spent some time with my favorite Pi Pico and a newly-acquired Debug Probe.
I’m going to blog in reverse order on these experiences starting with several unsuccessful attempts to interact with 5 DS18B20 (thermometer) sensors using Rust on an ESP32-C3 and then, trying to find a solution that worked, Python on a Pico.
DS18B20s use 1-Wire. 1-Wire is a very straightforward protocol (akin to 12C, SPI etc.). It is a serial communication protocol that, as its name hints, uses a single wire for data (the data wire can also be used for “parasitic” power).
Here are some diagrams:


Those of you who are familiar with it, will recognize this as the really excellent Wokwi simulator that includes several microcontrollers (including Arduinos but not micro:bits) and a slew of peripherals.
NOTE It is possible that the reason these examples don’t work is a 1-Wire timing issue running under Wokwi. I should buy some DS18B20 and try this in our simulation.
Wokwi is extensible, comprising multiple repos that implement the MCUs and peripherals including a C implementation of the DS18B20. This enables the DS18B20 device in Wokwi including permitting the following diagram.json entry:
{
"type": "board-ds18b20",
"id": "temp1",
"top": -40,
"left": 90,
"attrs": {
"deviceID": "000000000001",
"familyCode": "40",
"tempWaveForm": "sine",
"tempWaveFreq": "100"
}
}
NOTE The values in the
attrsobject are documented here
This repo is this peripheral’s implementation and it functions somewhat like a server. Even though I haven’t been able to get the Rust and Python (clients) running on the microcontrollers doesn’t work, the peripheral appears (!?) to work correctly. Here’s the output from Wokwi’s “CHIP CONSOLE”:
*** DS18B20 chip initialising...
reading temp mode: sine
*** DS18B20 setting attributes:
genDebug: 0
owDebug: 0
temperature: 0.000000
familyCode: 28
minTemp: -55.000000
maxTemp: 125.000000
temp_freq: 100.000000
temp_mode: 2
deviceID: 2800000000000140
DS18B20 chip initialised
*** DS18B20 chip initialising...
reading temp mode: sine
*** DS18B20 setting attributes:
genDebug: 0
owDebug: 0
temperature: 0.000000
familyCode: 28
minTemp: -55.000000
maxTemp: 125.000000
temp_freq: 100.000000
temp_mode: 2
deviceID: 28000000000002a2
DS18B20 chip initialised
*** DS18B20 chip initialising...
reading temp mode: sine
*** DS18B20 setting attributes:
genDebug: 0
owDebug: 0
temperature: 0.000000
familyCode: 28
minTemp: -55.000000
maxTemp: 125.000000
temp_freq: 100.000000
temp_mode: 2
deviceID: 28000000000003fc
DS18B20 chip initialised
*** DS18B20 chip initialising...
reading temp mode: sine
*** DS18B20 setting attributes:
genDebug: 0
owDebug: 0
temperature: 0.000000
familyCode: 28
minTemp: -55.000000
maxTemp: 125.000000
temp_freq: 100.000000
temp_mode: 2
deviceID: 280000000000047f
DS18B20 chip initialised
*** DS18B20 chip initialising...
reading temp mode: sine
*** DS18B20 setting attributes:
genDebug: 0
owDebug: 0
temperature: 0.000000
familyCode: 28
minTemp: -55.000000
maxTemp: 125.000000
temp_freq: 100.000000
temp_mode: 2
deviceID: 2800000000000521
DS18B20 chip initialised
NOTE There are 5
DS18B20 chip initialised. Each of which hasfamilyCode: 0x28and, although thedeviceIDare presentfamily-code:address:CRC(instead ofCRC:address:family-code) and, the CRCs disagree with my calculations (see below), you can see e.g.000000000001and on.
1-Wire devices have a hard-coded ROM 64-bit (8-byte) address comprising most-significant byte CRC, 6 bytes of “address” and a least-significant byte called the family code, uniquely identifying the type of sensor (in this case DS18B20 are 0x28 (40)).
Interestingly if your printer rejects a cartridge or your Apple computer dislikes a power supply, it’s likely because these peripherals use 1-Wire devices and the host device is decoding the peripheral’s ROM to determine whether it’s a valid peripheral.
There are 2 CRCs used by 1-Wire. These are documented. My (Rust) code appears to be an accurate implementation of the 8-bit 1-Wire CRC but my CRC calculations don’t agree with those produced by the Wokwi device:
| CRC | Serial Number | Family Code | Description |
|---|---|---|---|
0xa2 |
0x00000001B81C |
0x02 |
Example given in documentation |
0x29 |
0x000000000001 |
0x28 |
Wokwi DS18B20 #1 |
0x70 |
0x000000000002 |
0x28 |
Wokwi DS18B20 #2 |
0x47 |
0x000000000003 |
0x28 |
Wokwi DS18B20 #3 |
0xc2 |
0x000000000004 |
0x28 |
Wokwi DS18B20 #4 |
0xf5 |
0x000000000005 |
0x28 |
Wokwi DS18B20 #5 |
NOTE My CRC calculator agrees with the documented example and validates with the CRC check (prepending the CRC to the ROM) and recalculating results in
0x00.
The Rust example is implemented using the onewire crate.
Unfortunately, it fails to read temperatures from any of the DS18B20s:
SP-ROM:esp32c3-api1-20210207
Build:Feb 7 2021
rst:0x1 (POWERON),boot:0xc (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd6100,len:0x420
load:0x403ce000,len:0x90c
load:0x403d0000,len:0x2370
entry 0x403ce000
INFO - Logger initialized
INFO - Embassy initialized
INFO - LED on
INFO - [ds18b20_task] Task started
INFO - Presence pulse detected
INFO - Adding temperature sensor ([40, 0, 0, 0, 0, 0, 4, 127])
INFO - Adding temperature sensor ([40, 0, 0, 0, 0, 0, 2, 162])
INFO - Adding temperature sensor ([40, 0, 0, 0, 0, 0, 1, 64])
INFO - Adding temperature sensor ([40, 0, 0, 0, 0, 0, 5, 33])
INFO - Adding temperature sensor ([40, 0, 0, 0, 0, 0, 3, 252])
INFO - Waiting for measurement to finish
INFO - Starting temperature measurement
INFO - Reading temperature
ERROR - Failed to read temperature: CrcMismatch { computed: 201, expected: 255 }
INFO - Starting temperature measurement
INFO - Reading temperature
ERROR - Failed to read temperature: CrcMismatch { computed: 79, expected: 0 }
INFO - Starting temperature measurement
INFO - Reading temperature
ERROR - Failed to read temperature: CrcMismatch { computed: 201, expected: 255 }
INFO - Starting temperature measurement
INFO - Reading temperature
ERROR - Failed to read temperature: CrcMismatch { computed: 201, expected: 255 }
INFO - Starting temperature measurement
INFO - Reading temperature
ERROR - Failed to read temperature: CrcMismatch { computed: 201, expected: 255 }
INFO - Cycle finished. Waiting 5 second
It finds the 5 DS18B20s (Adding temperature sensor) and determines the correct family code (40==0x28) and serial numbers. It finds CRCs by serial number: 64 (0x40),162 (0xa2),252 (0xfc) ,127 (0x7f),33 (0x21). The values correpond to the CRCs calculated by wokwi-ds1820-custom-chip so I assume they are correct and my calculator is incorrect.
The MicroPython repo includes definitions of onewire and ds18x20. So these libraries are available by default to MicroPython code:
import ds18x20
import onewire
import time
from machine import Pin
try:
pin = machine.Pin(5, machine.Pin.OPEN_DRAIN)
except Exception as e:
pin = machine.Pin(5)
print(f"OPEN_DRAIN unavailable: {e}")
ow = onewire.OneWire(machine.Pin(5))
print(f"ow.reset() presence: {bool(ow.reset())}")
roms = ow.scan()
print(f"ow.scan() -> {[bytes(r).hex() for r in roms]}")
sensors = ds18x20.DS18X20(ow)
roms = sensors.scan()
print(f"sensors.scan(): {[r.hex() for r in roms]}")
while True:
sensors.convert_temp()
time.sleep_ms(750)
for rom in roms:
t = sensors.read_temp(rom)
print(f"{rom.hex()}: {t:.2f} °C")
time.sleep(1)
I won’t reproduce the CHIPS CONSOLE output because it is essentially the same as when using the ESP32-C3.
Disappontingly, the Python code is unable to scan for devices
ow.reset() presence: True
ow.scan() -> []
sensors.scan(): []
The smart money (i.e. LLMs) thinks that the issue is the timing inaccuracies/specificity when using the emulator. The only way that I could prove this would be to reproduce the circuits in our simulation.
Watch this space!