Computing stuff tied to the physical world

Tracking time in your sleep

In AVR, Software on Oct 18, 2010 at 00:01

No, this isn’t a story about bio-rhythms :)

One of the challenges I’ll be up against with Room Nodes is how to keep track of time. The fact is that an ATmega is extraordinarily power efficient when turned off, and with it a JeeNode – under a few microamps if you get all the little details right. That leads to battery lifetimes which are essentially only determined by self-discharge!

But there are two problems with power off: 1) you need to be 100% sure that some external event will pull the ATmega out of this comatose state again, and 2) you can completely lose track of time.

Wireless packets are of no use for power-down mode: the RFM12B consumes many milliamps when turned on to receive packets. So you can’t leave the radio on and expect some external packets to tell you what time it is.

Meet the watchdog…

Fortunately, the ATmega has a watchdog, which runs on an internal oscillator. It isn’t quite as accurate, but it’ll let you wake up after 16 ms, 32ms, … up to 8 seconds. Accuracy isn’t such a big deal for Room Nodes: I don’t really need to know the temperature on that strict a schedule. Once every 4 .. 6 minutes is fine, who cares…

There’s a Sleepy class in the Ports library, which manages the watchdog. It can be used to “lose time” in a decently accurate way, and will use the slowest watchdog settings it can to get it out of power-down mode at just about the right time. To not disrupt too many activities, the “millis()” timer is then adjusted as if the clock had been running constantly. Great, works pretty well.

It’s not enough, though.

As planned for the next implementation, a Room Node needs to sleep one minute between wakeups to readout some sensors, but it also needs to wake up right away if the motion sensor triggers.

One solution would be to wake up every 100 ms or so, and check the PIR motion sensor to see whether it changes. Not perfect, but a 0.1s delay is not the end of the world. What’s worse though is that this node will now wake up 14,400 times per day, just to check a pin which occasionally might change. This sort of polling is bound to waste some power.

Meet the pin-change interrupt…

This is where pin-change interrupts come in, They allow going into full power-down, and then getting woken up by a change on any of a specified set of pins. Which is perfect, right?

Eh… not so fast:

Screen Shot 2010 10 17 at 22.05.30

Q: What time is it when the pin-change occurred?

A: No idea. Somewhere between the last watchdog and the one which will come next?

IOW, the trouble with the watchdog is that you still don’t really track time. You just know (approximately) what time it is when the watchdog fires again.

If the watchdog fires say every 8 seconds, then all we know at the time of a pin-change interrupt, is that we’re somewhere inside that 8s cycle.

We can only get back on track by waiting for that next watchdog again (and what if the pin change fires a second time?). In the mean time, our best bet is to assume the pin change happened at the very start of the watchdog cycle. That way we only need to move the clock forward a little once the watchdog lets us deduce the correct moment. FYI: everything is better than adjusting a clock backwards (timers firing again, too fast, etc).

Now as I said before, I don’t really mind losing track of time to a certain extent. But if we’re using 8-second intervals to get from one important measurement time to the next, i.e. to implement a 1-minute readout interval, then we basically get an 8-second inaccuracy whenever the PIR motion detector triggers.

That’s tricky. Motion detection should be reported right away, with an ACK since it’s such an important event.

So we’re somehere inside that 8-second watchdog cycle, and now we want to efficiently go through a wireless packet send and an ACK cycle? How do you do that? You could set the watchdog to 16 ms and then start the receiver and power down. The reception of an ACK or the watchdog will get us back, right? This way we don’t spend too much time waiting for an ack with the receiver turned on, guzzling electrons.

The trouble is that the watchdog is not available at this point: we still want to let that original 8-second cycle complete to get our knowledge of time back. Remember that the watchdog was started to get us back out in 8 seconds, but that it got pre-empted by a pin-change.

Let me try an analogy: the watchdog is like throwing a ball straight up into the air and going to sleep, in the knowledge that the ball will hit us and wake us up a known amount of time from now. In itself a pretty neat trick to keep track of the passage of time, when you don’t have a clock. Well, maybe not for humans…

The scenario that messes this up is that something else woke us up before the ball came down. If we re-use that ball for something else, then we have lost our way to track time. If we let that ball bring us back into sync, fine, but then it’ll be unavailable for other timing tasks.

