how to verify CPU is going to sleep?

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

I have a demo to use a timer interrupt to wake up the CPU and toggle a pin to blink the LED on my Arduino Uno 3.

Is there a way to verify the processor is sleeping?   The led does flash as expected, and my (home coded) simulator says it's sleeping.

 

/* demo to delay using timer interupt */
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>

/* Tune CLKSEL, OCRTOP, CTRDIV to give 1 msec delay. */
#if F_CPU == 20000000
#define DELAY_CLKSEL 5
#define DELAY_OCRTOP 39
#define DELAY_CNTDIV 2
#elif F_CPU == 16000000
#define DELAY_CLKSEL 4
#define DELAY_OCRTOP 125
#define DELAY_CTRDIV 2
#elif F_CPU == 8000000
#define DELAY_CLKSEL 4
#define DELAY_OCRTOP 125
#define DELAY_CTRDIV 4
#elif F_CPU == 1000000
#define DELAY_CLKSEL 3
#define DELAY_OCRTOP 8
#define DELAY_CTRDIV 2
#else
#error "unhandled DELAY for F_CPU"
#endif

volatile uint8_t wait_ctr;
volatile uint8_t wait_flg;

/* Wake up main on wait_val transition from one to zero. */
ISR(TIMER0_COMPA_vect) {
  if (wait_ctr != 0) {
    wait_ctr -= 1;
    if (wait_ctr == 0) {
      wait_flg = 0;
    }
  }
}

void my_delay_ms(uint16_t ms) {
  wait_flg = 1;
  wait_ctr = ms/DELAY_CTRDIV;
  while (wait_flg) {
    sleep_cpu();
  }
}

void my_timer0_setup(void) {
  wait_ctr = 0;
  TCCR0A = 0x02;		    	/* CTC mode */
  TCCR0B = DELAY_CLKSEL;		/* set up  */
  OCR0A = DELAY_OCRTOP;			/*   for 1 msec delay */
  TIMSK0 |= _BV(OCIE0A);		/* enable timer0/A interrupt */
}

int main(void) {
  my_timer0_setup();
  sleep_enable();
  sei();

  DDRB |= _BV(DDB5);
  PORTB |= PORTB5;

  for (;;) {
    PINB = _BV(PINB5);
    my_delay_ms(100);
  }
}

/* --- last line --- */

 

EDIT: wait_ctr should be declared uint16_t

Last Edited: Mon. May 6, 2019 - 12:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MattRW wrote:
Is there a way to verify the processor is sleeping?
Yes (ammeter)

The AVR's current will be proportional to CPU current plus the peripheral current (megaAVR - power reduction register, XMEGA AVR - one general power reduction register plus one power reduction register per port) plus current through the pins.

 

Arduino Uno Rev3

 

"Dare to be naïve." - Buckminster Fuller

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

    You can use a delay function to toggle a pin. When CPU sleeps, the delay is longer.

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

angelu wrote:

    You can use a delay function to toggle a pin. When CPU sleeps, the delay is longer.

 

That sounds promising.  Thanks.

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

I was going to say "measure the current" but with a low sleep mode and 1ms delay, might be hard to measure.

 

Give some power budget numbers -- what do you expect to save in a low sleep mode with peripherals running and awakening every millisecond?

 

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

You can put a small resistor in the Vcc or GND line, which has a voltage drop of around 100mV during normal operation.

Then you can measure the ripple over that resistor with an oscilloscope.

The advantage of having such a shunt permanent in place is that it's small enough to never have to take it out of your development board, and 100mV is low enough to not cause any trobles for the uC, unless it's normally operating very near to it's minimum (brownout!).

 

Make sure to put the decoupling capacitor on the uC side of the shunt.

Back in the '70s & '80's  this was used by some engineers to detect latchup in cmos logic, or even balanced in such a way that if latchup occured, the chip did not get hot enough to destroy itself.

For better measurement it also helps to reduce current consumption to I/O of the uC. For example do not switch a LED from the uC pin directly, but put a transistor between the uC and the LED, so the LED current won't show up over your shunt resistor.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

Last Edited: Tue. May 7, 2019 - 02:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MattRW wrote:

angelu wrote:

    You can use a delay function to toggle a pin. When CPU sleeps, the delay is longer.

 

That sounds promising.  Thanks.

 

More specifically, you put the pin-toggle right next to the sleep command, polling loop.

If the part is not sleeping, the loop is running at full speed and pin toggle will be in low microseconds region.

If the part sleeps and wake on a slow interrupt, that shows in a much lower pin toggle rate.

You can comment/uncomment the sleep to confirm that change.

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

Here is what I did.   Recoded so that the interrupt is around 4 ms.   Then in the spin-loop I toggle a PORTD pin, wait 1 ms, toggle, wait 1ms.  Now, if the sleep works, then the port should stay unchanged for 2 more ms, giving a 25% or 75% duty cycle.  If the sleep is not working, then the spin loop will go again making the duty cycle 50%.     Below is (1) updated code (w/ sleep enabled), (2) scope trace for sleeping case, (3) scope trace for non-sleeping case.   (For the non-sleeping run I commented out the sleep_enable(); line of code.)

 

/* demo to delay using timer interupt */
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>

/* Tune CLKSEL, OCRTOP, CTRDIV to give 1 msec delay. */
#if F_CPU == 16000000
#define DELAY_CLKSEL 4
#define DELAY_OCRTOP 250
#define DELAY_CTRDIV 4
#else
#error "unhandled DELAY for F_CPU"
#endif

volatile uint16_t wait_ctr;
volatile uint8_t wait_flg;

/* Wake up main on wait_val transition from one to zero. */
ISR(TIMER0_COMPA_vect) {
  if (wait_ctr != 0) {
    wait_ctr -= 1;
    if (wait_ctr == 0) {
      wait_flg = 0;
    }
  }
}

void my_delay_ms(uint16_t ms) {
  wait_flg = 1;
  wait_ctr = ms/DELAY_CTRDIV;
  /* if sleep working for 16 MHz this will wake up every 4 ms */
  while (wait_flg) {
    PIND |= _BV(PIND5);
    _delay_ms(1);
    PIND |= _BV(PIND5);
    _delay_ms(1);
    sleep_cpu();
  }
}

void my_timer0_setup(void) {
  wait_ctr = 0;
  TCCR0A = 0x02;			/* CTC mode */
  TCCR0B = DELAY_CLKSEL;		/* set up  */
  OCR0A = DELAY_OCRTOP;			/*   for 1 msec delay */
  TIMSK0 |= _BV(OCIE0A);		/* enable timer0/A interrupt */
}

int main(void) {
  my_timer0_setup();
  sleep_enable();
  sei();
  
  DDRB |= _BV(DDB5);
  DDRD |= _BV(DDD5);
  
  for (;;) {
    PINB = _BV(PINB5);
    my_delay_ms(100);
  }
}

/* --- last line --- */

 

 

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


using an oscilloscope is a good idea. However, recently I got the chance to get a digital multimeter Keysight 34465A:

 

 

I can tell you, this thing is absolutly incredible. sometimes you never know if your program is really in power-down or "sleep mode" and with a digital multimeter this shows you whats behind...

 

Sorry I dont have a comment on your code but i thought this might help..

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

Do you sleep with that thing, Moe?

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

MattRW wrote:

Do you sleep with that thing, Moe?

 

Nah not really ;), but it show me if my thing is really sleeping or not ;). Its a bit expensive actually (1078 EUR)...you can go down to nA....

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

MattRW wrote:

Do you sleep with that thing, Moe?

 

Dang. I would! It's worth more than my car. Hmm. My toy train is worth more than my car.

 

I was just thinking I miss those 9 digit fluke meters of the early 80's. Bet they were pricey.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

Last Edited: Wed. May 15, 2019 - 06:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moe123 wrote:

...you can go down to nA....

Like any shunt resistor, ammeters have a higher shunt resistance when in lower current mode. You can see if the micro is sleeping with a regular shunt resistor. However, if you want to actually measure the current consumption in mA range while running and with the same scale while in power down mode with currents under 1µA, than it is a challenge.

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

angelu wrote:

Moe123 wrote:

 

...you can go down to nA....

Like any shunt resistor, ammeters have a higher shunt resistance when in lower current mode. You can see if the micro is sleeping with a regular shunt resistor. However, if you want to actually measure the current consumption in mA range while running and with the same scale while in power down mode with currents under 1µA, than it is a challenge.

 

So you want to compare a regular shunt resistor with the 34465A ?!

 

 

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

LOL@Torby

 

Btw, How is it with the storm ??

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

Moe123 wrote:

LOL@Torby

 

Btw, How is it with the storm ??

 

?

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

Torby wrote:

Moe123 wrote:

 

LOL@Torby

 

Btw, How is it with the storm ??

 

?

 

https://www.avrfreaks.net/forum/...