Repository navigation
Bugfix for DHT module to avoid timeouts on high system load #5848
Description
Activity
Thanks for the detailed description and fix.
What port/system are you using?
It was my understanding that the 18ms delay was a minimum, so allowing it to possibly extend beyond 18ms was OK. But I guess that's not the case.
If this fix is made then the
mp_hal_delay_ms(18)would need to be changed tomp_hal_delay_us_fast(18000), becausemp_hal_delay_msmay call scheduled Python code.- Hi Damien, I use Ubuntu 18.04 LTS and an ESP32 port (NodeMCU) Board. I compiled Micropython successfully and encountered the DHT problem and fixed it ;-). Yes, the use of |mp_hal_delay_us_fast(18000)| would also fix the problem! Idea: More elaborate could be: We can use 18ms for the DHT11 and 3ms for the DHT22 (the information which sensor is used could be passed to the function). Many thanks for the good work. Greetings from Germany and stay healthy! Stefan Hammes | | Am 05.04.20 um 13:52 schrieb Damien George:…Thanks for the detailed description and fix. What port/system are you using? It was my understanding that the 18ms delay was a minimum, so allowing it to possibly extend beyond 18ms was OK. But I guess that's not the case. If this fix is made then the |mp_hal_delay_ms(18)| would need to be changed to |mp_hal_delay_us_fast(18000)|, because |mp_hal_delay_ms| may call scheduled Python code. — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <#5848 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AO7ZYWBDCA7CNVA5TU5YHS3RLBWJJANCNFSM4LXMLOXQ>.
Idea: More elaborate could be: We can use 18ms for the DHT11 and 3ms for the DHT22 (the information which sensor is used could be passed to the function).
Yes that makes sense. 18ms is a long time (relatively) and reducing it to 3ms for DHT22 would be good.
- added a commit that references this issue
on May 15, 2020 Another solution for a similar problem (random timeout errors in DHT):
re-implement driver in viper for total control of DHT protocol parameters.# # origin: # https://github.com/micropython/micropython/tree/master/drivers/dht # import micropython # @UnresolvedImport from time import sleep_ms # @UnresolvedImport from machine import Pin # @UnresolvedImport from machine import time_pulse_us # @UnresolvedImport # # reimplement protocol in viper # @micropython.viper # @UndefinedVariable def dht_read_viper(pin_obj:object, dht_buf:ptr8) -> int: # @UndefinedVariable count = 0 # track bits # issue "0" start bit 10ms pin_obj.init(mode=Pin.OUT) pin_obj.value(1) sleep_ms(250) pin_obj.value(0) sleep_ms(10) pin_obj.value(1) # switch to line reading pin_obj.init(mode=Pin.IN) # accept start bit "1" of 80us ticks = int(time_pulse_us(pin_obj, 1, 250)) if ticks < 0: return -1 # failure: missing start bit # accept data stream of 40+ bits while True: # bit duration: "0"=27us and "1"=70us, border is 48us ticks = int(time_pulse_us(pin_obj, 1, 250)) if ticks < 0: break # stop on first timeout if count < 40: # collect first 5 bytes index = count >> 3 # data byte index entry = int(ticks > 48) # "0" vs "1" bit entry dht_buf[index] = (dht_buf[index] << 1) | (entry) count += 1 # restore "1" line level after reading pin_obj.init(mode=Pin.OUT) pin_obj.value(1) if count < 40: return -2 # failure: data stream incomplete # verify received data integrity dht_total = 0 for index in range(4): dht_total += dht_buf[index] & 0xFF dht_total = dht_total & 0xFF dht_check = dht_buf[4] & 0xFF if dht_total != dht_check: return -3 # failure: check sum mismatch return 0 # success: data received class DHTBase: def __init__(self, pin_obj:Pin): self.pin_obj = pin_obj self.dht_buf = bytearray(5) def measure(self) -> int: # report error status return dht_read_viper(self.pin_obj, self.dht_buf) class DHT22(DHTBase): def humidity(self) -> float: buf = self.dht_buf humi = buf[0] << 8 | buf[1] return humi * 0.1 def temperature(self) -> float: buf = self.dht_buf temp = (buf[2] & 0x7F) << 8 | buf[3] if buf[2] & 0x80: temp = -temp return temp * 0.1
I found an error in the DHT module, if the system load is high: I have many Python threads running and the DHT module constantly reports a timeout error. If system load is low, there is no error.
I have a fix for the problem: You should extend the atomic section to include the 18ms waiting. Simply move the mp_hal_quiet_timing_enter() before the mp_hal_delay_ms(18), see below. I see no problem to loose the 18ms because the DHT measurements should only be every 2-3 seconds.
The 18ms may be reduced for DHT22, because the data sheet needs at least 1ms delay. I use a 3ms delay with the DHT22 with no problems. But for DHT11 we need 18ms. So I would let the delay at 18ms.
The fix is easy, in the file:
micropython/drivers/dht/dht.c
ORIGINAL (line 51):
CHANGE TO:
Or with diff:
This gives correct DHT readings even with extremly high system load.
Please include this in the source code. Thanks.
Keep up the good work!
Stefan Hammes, Karlsruhe, Germany