DeepBlueSky 8 Posted January 8, 2015 Share Posted January 8, 2015 I decided to build an air humidity alarm so I know when to air (you can also attach a piezo buzzer, which is more recognizable in some situations). I found/use this lib. Chip: MSP430G2452 (this I had left, I think it's overkill for this task) -- Problem solved. Thanks to all who helped. To solve the problem I decided to comment out if (millis() < _lastMillis) { return _lastResult; // return last correct measurement } _lastMillis = millis() + 1; in DHT22_430.cpp because I think the millis() doesn't run below LPM1. I also don't need the millis() because I already wait in interrupts (3-10 seconds, enough for this sensor which needs at least 1-2 seconds time). I also commented out "delay(250);" and changed "delay(20);" to "delay(10);" to reduce unnecessary power consuming cycles. Tested and works. BTW: don't forget to comment out "#define DEBUG" in DHT22_430.h (but it will give you a compile error anyway when using timer ("multiple definition of `__isr_9'")). That's it, no further changes (if I would have made many small changes to the lib, I'd have attached the two lib files in an archive file). -- Power consumption: In LPM3: 10 Quote Link to post Share on other sites
roadrunner84 466 Posted January 8, 2015 Share Posted January 8, 2015 I don't know the DHT22 library, so I can't be really sure. But as far as I see, you should be able to drop into LPM3, since you're only using the ACLK in the down time. Maybe the DHT22 needs a few milliseconds between wakeup and .get()? Also, delaying inside an interrupt service routine is deemed bad practice. Instead, set a flag and return with clear on exit (__bic_status_register_on_exit(LPM3_bits)) void loop() { _BIS_SR(LPM1_bits); flag = mySensor.get(); h = mySensor.humidityX10(); //t = mySensor.temperatureX10(); if (flag) { if(h>=485) { digitalWrite(LED,HIGH); //on delay(5); //this maybe could be optimized without using delay() but since this is only a few ms, I think it's ok for now digitalWrite(LED,LOW); //off frequency=3; } else frequency=10; } } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_A0 (void) { if(wakeupCounter % frequency == 0) { //check every 10 seconds and sleep deep meanwhile __bic_status_register_in_exit(LPM3_bits); wakeupCounter=0; } wakeupCounter++; } Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 8, 2015 Author Share Posted January 8, 2015 Your code gave this error: error: '__bic_status_register_in_exit' was not declared in this scope In the msp430g2452.h header file I found ... #define LPM3 _BIS_SR(LPM3_bits) /* Enter Low Power Mode 3 */ #define LPM3_EXIT _BIC_SR_IRQ(LPM3_bits) /* Exit Low Power Mode 3 */ ... and replaced the line with LPM3_EXIT. Is this the same as your line? It compiles but unfortunately does not improve power consumption (700 Quote Link to post Share on other sites
cubeberg 540 Posted January 8, 2015 Share Posted January 8, 2015 Regarding the sleep time - Adafruit says you shouldn't query them more often than every second or two. They're not very fast devices. https://learn.adafruit.com/dht/overview Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 8, 2015 Author Share Posted January 8, 2015 Yes, that's why it is set to every 3 seconds. The delay(100)s come after this time has passed. But there's a problem which I tracked down: Using e.g. TACCR0 = 12000 and the if(wakeupCounter % frequency == 0) and setting any frequency doesn't work at all, even 10s. What also doesn't work at all is setting TACCR0 = 60000 and removing the if(...), so it only checks every 5s (which should be more than enough). By "at all" I mean that the sensor just doesn't return a valid value. It seems that the sensor needs a busy wait of approx 1 second (it's like only this delay(1000) starts the time of the sensor, which is, as already mentioned, "every second or two", which is no problem for me, I don't need a super fast sensor) which of course defies the purpose of sleep. So although this works, it is not a solution (edited my prior reply code too so it is more correct): void loop() { _BIS_SR(LPM3_bits); } ... delay(1000); flag = mySensor.get(); h = mySensor.humidityX10(); //t = mySensor.temperatureX10(); if (flag) { Any suggestions? Quote Link to post Share on other sites
roadrunner84 466 Posted January 9, 2015 Share Posted January 9, 2015 I made a typo: use __bic_status_register_on_exit instead of __bic_status_register_in_exit' I think your sensor may be dependent on SMCLK, which is turned off during LPM3. Maybe it's dependent on time deltas from Energia. Does the system work when dropping to LPM1 instead of LPM3? If it does not work in LPM1, but does work when adding the 1 second delay after waking from LPM1, then it's the library/driver. There could be some dependency on the Energia framework throwing you off. Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 9, 2015 Author Share Posted January 9, 2015 I tried your version again and it compiles with __bic_status_register_on_exit, but has the same problem as mentioned earlier. Yes, it does work in LPM1, no delay(1000) needed (it's the version in my first post). But when using LPM3 it only works with delay(1000) (as in my post #5). Without the delay in LPM3 I can wait as long as I want, the sensor still doesn't return any valid value. Quote Link to post Share on other sites
grahamf72 169 Posted January 9, 2015 Share Posted January 9, 2015 It looks like you are using rei_veilo's DHT22 library. Did you edit the header file and disable the DEBUG ? The reason I ask, by default his library uses the serial port to output debugging information. Because the 2452 lacks hardware serial, it uses timer_serial, and the 2452 only has 1 timer. If you are trying to use the timer to manage your wake times, it will clash with the timer that timer_serial uses, and hence you'll see funny behaviour like what you are seeing. I haven't actually used your code to see if this is the problem, but it is what jumps out at me from reading the thread. -------------- Edit -------------- Had another look, and I'm almost certain that the serial debug code in the library is the source of your frustrations. You are using P1_2 for your sensor, which is the TX pin for the 2452's timerserial library. I'd say that what's happening is the serial code in the debug is sending data on P1_2, which is messing up the DHT22. The reason you need the 1 second delay in LPM3, is to give the timerserial library time to clear the serial queue. Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 9, 2015 Author Share Posted January 9, 2015 I edited the cpp file and commented out the #if defined(DEBUG)...#endif, as I was indeed having problems compiling the code, which I should have mentioned, sorry. Quote Link to post Share on other sites
Rei Vilo 692 Posted January 9, 2015 Share Posted January 9, 2015 What does the data sheet say? Some sensors use a calibrated heated part to proceed with the measure, e.g. humidity, CO2, dust, ... Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 9, 2015 Author Share Posted January 9, 2015 Touching the sensor it seems rather cold, no warming. The thing is it needs this delay(1000) only in LPM3, not LPM1. Maybe clock related? In LPM3 SMCLK is, as roadrunner84 also mentioned, turned off, but I don't know. It's strange. LPM2 BTW is same as LPM3. From msp430g2452.pdf: Quote Link to post Share on other sites
grahamf72 169 Posted January 10, 2015 Share Posted January 10, 2015 I've had a bit of a play, and the following code (a mash up of yours and roadrunner's) is working fine, going into LPM3 with about 50uA according to my meter. Note that I have edited the header for the DHT22 library to comment out the #define DEBUG, and that my data pin for the DHT22 is on P1.4. // Include application, user and local libraries #include "DHT22_430.h" /// /// @brief Pin for DHT22 signal /// @n Connect /// * pin 1 (on the left) of the sensor to +5V /// * pin 2 of the sensor to DHTPIN /// * pin 4 (on the right) of the sensor to GROUND /// @n Place a 10k resistor between pin 2 (data) to pin 1 (power) of the sensor /// #define DHTPIN P1_4 DHT22 mySensor(DHTPIN); int wakeupCounter; int frequency; #define LED P1_0 void setup() { TACCTL0 = CCIE; TACCR0 = 12000; //1 second TACTL = MC_1 | TASSEL_1; for (int i=0;i<16;i++) //put all pins in INPUT, helps cut power consumption pinMode(i,INPUT); mySensor.begin(); pinMode(LED,OUTPUT); digitalWrite(LED,0); } void loop() { _BIS_SR(LPM3_bits); int flag = mySensor.get(); int h = mySensor.humidityX10(); //t = mySensor.temperatureX10(); if (flag) { if(h>=485) { digitalWrite(LED,HIGH); //on delay(5); //this maybe could be optimized without using delay() but since this is only a few ms, I think it's ok for now digitalWrite(LED,LOW); //off frequency=3; } else frequency=10; } } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer0_A0 (void) { if(wakeupCounter % frequency == 0) { //check every 10 seconds and sleep deep meanwhile __bic_status_register_on_exit(LPM3_bits); wakeupCounter=0; } wakeupCounter++; } Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 10, 2015 Author Share Posted January 10, 2015 I tried your code and also switched to your ports but it's the same without adding delay: LED does not blink if I breathe at the sensor. ("#define DEBUG" is commented out too). The sensor gets its data when restarting the chip but doesn't get its data when it's running/waking up when in LPM3 and without delay(1000). Maybe you should test again. What seems to work is when I comment out if (millis() < _lastMillis) { return _lastResult; // return last correct measurement } _lastMillis = millis() + 1; Because in my case I do a "millis()"/waiting by entering the interrupt routine every 10s. Quote Link to post Share on other sites
grahamf72 169 Posted January 10, 2015 Share Posted January 10, 2015 I think I've solved it. Mine is working, even when I changed to P1_2. But then I noticed that it was blinking about once every second, not once every 3 seconds as it should. That indicated to me that the clock it was using for the timer was about 3x faster than VLOCLOCK should be. What is 3x faster than VLOCLOCK? The 32768 crystal, and it just so happens my launchpad has the crystal. Grabbed a launchpad without the crystal and I got the failure. Then I realised, nowhere in the above code is the clock source for ACLK configured, so it is probably defaulting to the crystal. I added BCSCTL3=LFXT1S_2; to the setup() just before the lines to configure TimerA, and now it is running with approx 3 seconds between blips as expected on a board without the crystal. Sent from my iPad using Tapatalk Quote Link to post Share on other sites
DeepBlueSky 8 Posted January 10, 2015 Author Share Posted January 10, 2015 Had another look, and I'm almost certain that the serial debug code in the library is the source of your frustrations. You are using P1_2 for your sensor, which is the TX pin for the 2452's timerserial library. I'd say that what's happening is the serial code in the debug is sending data on P1_2, which is messing up the DHT22. The reason you need the 1 second delay in LPM3, is to give the timerserial library time to clear the serial queue. I'm not sure / I don't think so: Before I decided to ask I already commented out the debug code because it gave me a compile error right away "multiple definition of `__isr_9'". Using different ports also works (DHTPIN P1_3, LED P1_2) when millis() (see below) is commented out. grahamf72, you indeed solved it for yourself As already said your code doesn't work for me. However, when I comment out if (millis() < _lastMillis) { return _lastResult; // return last correct measurement } _lastMillis = millis() + 1; in DHT22_430.cpp it seems to work It looks like the millis() can't run in LPM2 / LMP3. I also commented out "delay(250);" and changed "delay(20);" to "delay(10);" to reduce unnecessary power consuming cycles. And what also works now is the code pattern suggested by roadrunner84. I think the problem is hereby solved First post edited. Can this be moved back to projects? Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.