I can think of a couple solutions:

  • Dribble – never use the watchdog for very long periods of time. Keep waking up very frequently, then an occasional pin-change won’t throw us off by much.

  • Delegate – get back on track by asking for an ack which tells us what time it is. This relies on a central receiving node (which is always on anyway), to tell us how to adjust our clock again.

  • Fudge it – don’t use the watchdog timer, but go into idle mode to wait for the ack, and make that idle period as short as possible – perhaps 2 ms. IOW, the ACK has to reach us within 2 milliseconds, and we’re not dropping into complete powerdown during that time. We might even get really smart about this and require that the reply come back exactly 1 .. 2 ms after the send, and then turn off the radio for 1 ms, before turning it on for 1 ms. Sounds crazy, until you realize that 1 ms of radio time uses as much energy as 5 seconds of power down time – which adds up over a year! This is a bit like what TDMA does, BTW.

All three options look practical enough to consider. Dribbling uses slightly more power, but probably not that much. Delegation requires a central node which plays along and replies with an informative ack (but longer packets take longer to receive, oops!). Fudging it means the ATmega will be in idle mode a millisec or two, which is perhaps not that wasteful (I haven’t done the math on that yet).

So there you go. Low power stuff isn’t always trivial, once you start pushing for the real gains…

  1. How about running the ATmega off the intrnal RC oscillator to free the external oscillator pins for a 32768Hz Quartz that is then used to run one of the timers as a real time clock? Then your programs would have a fairly precise “watch” to look at whenever the CPU gets woken up by the watchdog or some external event.

    • That’s indeed an interesting option! Power down with watchdog running draws 3..4 µA, whereas Power save with a 32 kHz crystal and timer 2 running draws only 1 µA. So that should make it possible to keep track of time with a 31 µs granularity at all times. There would have to be a brief wakeup to handle overflow from timer 2 every 8 ms. The whole system would run at 8 MHz, which should still be plenty for the RF12 driver plus all other room node code.

      The advantage is that power save can always be used, with timer 2 always tracking time. It’ll probably take some work to get this mode going (RC for system clock, 32 kHz for timer 2 in async mode). To test it, I’ll need to replace the resonator with a crystal + caps, and then start fiddling with fuse bits, etc. Hmm… not trivial, but might be worth a try.

      Neat – thanks!

  2. What about measuring a capacitor discharging over a roughly 8 second curve, acting like a calibrated “candle” burning down?

    • Nifty, but discharge = current leakage, keep in mind that this is about squeezing very low power levels to the limit. The ADC needs a certain amount of charge to “fill” its sample-and-hold bucket, which may affect the discharging cap too much, affecting the readout if discharge currents are kept really low. My expectation is that the power levels involved will be more than running the watchdog at a higher rate (the dribble option) – but that’s just a hunch. There may also be the issue of requiring an ADC pin, but that depends on the use case (the little-used ADC 6 and 7 are not an option, because you can’t set them to digital to charge the cap).

      Lots of trade-offs!

  3. Hi JCW,

    Q: What time is it when the pin-change occurred? Why do the JeeNode need to know the time when the pin-change occurred ? I think tracking the time can be done by the CentralNode or f.e. JeeMon. JeeNode only reports the PinChange. After the first PinChange occurs you can disable the Interrupt. For the 8-Second-Intervall: – Start Watchdog in 8-Second-Intervall – Pin-Change-Interrupt-Fires: — Report the event to Central-Node — Disable the interrupt – Watchdog-TimeOut: — Check the PinStatus and report — if PinStatus is still “Motion” wait for next Watchdog-TimeOuts — if PinStatus is “NoMotion” enable Pin-Change-Interrupt

    In WorstCase you have 7 Seconds in Status “Motion” or 8 Seconds in “Motion” between Watchdog-TimeOuts. If you use a 4-Second-Intervall you have 3 Seconds in Status “Motion” or 4 Seconds in “Motion” between Watchdog-TimeOuts.



  4. i2c real time clocks use low power too. why not an rtc-plug ? I checked one it’s consuming 500 nA.

    • That could work, i use the 1 Hz square-wave-pin from a DS1307 for regular tasks. But the DS1340 don’t have this pin…

  5. I’d just assume that on average, the port-change interrupt will happen at the 4sec mark (if the watchdog is at 8sec). Over time this will drift somewhat, but you need some way to periodically fix the inevitable clock drift anyway. I’d suggest sometime around 3:15 AM, because that way you also get the twice-yearly DST changes as soon as possible.

    Does external resonator draw the same amount of power as the internal clock?

Comments are closed.