Millis and sleep
-
Re: gw.sleep(...) and milis()
I have a use case on an ATMega328 where I want to know the millis, also after a sleep.I have been thinking about it and this crossed my mind:
A solution could be to modify the millis() function. If it is called while the sleep function was active (that can only happen in an ISR I guess) it could set the millis counter to the saved millis at sleep start, plus the elapsed time since sleep start (i.e. the sleep timer count). It should also do so at sleep end.
Unfortunately I do not know much about the internals of the MySensors and Arduino software, so my suggestion might be complete nonsens.My preferred solution would be the use of a real time OS, But that seems very complicated.
-
@cvdenzen the atmegas will no longer increase their millis counter on sleep. The sleep time, or approximate time elapsed during sleep, is using the watchdog timer and can therefore be off as much as 8 seconds!
It depends on your application if this is acceptable or not.
If not, you have to revert to a different timing method (eg external timer) or use a different cpu.
-
What is the problem in modifying the millis() function in the way I proposed? Why is it impossible to add the watchdog count to the millis counter?
I know that currently this is not supported, but it would be a nice feuture to have.
-
@cvdenzen I'm not saying it's impossible, I'm warning you that the result will be very inaccurate.
Everytime your node sleeps, it's millis counter would rely on the watchdog and each time an error will be introduced. Worst case this will be 8 seconds per sleep call, which adds up rapidly.
But, if that's acceptable to your use case, please go ahead!
-
@Yveaux I mean to modify the MySensors code, adding a new feature to MySensors. The accuracy can be very good if it is implemented in the right way.
Something like this, ignoring some details to be solved:
Sleep() sets a variable inSleep to true, starts the watchdog counter and goes to sleep.
When millis() is called and inSleep is true, millis() must add the elapsed time (as calculated from the watchdog timer) to the millis counter and return this value. This can only happen in an ISR.
Before returning, the sleep() function adds the elapsed time (as calculated from the watchdog timer) to the millis counter and sets inSleep to false, in one atomic action.Accuracy can be as good as one or two millis per sleep I guess, max one at start and max one at stop.
-
@cvdenzen said in Millis and sleep:
Accuracy can be as good as one or two millis per sleep I guess
No it cannot. Look up the watchdog specs on the atmega datasheet.
When the atmega is sent to sleep for 8 seconds and is woken by an interrupt it does not know how long it actually slept. Could be 1ms, could be nearly 8 seconds.
This is also documented in the interface : https://github.com/mysensors/MySensors/blob/b9d9cc339659f724aa94d4108fc5289a720d1bcd/core/MySensorsCore.h#L393If it is not woken by an interrupt, timing will be more precise, but possibly still a lot less accurate than the regular atmega timer as the watchdog uses an rc oscillator.
-
instead of using sleep() and the watchdog timer, you could use a 32768 Hz watch crystal and keep timer T2 running during "sleep". I have built some simple window sensor nodes that consume 10µA when using the sleep() function, and 11µA when using a timer2 interrupt every 20ms, and set_sleep_mode(SLEEP_MODE_PWR_SAVE);
With the external watch crystal, T2 keeps running during "sleep", whereas the sleep mode used by the MySensors sleep() functions stops all timers, afaik.
-
Finally, after reading the data sheet, I see the problem with the watchdog timer: its value can not be read.
Timer2 would be a nice option. I will have a look at that. Thanks for your answers!
-
I'm using the sleepRemainingMs function for that and it works if accuracy is not important