The other day, I mentioned a way to keep approximate track of time via the watchdog timer, by running it as often as possible, i.e. in a 16 ms cycle.
This brought out some loose ends which I’d like to clean up here.
First of all, the loseSomeTime() code now runs 60 times per second, so optimizing it might be useful. I ended up moving some logic out of the loop, to keep the time between power-down states as short as possible:
The result is this power consumption profile, every ≈ 16 ms:
That’s still about 22 µs @ 6.5 mA. But is it, really?
The above current measurement was done between the battery and the power supply of a JeeNode SMD. Let’s redo this without regulator, i.e. using a “modded” JeeNode with the regulator replaced by a jumper:
Couple of observations:
- different ATmega, different watchdog accuracy: 17.2 vs 16.3 ms
- the rise and fall times of the pulse is sharper, i.e. not dampened by a 10 µF buffer cap
- new behavior: there’s now a 0.4 mA current during 80 µs (probably the clock starting up?)
- that startup phase adds another 75 nC to the total charge consumed
- note that there is a negative current flow, causing the charge integral to decrease
The worrying bit is that these two ways of measuring the current pulses differ so much – I can’t quite explain it. One thing is clear though: an adjusted fuse setting with faster clock startup should also make a substantial difference, since this now needs to happen 60 times per second.
A second improvement is to assume that when a watchdog cycle gets interrupts, half the time has passed – on average that’ll be as best as we can guess, assuming the interrupt source is independent:
The last issue I wanted to bring up here, is that small code optimizations can sometimes make a noticeable difference. When running the test sketch (same as in this post) with a 8192 millisecond argument to loseSomeTime(), the above code produces the following profile:
The reason the pulse is twice as wide is that the “while” in there now loops a few times, making the run time almost 50 µs between power-down phases. As Jörg Becker pointed out in a comment, the ATmega has no “barrel shifter” hardware, meaning that “shift-by-N” is not a hardware instruction which can run in one machine cycle. Instead, the C runtime library needs to emulate this with repeated shift-by-1 steps.
By changing the while loop from this:
… to this:
… we get this new power consumption profile (the horizontal scale is now 20 µs/div):
IOW, this takes 20 µs less time. Does it matter? Well, that might depend on who you ask:
Marketing guy: “50 µs is 67% more than 30 µs – wow, that means your sketch might last 5 years i.s.o. 3 years on the same battery!”
Realist: “50 µs i.s.o. 30 µs every 8 seconds – nah, those extra 120 nC or so will merely add 15 nA to the average current consumption.”
The moral of this story: 1) careful how you measure things, and 2) optimize where it matters.
Anyway, I’ve added all three changes to JeeLib. It won’t hurt, and besides: it leads to smaller code.