4
\$\begingroup\$

I'm trying to put a cortex m4 processor (m3 with dsp extensions) to sleep for a little less than a second. I want to be able to tell it to sleep, then a second later, or when a button is pressed, pick up right where I left off. I've looked in the reference manual and VLPS or LLS modes look like it would fit my needs. Ideally I'd like a glorified delay function, for it to sleep for a second. I don't know how to begin to enter that mode or how to program the NVIC. I'm using C on bare metal.

Any help would be greatly appreciated.

Here's the code:

#include "IntervalTimer.h"

//The following is where the SLEEPDEEP flag is at
#define SCR         (*((volatile unsigned long *) 0xE000ED10))

volatile uint32_t timerCounter0;
boolean printNow = false;

void timerCallback0() {
  timerCounter0++;
  printNow = true;
}

void setup() {
  SCR = SCR | 0x04;    //Set SLEEPDEEP
  Serial.begin(true);
  IntervalTimer timer0;
  timer0.begin(timerCallback0, 1000000);
}

void loop() {
  if (printNow) {
    Serial.println(timerCounter0);
    printNow = false;
    asm("wfi\n");
  }
}
\$\endgroup\$
1
\$\begingroup\$

You are counting many periods of a fairly short timer, each expiration of which requires you to wake up. To get maximum power savings, you need to put the timing entirely in hardware, so that you only generate an interrupt at the end of the desired period, or at least fairly infrequently. You should probably look at using a larger value in the timer register, and possibly using a prescalar divisor. (Even if you are waking up only a few times a second and so not wasting much power, this will make it a pain to measure power consumption unless you use a scope to measure across a series resistor)

However, even then you would likely still be running on a fast PLL clock, which consumes a lot of power. So for more power savings you will want to switch to a low power clock source such as an internal or external KHz-range backup clock, or at least disable the PLL and possibly crank up any system-wide clock prescale divider.

And you also likely have many parts of the chip powered up and clocked which are not needed in sleep mode - likely you want to power down and de-clock everything except the GPIO, interrupt controller, counter module and RAM.

Additionally, you need to audit your circuit design for any cases where you are driving a signal against a pullup or pulldown resistor, or even letting a digital input float in the vicinity of a logic transition.

Getting a system down to microamp standby modes can be an involved project, as you eliminate one power leach after another. Also watch out for debugger, serial, USB, etc connections - not only as potential loads, but also potential stealth power sources for the system to get power while bypassing whatever you are measuring with (yes, you can get energy from data pins).

\$\endgroup\$
3
\$\begingroup\$

I'm not sure which MCU you are using exactly, so I checked in the STM32F4 reference manual, which I'm most familiar with. Since sleep modes are implemented by the ARM core, it should be similar to any other Cortex M4 MCU. Section 5.3.3 discuss entering/exiting sleep mode (checking it out for details).

To enter sleep mode:

The Sleep mode is entered by executing the WFI (Wait For Interrupt) or WFE (Wait for Event) instructions.

Depending on some register's value, the sleep mode is entered immediately or only after it exit the lowest priority ISR.

To exit after 1 second, you will need to setup a timer that will trigger an ISR after 1 second. (Since this is MCU implementation dependant, I'll skip the details for the STM32F4.) If sleep mode was entered with WFI, this interrupt (as well as any other interrupt) will wake the MCU. If you need more detailed control on what should wake the MCU, you should sleep with WFE and setup the wake event (section 10.2.3 of the manual).

\$\endgroup\$
  • \$\begingroup\$ I used the WFI instruction in code to verify that it works, but it didn't do anything. Do I need to have an interrupt set up beforehand? \$\endgroup\$ – robostork Jun 12 '13 at 14:36
  • \$\begingroup\$ Yes, you need to to setup a timer so that it interrupts after one second. If you don't see any effect, it could also be that you have another interrupt that triggers repeatedly and thus force sleep exit just after WFI is called. \$\endgroup\$ – abey Jun 12 '13 at 22:03
  • \$\begingroup\$ I've edited the discription to include the code I'm using. It works as expected, but power draw is the same. Any ideas? \$\endgroup\$ – robostork Jun 13 '13 at 4:55
0
\$\begingroup\$

Not sure if this is what you were looking for, but I'll have a go anyways.

Using C, you should be able to have the processor do nothing (ie: sleep) using the sleep() function from <time.h>.

Refresher:

#include <time.h>

 int main() {
     int sleepms;
     sleep(sleepms); //Sleep for "sleepms" milliseconds
 }
\$\endgroup\$
  • 1
    \$\begingroup\$ No, sleep is part of posix, not C. The question concerns bare-metal development, and this would only work if there's a scheduler or support library implementing a sleep() in a way that ultimately suspends the core (or at least dramatically reduces the clock) if there are no other tasks requiring it to be active. \$\endgroup\$ – Chris Stratton Jun 13 '13 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.