Author Topic: LowPower.powerDown and millis()  (Read 10524 times)

d00m178

  • Jr. Member
  • **
  • Posts: 82
LowPower.powerDown and millis()
« on: November 04, 2019, 10:56:16 AM »
Hello

I want to check the uptime of Moteino (then I will send it via LoRa)

so I have in code millis() function

Code: [Select]
      uptime = uptime+(millis()/1000);
      srv_data.uptime = uptime; //server uptime in _seconds_

then I send this srv_data via radio.

it works only if Moteino doesn't use sleep mode.
If Moteino has a sleep mode via
Code: [Select]
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

I assume that it sleep 8 seconds
1 time per cycle.
But then I receive wrong uptime variable - it a far less that real time from the start of Moteino.
It seems that I need take into account the time when Moteino is sleeping.
So I decided just add +8sec to uptime but this lead to another issue - uptime start to grow very fast and after 5 real minutes it can show about 10 min!
Please advice..

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: LowPower.powerDown and millis()
« Reply #1 on: November 04, 2019, 12:07:08 PM »
I advise not to assume anything, instead take measurements.
You know that while it sleeps, the timers are OFF. It then takes time to start everything up and then go back to sleep. That is overhead. So it's not going to be exactly 8 seconds.
Also, you have to ensure that nothing else is waking it, except the watchdog.
You can look around at some of the example sketches of how the "8 second sleep time" is accounted for. An example here for the mailbox notifier which reports "time ago" but I don't expect high accuracy from it.
Also you need to be ready to accept that sometimes if the mote is awaken in the middle of the 8 second cycle then that will depreciate accuracy if that's what you're looking for.
In general you should not try to keep time using the atmega timers, they are inaccurate even if you don't sleep. Even the best crystals have drift with temperature and age. It can be quite bad.
Instead, keep accurate time at a central node or a gateway, using NTP, or if you really have to an RTC.

d00m178

  • Jr. Member
  • **
  • Posts: 82
Re: LowPower.powerDown and millis()
« Reply #2 on: November 05, 2019, 11:07:48 AM »
thank you for advice.
Im not going to keep the time on the node.
Just want to know the uptime of this node - how many seconds it is in powered on state.
but seems even if I add some "drift" to the calculated uptime it anyway start to hurry or late.
and after hours or day it will definitely show wrong uptime data.

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: LowPower.powerDown and millis()
« Reply #3 on: November 05, 2019, 01:02:30 PM »
That's if you consider uptime to include sleep time. Are you "uptime" when you sleep?

Instead what I do, to keep uptime, I send a simple "START" message to my gateway, which logs it with a timestamp. So I know when it came online, or when it last restarted. Simple, precise, no coding headaches and assumptions.

MojaveTom

  • NewMember
  • *
  • Posts: 24
  • Country: us
Re: LowPower.powerDown and millis()
« Reply #4 on: February 15, 2021, 11:02:33 PM »
Sorry to resurrect this old thread, but it is relevant to what I have to say.

As Felix points out, if any interrupt comes along while you are in powerDown, you will wake the CPU and exit the powerDown routine.  In my application, I want sample my sensors at some reasonably consistent interval, but the time variable that is used to keep track of elapsed time in the mailbox code and in the motion mote code becomes very inaccurate for each interrupt.

As I see it, the problem is that when the CPU wakes up in powerDown it doesn't know which interrupt awakened it, so it just assumes that it was the WDT.  Since the interrupt service routine for the WDT is in that same module, it is easy to add a static volatile bool WdtIsrServiced = false; that is set when the WDT interrupt is entered, and cleared when the powerDown function first sleeps the CPU.  The CPU is just re-slept if it is awakened and the WdtIsrServiced is still false.  When the WdtIsrServiced flag is true, the powerDown function exits as usual.

For my test case, a sketch similar to MotionMote, with this mod to powerDown, I was off by about 20 seconds over the course of 6 minutes.  For the purpose of sampling sensors at a reasonably consistent interval, this is good enough.

The other power saving functions in the Low-Power library could probably benefit from a similar strategy.  I plan to create a pull request for this purpose.

Tom

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: LowPower.powerDown and millis()
« Reply #5 on: February 16, 2021, 09:50:06 AM »
Tom, all true and very good points, if this solves the powerDown() unknown slept time that would be sweet!

MojaveTom

  • NewMember
  • *
  • Posts: 24
  • Country: us
Re: LowPower.powerDown and millis()
« Reply #6 on: February 16, 2021, 05:12:25 PM »
Felix,

I generated a pull request to Rocket-Scream/Low-Power.  I will also generate a pull request to LowPowerLab/LowPower.  I see that you are much more active on GitHub than Rocket-Scream seems to be.

Tom

MojaveTom

  • NewMember
  • *
  • Posts: 24
  • Country: us
Re: LowPower.powerDown and millis()
« Reply #7 on: February 16, 2021, 06:25:58 PM »
I tried to create a pull request for you, but got all bollixed up on GitHub.  The only file I changed is LowPower.cpp.  Here is a link to just that file on GitHub.

https://github.com/MojaveTom/Low-Power/blob/LowPowerLab/LowPower.cpp

Here's the commit message I used:

Quote
Restart sleep if WDT not what awakened CPU.

A volatile flag is set in the WDT ISR to show that the WDT interrupt
happened.  The flag is cleared in functions when not SLEEP_FOREVER
before the interrupt is enabled.  When an interrupt awakens the CPU,
the flag is checked and the CPU put back to sleep if the WDT interrupt
was not the cause of the awakening.  For the case of SLEEP_FOREVER,
the flag is set to "true" before the CPU is slept, and the functions
return when awakened by any interrupt.

Thanks for your patience,
Tom

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: LowPower.powerDown and millis()
« Reply #8 on: February 16, 2021, 07:36:13 PM »
Thank you Tom, I prep-ed a diff and I will have to chew on this a bit and consider how I might test it and cover all cases since WDT sleep is in use in many projects.

MojaveTom

  • NewMember
  • *
  • Posts: 24
  • Country: us
Re: LowPower.powerDown and millis()
« Reply #9 on: February 16, 2021, 11:42:13 PM »
I understand.  Testing can be difficult.  I don't have enough variety of systems to test it to any extent.

I will use my modded library in my projects.  I will let you know if I encounter any problems.

Tom