hamishcunningham / fishy-wifi

Scripts, notes and the odd subaquatic gizmo for the ESP8266 and what-have-you.
GNU Affero General Public License v3.0
25 stars 13 forks source link

Waterelf32 startPeripherals not detecting DHT22 #15

Closed cgmcintyr closed 6 years ago

cgmcintyr commented 6 years ago

As noted in https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf, the DHT22 has an average sensing period of 2s.

The function startPeripherals will occasionally not detect the DHT22 as a reading has not yet been made before initialising the sensor with dht.begin(): https://github.com/hamishcunningham/fishy-wifi/blob/c7e3cb415f0ee15786c1d1fe610efdc433e5f889/ardesp/waterelf32/waterelf32.ino#L816-L823

Adding a delay(2000) before line 816 seems to work as a fix for this.

layerzerolabs commented 6 years ago

My reading of that datasheet (note however we are using AM2302, a clone of DHT22) is that the period between readings has to be >2s. However, the datasheet also states "When power is supplied to sensor, don't send any instruction to the sensor within one second to pass unstable status." Can you test with a 1s delay? Also I see that there are a number of startup functions such as startAP and startWebServer that don't depend on the peripherals - could we move the startPeripherals function after those to achieve a delay? Additionally we could move this sensor to the end of the startPeripherals function to get a bit more of a delay? Can you test and report back? Ta!

Eroc33 commented 6 years ago

This may be related to an issue I have been investigating where I discovered that turning off WiFi significantly increases the reliability of reading the DHT and Water temperature sensors. I have some idea of what's going on but it may need further investigation.

Eroc33 commented 6 years ago

This issue in the DHT library may also be relevant: https://github.com/adafruit/DHT-sensor-library/issues/48 (implementing this change appears to have decreased the failure rate of my sensor)

EDIT: This makes the sensor work 99% reliably in the example provided with the library (it was pretty intermittent otherwise), but it still doesn't get detected by the waterelf code.

hamishcunningham commented 6 years ago

Sounds like a timing issue if WiFi impacts on reliability, which was typical ESP8266 but is a bit more surprising on (dual core) ESP32. Perhaps having the handler for webserver requests in the main loop is part of the problem?

layerzerolabs commented 6 years ago

I'm shocked that despite excellent investigation and the simplicity of the fix suggested over at adafruit that it hasn't been implemented! Well found - have you tried increasing the second delay to 50us as well?

Eroc33 commented 6 years ago

One solution I have found that works for the water temperature sensor, but doesn't have much effect on the DHT readings to to place the library calls doing soft serial in a critical section (which disables ISRs and task pre-emption). As far as I can tell the esp8266 uses co-operative tasks (as does the original arduino for which the libraries are designed), but the esp32 uses pre-emptive tasks so I suspect the issue is that the soft-serial routines are being pre-empted by the task running the WiFi stack which would disrupt the timing, but also explain why this was not seen on esp8266.

Eroc33 commented 6 years ago

I've finally tracked down what seems to be the real source of the problem, which is that the arduino functions noInterrupts and interrupts are defined to be no-op in esp-arduino core, there is an issue open for this at https://github.com/espressif/arduino-esp32/issues/832, but for now you can modify DHT.h in the DHT library changing the InterruptLock class to the following:

class InterruptLock {
  public:
   InterruptLock() {
    #ifdef ESP32
        portDISABLE_INTERRUPTS();
    #else
        noInterrupts();
    #endif
   }
   ~InterruptLock() {
    #ifdef ESP32
        portENABLE_INTERRUPTS();
    #else
        interrupts();
    #endif
   }
};

(I also tried putting portDISABLE/ENABLE_INTERRUPTS() around the whole section of code using the DHT in waterelf, but for some reason that didn't work, which is what threw me off of finding this answer for so long)

cgmcintyr commented 6 years ago

@Eroc33 nice work!

As a small change, looking into the FreeRTOS documentation they seem to recommend using taskENABLE_INTERRUPTS() and taskDISABLE_INTERRUPTS() over portENABLE_INTERRUPTS() and portDISABLE_INTERRUPTS().

Looking at the source code for tasks.h these are just macros that essentially alias their port equivalents, however they are meant to act as interfaces so we should probably use them :)

layerzerolabs commented 6 years ago

Great stuff - nice to get the interface macros even for a hotfix...