Non-blocking interrupt driven DHT22 library

I have it to were it seems stable and that includes adding in another IO pin interrupt for a dust sensor.

The only change I made was to move a char array I used to populate the string for the UDP sending. It was 64 bytes in length so I moved this to global. It may have been a stack corruption issue.

Anyway, using the calculation outside the interrupt also helps. I am sitting here watching UDP data every 5 seconds with the DHT22 being polled every 2.5 seconds :smile:

Thanks for your work on this Paul. It has saved me a few days writing code.

Right, now I can start to add the other parts of the weather station.

Ah damn. It was still sending UDP this morning but the DHT22 was showing readings of -5.0 for both readings.

Resetting the core didn’t solve it but after removing power and re-starting it was working again.

Something in the DHT22 is hanging. Don’t look like I am going to stay with this sensor as it is just not reliable enough. Even though the Sensirion SHTxx devices are more expensive, they do work reliably.

@v8dave, I’m having the exact same results and no clue why the DHT22 stalls. The blocking version works fine but something about the interrupt is affecting it.

Hi Paul, I have a logic analyser and I will hook this up to the DHT22 line and see what it looks like when working and then when it stalls.

Right now I have changed the sampling time to 10 seconds and so far it has been running for over 3 hours without any errors. I also made some changes to the code which if still working when I awake tomorrow I will let you know what they are but basically I reset the IO pin to output and set it high on completion of the data reception or any error.

PS… Running on 3.3V with 2K2 pullup resistor.

@v8dave, I have a logic analyzer also but I could not figure how to setup the trigger for when it fails! I look forward to your results :smile:

@v8dave, I have a theory and a solution for the stalling DHT22. First, the theory. I believe that if an interrupt occurs during the ā€œwake upā€ portion of the code, specifically the delay 40us part, then this could delay the setting of the DHT pin to INPUT mode. So the DHT will respond with the pin being an OUTPUT causing a ā€œcollisionā€ and cause it to go into stall… maybe.

The solution. I now power the DHT from a Spark data pin! The pin gets set to HIGH in init() to power the DHT. If acquire() or acquireAndWait() take too long, I reset the DHT by taking the power pin LOW for some milliseconds (I am still working on figuring out the shortest possible time) and HIGH again. This restarts the DHT.

I have just started testing and things look good so far. If this approach works, I will change the the constructor to pass the reset pin. Also, another member did a PR to make the library work with a DHT11 sensor so I will roll that in as well. Stay tuned! :smile:

@v8dave, it seems to be working!! I had several ā€œfailuresā€ of the DHT22 and the recovery mechanism works just fine :stuck_out_tongue: Now I will see what the shortest power off pulse I can use to reset the DHT22. :smile:

Nice work. Look forward to checking it out tomorrow. That’s assuming the code changes appear during the night. :slight_smile:

I was also thinking, could you disable interrupts just for the 40us bit? My dust sensor is in the ms range between pulse so it would not be affected by the short disable.

@v8dave, the noInterrupts() command only disables user interrupts, not the ones used by the firmware. I tried it and it still failed and I don’t want to play with the CC3000 interrupts. So far, the code recovers from every failure and I am still playing with the power cycle timing. :smile:

I just wanted to chime in and say I’m having the same infinite loop issue (I assume it’s an infinite loop anyways). The code locks up after a few seconds (or less) to a few minutes, but it reliably locks up unless I comment out the DHT22 stuffs. I’ve tried with various pull-ups to no avail.

I do have a couple of questions about the example code and usage in general. In the example, you have:

DHT22.acquire();
while (DHT22.acquiring());```

Is that the same as `DHT22.acquireAndWait()`?  Instead of running the while loop and potentially hanging up code, would I want to try something like this instead?

void loop() {
if(DHT22.acquiring()==false) {
// Code here for doing all the fun temperature and humidity stuff
DHT22.acquire();
}
}```

Or would I want to use DHT22.getStatus() and check for IDDHTLIB_* in an if or switch statement in each loop()?

:eyes: :heart: @peekay123

Hi Paul, when will you release the code for me to try out? :slight_smile:

@v8dave, yes I will put the code up on my repo for you to test. Oddly, I am still having problems with the audo-recovery it seems. After leaving the Core running all day and working fine, it seems to have stopped publishing overnight. The core is still running abut not publishing.

