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 registeredLogged 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=-22Logged every time a poll cycle tries to trigger a bulk conversion and the kernel rejects it.
err=-22isEINVAL.
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):
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.