Slow OneWire Bulk-Read Polling

This applies to herosdevices.core.bus.onewire.OneWireBusMaster and herosdevices.core.bus.onewire.W1ThermBusMaster, which poll a onewire bus by triggering one bulk conversion for every sensor at once (therm_bulk_read) instead of reading each sensor individually. On a working bus, one poll cycle takes roughly one conversion time (about 750 ms at 12-bit resolution), no matter how many sensors are attached. If the kernel refuses the bulk trigger, OneWireBusMaster falls back to reading each sensor individually so a poll cycle still completes, but every sensor then pays its own conversion time.

Symptoms

The poll_time observable (or the time a manual poll_once() takes) is close to:

number_of_sensors * ~750 ms

For example, 13 sensors on one bus reporting a poll time around 9.5-10.5 s instead of roughly 1 s.

Diagnosis

Check the kernel log for the bulk-read trigger being refused:

dmesg | grep -iE "not registered|therm_bulk_read"

Two messages point at this problem:

Family 28 for <rom-id> is not registered

Logged once per sensor, right when the bus master’s first search runs.

therm_bulk_read_store: unable to trigger a bulk read on the bus. err=-22

Logged every time a poll cycle tries to trigger a bulk conversion and the kernel rejects it. err=-22 is EINVAL.

If you see the first message on its own (only near boot) followed by the second message persisting afterwards, this is a boot-ordering problem, described below. Also worth ruling out before digging further:

# do all sensors use the same power mode? a mix of parasite- and externally-powered
# sensors on one bus also makes the kernel refuse the bulk trigger
for d in $(cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves); do
  echo -n "$d: "; cat /sys/bus/w1/devices/$d/ext_power
done

Cause

w1-gpio’s master driver runs its first bus search as soon as it comes up. If w1-therm, the driver that recognizes DS18B20-family sensors, has not registered yet at that exact moment, every sensor found in that first search is added to the bus as an unrecognized (“not registered”) device. Once a sensor gets added this way, it stays ineligible for bulk-read for the rest of that boot, even after w1-therm loads a moment later - the kernel does not retroactively upgrade it.

On a typical setup, w1-gpio and its dependency wire load early via the dtoverlay=w1-gpio device tree overlay, while w1-therm is only pulled in reactively once a matching device is found. That ordering is exactly backwards for bulk-read: w1-therm needs to already be loaded before the first search runs, not after.

Tip

You can reproduce and confirm this by hand. Force a clean reload with the modules in the correct order and watch for the “not registered” message to disappear:

rmmod w1_therm 2>/dev/null
rmmod w1_gpio
rmmod wire
modprobe wire
modprobe w1_therm
modprobe w1_gpio
sleep 3
dmesg | tail -50
cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count

Fix

Make module loading order explicit instead of relying on the device tree overlay’s reactive autoloading. Add the following to /etc/modules (Raspberry Pi OS reads this via systemd-modules-load.service early in boot, before the overlay-triggered probe):

/etc/modules
wire
w1-therm
w1-gpio

Leave dtoverlay=w1-gpio in config.txt as is - it is still needed for the GPIO pin configuration itself. This change only makes sure w1-therm is ready before w1-gpio probes.

Verifying the fix

Reboot, then check that no sensor was added before w1-therm was ready:

dmesg | grep -iE "not registered|therm_bulk_read"
cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count

Both commands should come back clean: no matching log lines, and a slave count matching the number of sensors you expect. A manual trigger should now settle quickly instead of erroring:

echo trigger > /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read
sleep 1
cat /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read   # expect 1, not an error
for d in $(cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves); do
  echo -n "$d: "; cat /sys/bus/w1/devices/$d/temperature
done
cat /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read   # expect 0 (drained)

Note

OneWireBusMaster writes the trigger command with a trailing newline (f"{action.trigger_value}\\n" in _drain_action). On some kernel versions, w1-therm rejects a trigger write missing that newline - same err=-22 symptom, unrelated to boot order. If the fix above does not resolve the symptom, make sure you are running a herosdevices version that includes this trailing newline.