I will be writing a new version of idDHT that will work differently:

  • It will support both DHT11 and DHT22 sensors
  • The constructor call will include the sampling time (default 1s for DHT11 and 2s for DHT22) and, optionally, the DHT power pin for auto-recovery of a stall
  • The DHT object obtain readings at specified intervals and if timeout on DHT device occurs, ā€œrebootā€ the device to recover automatically
  • User will call updateDHT() in loop() so it can manage its timers - the call will pass back a status like NEW_READINGS_READY, STALL_RECOVERY, along with the ISR errors

This will allow DHT library to not use any delay() calls and be truly non-blocking. Any thoughts? :smile:

Funny how I was trying to use the same library this week and the core kept timing out sometimes and all the testing pointed to the DHT22 library. I ended up going with a simpler io polled library instead of the interrupt based one to get past it for now and it works like a champ. I’ll keep an eye on the changes to the dht22 library.

Sounds good to me. Can’t wait.

Did you upload this yet as I checked the existing github and can't find anything with the changes you mentioned.

@v8dave, I was getting odd behaviour from the code and decided to not post it. Instead, I will be posting the new non-blocking code that will include the DH11 stuff as well as stall recovery.

Great. Looking forward to testing it. In the mean time I am completing the rest of the code for the other sensors.

Hi,

I can confirm that the DHT22 stalls in some occasion. Using an oscilloscope I found some issues:

  1. running the data wire on a digital pin (D0-D7) the core produces during powerup or awake from deep-sleep a short low pulses wich triggers the DHT22. In this situation the pin is set as outport and the DHT22 can not pull the signal low. Using a analog pin does not show this behavier.

  2. going into deep-sleep mode also toggle the data line with very short pulse which triggers the DHT22 again.

  3. the code has some problems because if the DHT22 stalls, no interrupt is generated and the code hangs in the DHT22.acquiring() procedure.

  4. There are different quality of this sensor on the market. I running two off them on Arduino (5V) since months. Some say using 3V3 power gives more problem then 5V.

I use now the DHT22.acquireAndWait() procedure and added some timeout check

int idDHT22::acquireAndWait() {
Ā Ā Ā  unsigned long msStart = millis();
Ā Ā  Ā acquire();
Ā Ā  Ā while(acquiring()) {
Ā Ā  Ā Ā Ā Ā  if ((millis() - msStart) > 1000){
        detachInterrupt(_sigPin);
        _status = IDDHTLIB_ERROR_DATA_TIMEOUT;
        _state = STOPPED;
Ā Ā  Ā Ā Ā Ā Ā break;
Ā Ā  Ā Ā Ā Ā  }
Ā Ā  Ā };
Ā Ā  Ā return getStatus();
}

Because an analog pin is input by default, I made some code modification in the DHT.init and DHT22.acquire() procedure

void idDHT22::init(int sigPin, void (*callback_wrapper) ()) {
	this->_sigPin = sigPin;
	this->isrCallback_wrapper = callback_wrapper;
	_hum = 0;
	_temp = 0;
	pinMode(_sigPin, INPUT);
	/*
	//pinMode(sigPin, OUTPUT);
	//digitalWrite(sigPin, HIGH);
	*/
	_state = STOPPED;
	_status = IDDHTLIB_ERROR_NOTSTARTED;
}



/*
* Toggle the digital output to trigger the DHT device
* to send us temperature and humidity data
*/
pinMode(_sigPin, OUTPUT);
digitalWrite(_sigPin, LOW);
delay(18);					//Spec: min 1ms
digitalWrite(_sigPin, HIGH);
pinMode(_sigPin, INPUT);
delayMicroseconds(40);			//Spec: 20-40us

The pullup is made with a 10k resistor

The sensor has stalled twice today running it on 3V3. Now I testing 5V on power pin and data line pullup to 3V3 to be compatible with analog pin.

There are many datasheet available and the min. voltage for this sensor goes from 3V to 3.6V

@digixx, I am still working on my true non-blocking and stall recovering library. I am in the debugging phase and hope to be finished very soon. I still don’t understand why the DHT22 stalls in the first place which really bothers me. If anyone has any thoughts on that, it would be good to brainstorm. :smile: