ISR versus main while loop

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which consumes less battery power: running a Switch() case that contains 5 Cases (one of the Cases will be Sleep Enable) inside an ISR(), or running a Switch() routine in Main()?

Basically, I want to conserve coin cell battery power as much as possible. It involves blinking low power LEDs of varying patterns depending on the Case selected.

My idea was to have a pushbutton provide the external interrupt and to run the entire program via interrupts.

Each Switch() Case would blink the LED pattern indefinitely, until the pushbutton external interrupt changes to the next Switch() Case.

The final Switch() Case is a Sleep Enable. The next pushbutton external interrupt would start this Switch() Case cycle again to the very beginning.

So, an additional question is can a program stay inside the ISR indefinitely using the While() inside the ISR? If it can, would an external interrupt still be detected even though the ISR hasn't returned to the Main() program?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It does not matter where the code runs from for the power consumption. ISR handler can be called again if you enable interrupts first, but you should not do this, because each new interrupt will case context save on the stack.

Just do a normal program loop in the main() and set flags in ISRs.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just have the timer interrupt set a flag. As to what method uses the most power - you'll have to measure it methinks.

You can sit in a dead loop in the isr, but execute a sei() to reenable the interrupts as the avr disables them when it enters a isr. Not recommended though. Keep things simple.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off, using switches to generate interrupts is a really poor ideal. Switches bounce and give you lots of interrupts. It can be really nasty.

While in an ISR, all other interrupts are ignored (unless you do some undesirable things like re-anablig interrupts inside the ISR). While there is no technical reason why a program could not stay in an ISR for-ever, it does not seem like very good program design.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
First off, using switches to generate interrupts is a really poor ideal. Switches bounce and give you lots of interrupts. It can be really nasty.
Since OP wants a push button to wake the chip, an interrupt is the way to go.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Then, some Rs and Cs ought to be added to minimize the consequences of the switch bounce.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mrjimbo wrote:
Which consumes less battery power: running a Switch() case that contains 5 Cases (one of the Cases will be Sleep Enable) inside an ISR(), or running a Switch() routine in Main()?

If I understand this question correctly it says "if I run code X in main or code X in an ISR which will consume more power?"

If X is invariant then why would the power change?

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For minimum power, you probably would need to compare the assembly level instructions of the two different cases.

However, the difference is probably insignificant compared to LED power consumption. You would probably save more power by minimizing your LED on time (e.g. shaving 1% off on time). This of course assumes that the processor is always put to sleep during LED on time .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
Then, some Rs and Cs ought to be added to minimize the consequences of the switch bounce.

Jim


Alternatively, the wakeup ISR can disable further wakeup interrupts. I've used switches to wakeup on interrupt plenty of times without problems.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I want to conserve coin cell battery power as much as possible.

The way you are going to do that is by making the CPU sleep as much as possible. As Sleep is woken by an interrupt it makes sense to just have a "normal" loop in main() that does some stuff then enters sleep when it can. Either a timer or the button causing an interrupt will likely wake it out of sleep each time something else has to be done.

But of course conserving coin cell capacity and keeping LEDs lit are not happy bed fellows. Perhaps you can PWM the LEDs a bit for a slightly lower brightness but also to reduce power consumption. That will likely have far more impact than worrying about where the main loop of the program is executing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is surprising how short a flash can still be seen on an LED. Certainly tens of milliseconds are still very noticeable.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
It is surprising how short a flash can still be seen on an LED. Certainly tens of milliseconds are still very noticeable.
It doesn't make for an especially bright flash, but I use 64 microseconds as a 'heartbeat' on some coin-cell apps. Visible, even with a 6K8 resistor and LED forward current around 200 uA.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So, an additional question is can a program stay inside the ISR indefinitely using the While() inside the ISR?

As mentioned, I'd never structure a program this way. You can service each interrupt that awakens from sleep and go back to the mainline to go back to sleep. (I'm assuming that a timer is managing the actual LED output?)

Quote:

Which consumes less battery power: running a Switch() case that contains 5 Cases (one of the Cases will be Sleep Enable) inside an ISR(), or running a Switch() routine in Main()?

Oh, yes, a follow-on from above...the normal caveat is "don't go to sleep in an ISR" because interrupts are disabled and you'll never wake up. If you >>do<< re-enable interrupts in the ISR, then you have to unwind the stack eventually or you will quickly get stack overflow.

Now, re your original question about ISRs or not w.r.t. power consumption. Short answers:
1) Are you using lowest power AVR8 PA models?
2) It should be easy enough to construct two test programs and check;
3) Without interrupt sources enabled and catching ISRs, it is difficult (impossible?) to awaken on an event AFAIK;
4) As others have said, even if you mesure a few pA difference [how are you going to do that?] the mention of "LED" implies that would be dwarfed by the uA/mA for the LED work.

