Author Topic: LowPower::idle isn't working with TIMER0_ON  (Read 3350 times)

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
LowPower::idle isn't working with TIMER0_ON
« on: October 10, 2017, 09:35:09 AM »
Hi all !
First, I use moteino R6
I use millis() function in my sketch and don't want to lose timetracking even when sleeping. But I also want to save power between loops, so I tried to use the LowPower library.
As I understand, if I want the millis() counter still running, I need to keep TIMER 0 running, so I use the LowPower::idle function to "sleep" a defined amount of time before wake up my sketch.
If I use TIMER0_OFF, the moteino is sleeping accordingly to the period_t enum given to the function, but millis() is also sleeping,
But if I use TIMER0_ON, the moteino stay awake and idle function has no effect...
Am I missing something here ?

this code does nothing :
Code: [Select]
LowPower.idle(SLEEP_2S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_ON, SPI_OFF, USART0_OFF, TWI_OFF);

this code is working :
Code: [Select]
LowPower.idle(SLEEP_2S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);

Thks to help me.
« Last Edit: October 10, 2017, 09:40:31 AM by Uncle Buzz »

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #1 on: October 10, 2017, 03:01:05 PM »
Idle normally means the processor's main clock is stopped but other peripheral clocks carry on (if enabled). As soon as there is an interrupt the processor clock will start up again. I think TIMER0 is updating the mills counter via an interrupt, so the first interrupt it gets will wake it up. I think you would need to check conditions to determine whether the loop should run or whether it needs to be put back to idle sleep, in which case it'll wake up every millisecond, update the counter, and go back to sleep again.

Mark.

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #2 on: October 12, 2017, 04:10:18 AM »
Thank you for your answer, the interrupt of TIMER makes sense and it's why sleep is stopped after 1 ms.
Is there another way to determine how much time the μ was sleeping? how the WDT measures time? Is it possible to retrieve some information from WDT?

Thank you.

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #3 on: October 12, 2017, 05:10:48 PM »
No registers for the WDT counter, it uses an internal 128kHz (inaccurate) timer and just selects a tap from that internal counter to trigger the watchdog reset/interrupt.

It all depends on what resolution, accuracy and power saving you really want from this. If it's to maintain an accurate real time clock and you want to save as much power as possible by sleeping then I think bodging on a 32kHz watch crystal and using TIMER2 might be your only option. If you can live with lower resolution and accuracy you could use the 128kHz low power internal clock to clock a timer while asleep. Keeping the normal timers going though using a prescaled system clock will use a lot of power in comparison. I think someone posted something about the 32kHz watch crystal somewhere.

Mark.
« Last Edit: October 12, 2017, 05:37:16 PM by perky »

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #4 on: October 12, 2017, 06:17:46 PM »
I think someone posted something about the 32kHz watch crystal somewhere.

Mark.

I haven't posted anything about it, but I did successfully get one working with a 328p DIP set to run at 8MHz on its internal oscillator.  You have to do this because you need OSC1 and OSC2 to connect to the watch crystal.  The power savings was not that impressive to me though.  I believe it was around 450uA while in power save.  I don't have an oscilloscope so I don't know how accurate the 1s waking was, but it did seem to be a reliable wakeup signal.

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #5 on: October 12, 2017, 08:06:51 PM »
I haven't posted anything about it, but I did successfully get one working with a 328p DIP set to run at 8MHz on its internal oscillator.  You have to do this because you need OSC1 and OSC2 to connect to the watch crystal.  The power savings was not that impressive to me though.  I believe it was around 450uA while in power save.  I don't have an oscilloscope so I don't know how accurate the 1s waking was, but it did seem to be a reliable wakeup signal.

Power-save should shut the main system clock down and all other clocks other than the asynchronous clock, leaving only the watchdog and TIMER2 in asynchronous mode running. In theory this should get you down to a few uA, those measurements for power-save mode are clearly not right, but they are consistent with the datasheet for idle sleep (figure 33-10) ;)

