Computing stuff tied to the physical world

Low-power waiting – interrupts

In AVR, Hardware on Jun 17, 2012 at 00:01

Following yesterday’s trial, here is the code which uses the pin-change interrupt to run in a continuous cycle:

Screen Shot 2012 06 15 at 17 57 02

The main loop is empty, since everything now runs on interrupts. The output signal is the same, so it’s working.

Could we somehow increase the cycle frequency, to get a higher time resolution? Sure we can!

The above code discharges the cap to 0V, but if we were to discharge it a bit less, it’d reach that 1.66V “1” level more quickly. And sure enough, changing the “50” loop constant to “10” increase the rate to 500 Hz, a 2 ms cycle:


As you can see, the cap is no longer being discharged all the way to 0V. A shorter discharge cycle than this is not practical however, since the voltage does need to drop to a definite “0” level for this whole “cap trick” to work.

So how do we make this consume less power? Piece of cake: turn the radio off and go to sleep in the main loop!

Screen Shot 2012 06 15 at 19 50 10

The reason this works, is that the whole setup continuously generates (and processes) pin-change interrupts. As a result, this JeeNode SMD now draws about 0.23 mA and wakes up every 2 ms using nothing more than a single 0.1 µF cap tied to an I/O pin. Mission accomplished – let’s declare (a small) victory!

PS. Exercise for the reader: you could also use this trick to create a simple capacitance meter :)

  1. You could make it take even less power by using a smaller cap (and a smaller external ressistor, instead of the internal pull-up). The way it is now, your setup needs 100 µA.

    • Good point. Yeah, the power savings aren’t enormous – that’s why I called it a small victory ;)

  2. OK, so for a useful sketch would you 1) Test for something in the interrupt, to see if you are ready to exit from low power mode for a while 2) Set a global flag if so, and 3) Test that flag in the main loop and do something more substantial before restarting the sleep?

    Or what?

    • Sort of – I’d probably aim for something like this: set a countdown value, then decrement it in the interrupt code (along with the discharge) and keep re-entering low-power mode until the counter reaches zero.

    • OK, a decremented counter reaching zero would be one of the kinds of “test for something” I had in mind.

      The other part of my question is whether, once the condition was met, one would best (1) take the appropriate actions inside the ISR, or (2) set a flag and return without sleeping so that loop() would know that it should take the actions, or even (3) abort the interrupt service by popping the stack and enabling interrupts and whatever else is needed, and take the action at non-interrupt level but outside the loop().

    • General guideline: do as little as possible in the ISR. It locks out the CPU from servicing other interrupts (the RFM12B needs very quick service), it requires more stack space, and not all library code is written to run with interrupts disabled.

  3. Nice thinking around the problem – well done – a fun series.

  4. I think the biggest problem here might be that the strength of the pullups is very poorly specified. I think you might have problems with repeatability of those delays on different parts. I would have gone with a 32768k crystal.

    • Indeed – a 50% variation wouldn’t surprise me. But it could be calibrated against the 16 MHz system clock, if all you need is accuracy within a few milliseconds.

Comments are closed.