It is somewhat intriguing. If I was working on a "mote" research project or app that needs to run off the fumes from a urine sample as a power source I suppose it might be worth doing some test runs on what the relative power consumption of various instruction patterns is.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All, I apologize for not being able to get back so quickly! Thank you very much for everyone's responses. I was quite humbled with the number of responses! :-) Nevertheless, I will try to reply to as many of your responses as I can:

Quote:
You can service each interrupt that awakens from sleep and go back to the mainline to go back to sleep. (I'm assuming that a timer is managing the actual LED output?)

My intentions of doing a While() loop inside an ISR was to indefinitely blink LEDs until the next external pushbutton interrupt advances the Switch() Case to the next state. I just recently got a headlight for my 8-year old son's bike. It's operation mimics the state machine I would like to create for this patch LED project. The headlight state machine has 4 modes of operation (3 blink patterns and 1 "off"). I'm thinking that the "off" mode is really a power-down sleep mode. This headlight has a single button to cycle through all 4 modes.

Quote:
the normal caveat is "don't go to sleep in an ISR" because interrupts are disabled and you'll never wake up. If you >>do<< re-enable interrupts in the ISR, then you have to unwind the stack eventually or you will quickly get stack overflow.

Wow, that's why you all are the geniuses. I don't know anything about "unwinding stack" or "stack overflow". But, if you say it's not wise to put the chip to sleep in ISR, then I won't do it! :-)

Quote:
1) Are you using lowest power AVR8 PA models?
2) It should be easy enough to construct two test programs and check;
3) Without interrupt sources enabled and catching ISRs, it is difficult (impossible?) to awaken on an event AFAIK;
4) As others have said, even if you mesure a few pA difference [how are you going to do that?] the mention of "LED" implies that would be dwarfed by the uA/mA for the LED work.

1. Atmega328P. But I've never experimented before with shutting down resources on a MegaAVR, so this is new territory for me. I've been doing quite a bit of reading in recent days, though.
2. Yes, but I was just asking all of you based on your personal experience if generally there were differences in power consumption depending on where or how code is executed. For instance, my feeble thinking was that putting an entire program in a While(1) loop in the Main() would somehow constantly the AVR run instructions, thus consuming battery power. But, like someone said that a While() loop is a While() loop no matter where it is executed from.
3. I'm definitely thinking of using a small tactile pushbutton (using the one from the $35 Arduino beginners components kit) for the external interrupt source. I know I will need to debounce this, and I have read from somewhere that disabling the interrupt INT0 as soon as the interrupt detects a falling edge serves as a debounce method. I tested this tonight with PORTD2, but not as an external interrupt. I only tried "if (PIND == 0x00), then DDRD = 0x00, PORTD = 0x00, and _delay_ms(500)" Seemed to work without problems.
4. Yeah, just got to see how possible this is. BTW, I was planning on using two coin cell batteries to double the current capacity.

Quote:
64 microseconds as a 'heartbeat' on some coin-cell apps. Visible, even with a 6K8 resistor and LED forward current around 200 uA.

Cool! I'll have to remember that!

Quote:
Perhaps you can PWM the LEDs a bit for a slightly lower brightness but also to reduce power consumption.

Good idea. I've been looking at that, because someone had mentioned that I could get a twinkling effect using PWM. I was able to demonstrate on my breadboard tonight doing PWM on a single LED. I would like to accomplish doing 3 different PWM duty cycle and frequencies to twinkle 3 different LEDs. But, being how novice I am, this will take a little more time. Tonight I was trying to figure out how to run two 8-bit timers simultaneously. Fail! I just got to read some more! :-)

Quote:
As Sleep is woken by an interrupt it makes sense to just have a "normal" loop in main() that does some stuff then enters sleep when it can.

Yeah, I'm beginning to realize that this is the way to go. Have all of my code in the Main() and use the ISR to advance my "current_state" variable to advance to the next Case in the Switch() statement

Quote:
Alternatively, the wakeup ISR can disable further wakeup interrupts. I've used switches to wakeup on interrupt plenty of times without problems.

I was thinking I could do the same. Glad to hear you haven't had troubles with this method

Quote:
For minimum power, you probably would need to compare the assembly level instructions of the two different cases.

Yeah, this definitely is not a science project for me. Plus, I'm just not smart enough. Nevertheless, you are right that the most worry I should have would be the LEDs

Quote:
If X is invariant then why would the power change?

Good point!

Quote:
You can sit in a dead loop in the isr, but execute a sei() to reenable the interrupts as the avr disables them when it enters a isr. Not recommended though. Keep things simple.

Yeah, I would like to keep things simple.

Quote:
using switches to generate interrupts is a really poor ideal. Switches bounce and give you lots of interrupts. It can be really nasty.

I do plan to debounce it, and I need a person to push the tactile button to wake up the AVR

Quote:
Just do a normal program loop in the main() and set flags in ISRs.

Yep, I am seeing that now.

THANKS EVERYONE! :-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greta to see that you are listening to the suggestions. The idea of a while(true) loop in an ISR was scary.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Who the hell's Greta?

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hansel's sister. ("Hans och Greta" is Swedish for "Hänsel und Gretel") :-)