Mark.

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #6 on: October 16, 2017, 05:33:43 AM »
If you can live with lower resolution and accuracy you could use the 128kHz low power internal clock to clock a timer while asleep.
lower accuracy could be sufficient, so how using the 128kHz internal clock to evaluate time during sleeping ? Is it only a software solution based on stock moteino or does it need some hardware modifications ?
Thank you.

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #7 on: October 16, 2017, 08:17:59 AM »
The 128kHz oscillator is what the watchdog timer uses to wake up after say 1 second so the solution would be strictly software on a stock Mote.  In your sleep loop, you would increment a second counter right as you wake up.  Then check to see if it is time to do something.  If not, go right back to sleep.  In this scenario your Mote could be awake as little as 5uS every second and still have a rough sense of how much time has elapsed.  I believe this oscillator is +/-10%.

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #8 on: October 16, 2017, 09:23:26 AM »
ok, that's what I did... but there is no way to know how much time was spend sleeping if wakeup is caused by an extern interrupt (I use 2 buttons on interrupt to control my sketch). I have to deal with this non previsible event or accept very inaccurate time evaluation.
I will use extern clock next time to use with TIMER2.
If you see another way to obtain an approximate evaluation of time in this case, thank you to point me at.

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #9 on: October 16, 2017, 10:57:31 AM »
Yes you are right given that.  Maybe you need to add a 70-cent real time clock to your project then.  That would let you sleep the sleep of the dead, still wake for your button interrupts and not lose track of time.

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #10 on: October 16, 2017, 02:51:54 PM »
I've been doing some research on RTCs lately and I've identified this one https://www.nxp.com/docs/en/data-sheet/PCF8523.pdf  and https://www.digikey.com/product-detail/en/nxp-usa-inc/PCF8523T-1118/568-5306-1-ND/2530784 as one to experiment with since it is 150nA but still offered in a package that I can hand-solder.  I designed this uber cheap little board to make it breadboard friendly so I can experiment easily: https://PCBs.io/share/zvq1Z which is *way* less expensive than this which also works: https://www.sparkfun.com/products/13655 but why pay $3 + shipping instead of $0.63 shipped?
« Last Edit: October 16, 2017, 02:55:19 PM by ChemE »

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #11 on: October 16, 2017, 04:37:01 PM »
ok, that's what I did... but there is no way to know how much time was spend sleeping if wakeup is caused by an extern interrupt (I use 2 buttons on interrupt to control my sketch). I have to deal with this non previsible event or accept very inaccurate time evaluation.
I will use extern clock next time to use with TIMER2.
If you see another way to obtain an approximate evaluation of time in this case, thank you to point me at.

You could use TIMER2 and clock it with the 128kHz low power clock while it's asleep if the timing inaccuracy is acceptable. Unfortunately TIMER2 is only 8 bit so if you need resolution as well you might need to use some overflow interrupts to regularly update the elapsed time, but that obviously can be 256 times your resolution. If you need real time and the lowest power possible with sleeping then there's no other option but to use an external 32kHz watch crystal with TIMER2 and use the 8MHz internal clock for the main system clock. If you choose to run TIMER2 while asleep (which you would in both those scenarios), then you can dispense with the watchdog timer for waking up, you could use the timer instead.

Mark.
« Last Edit: October 16, 2017, 04:42:17 PM by perky »

perky

  • Hero Member
  • *****
  • Posts: 873
  • Country: gb
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #12 on: October 16, 2017, 04:55:58 PM »
BTW using an external watch crystal is exactly what I do with another project that uses an xmega D device. That has a 16 bit asynchronous counter that allows up to 16 seconds with 0.25ms resolution, and I use that both to maintain a real time clock for the LCD display and accurately time wake ups for timeslots down to 0.25ms. There are subtlties with the asynchronous register updates you need to watch out for but my clock is accurate to about 1 second a day with a 10ppm crystal.

Mark.
« Last Edit: October 16, 2017, 04:58:03 PM by perky »

Uncle Buzz

  • Full Member
  • ***
  • Posts: 146
  • Country: fr
Re: LowPower::idle isn't working with TIMER0_ON
« Reply #13 on: November 21, 2017, 05:22:02 AM »
Thank you for your advices !

I know what I'll do next time. for this PCB, I already have an RTC, but didn't anticipate this need, I only have I2C and power connected.
So, what I did is to predict how many ms have passed during sleeping mode and correct the millis() counter at wakeup, based on WDT clock. As the precision is about 10%, I check the new millis() counter with my RTC, and correct it if there is more than 2s of desync.
I added a dynamic coefficient to correct the millis() counter from WDT, I increase or decrease this coefficient each time I need to sync millis() with RTC, depending of how often I have to resync, so, after some resync the correction from WDT is quite accurate (enough for my needs).

Another question about TIMER accuracy and consumption :
As I don't use any PWM, I tried to power off TIMER1 and TIMER2 permanently since only TIMER0 is needed to micro and millis counter. But when I do that, it's like TIMER0 is not accurate, it's like  it uses the same clock as WDT.
Do you know if TIMER0 depends of a clock used by TIMER1 or TIMER2 ? If yes, which one, and which one I can stop permanently to reduce consumption and keep accurate TIMER0 ?

Thank you.