Sleep-on-exit is a feature in Cortex-M3 processors that allows the processor to automatically enter a low power sleep mode when exiting an ISR or exception handler. This reduces power consumption by avoiding unnecessary wakeups when handling short interrupt service routines. By enabling sleep-on-exit, the processor can go to sleep and wake up much faster between events, maximizing time spent in energy-saving sleep modes.
What is Sleep-on-Exit?
Sleep-on-exit allows a Cortex-M3 processor to automatically re-enter sleep mode when returning from an ISR or exception handler, without needing extra instructions in the handler routine. This feature works by setting the SLEEPONEXIT bit in the System Control Register (SCR).
With sleep-on-exit enabled, whenever the processor exits an ISR or exception handler, it will immediately re-enter sleep mode instead of continuing normal program execution. This avoids waking up the full processor for very short ISRs that don’t require further processing after the interrupt. By reducing unnecessary wakeups, overall power consumption is decreased.
How Sleep-on-Exit Works
Here is a simplified overview of how sleep-on-exit operates in a Cortex-M3:
- The processor is in sleep mode, an interrupt occurs and wakes up the processor.
- The corresponding ISR runs to completion and executes an exception return instruction to exit the handler.
- With sleep-on-exit enabled, the processor automatically re-enters sleep mode instead of continuing program flow.
- This process repeats for any subsequent short ISR handlers.
Essentially the processor goes directly back to sleep without needing to execute extra instructions after each interrupt service routine. This avoids waking up the full processor for the main program if not needed.
Benefits of Sleep-on-Exit
The major benefits of enabling sleep-on-exit are:
- Reduces power consumption by minimizing wakeups for short ISRs
- Allows processor to quickly go in and out of sleep around interrupts
- Frees up processor cycles for application code instead of sleep management
- Requires less programmer effort compared to manually inserting sleep code
For interrupt-driven applications that spend a lot of time idle waiting for external events, sleep-on-exit can help maximize the time spent in low power sleep modes. This in turn extends battery life for portable devices.
How to Enable Sleep-on-Exit
Enabling sleep-on-exit only requires setting a single bit in the Cortex-M3 System Control Register (SCR). This register controls various system-level configurations like sleep and exception handling.
To enable sleep-on-exit:
- Read the current value of the SCR register into a temporary variable
- Set bit 1 of the temporary variable to 1 to set the SLEEPONEXIT bit
- Write the new temporary value back to the SCR to update the system configuration
For example, in C code: uint32_t scr = __get_SCR(); // read SCR scr |= 0x2; // set SLEEPONEXIT bit __set_SCR(scr); // update SCR
The SLEEPONEXIT bit can be cleared to 0 at any time to disable sleep-on-exit. The SCR register may contain other configuration bits that should be preserved when updating it.
Compiler Intrinsics for SCR Access
Most Cortex-M3 toolchains provide intrinsics to directly read and write the SCR register in C code. For example with ARM Compiler 5:
- __get_SCR() – returns SCR contents
- __set_SCR() – sets SCR contents
Check your compiler documentation for the right intrinsic functions to use.
When to Enable Sleep-on-Exit
Enabling sleep-on-exit is recommended for most interrupt-driven applications to maximize power savings. It has the largest benefit when the processor spends significant time idle waiting for external events.
Specific cases where sleep-on-exit should be enabled include:
- Applications with multiple short interrupt handlers
- Event-driven state machines that are idle most of the time
- Sensor monitoring code with intermittent activity
- Low duty cycle wireless protocols like BLE
However, sleep-on-exit may not be appropriate in a few cases:
- Interrupt handlers that make function calls or have long execution times
- Applications requiring very fast ISR exit latencies
- Interrupts that occur in rapid bursts faster than sleep entry/exit time
For complex interrupt service routines that do significant processing, it may be better to manually enter sleep mode at optimal points instead of using sleep-on-exit.
Guidelines for Using Sleep-on-Exit
Here are some guidelines on when and how to effectively use sleep-on-exit in Cortex-M3 designs:
- Enable by default, disable if any ISR requires longer processing
- Use for short ISRs less than 150 cycles (configurable threshold)
- Ideal for sensing and data collection applications
- Disable if response latency requirement is under 500us
- May need slight ISR optimization to avoid long delays before sleeping
- Combine with Wake-up Interrupt Controller (WIC) for faster latency
Testing sleep mode current consumption with and without sleep-on-exit enabled will give a good indication of potential power savings.
Customizing Sleep-on-Exit Behavior
The Cortex-M3 processor provides several options to customize sleep-on-exit behavior as needed by the application.
Sleep-on-Exit Threshold
The processor can be configured to only enter sleep for ISRs under a specific cycle threshold. This avoids needlessly going to sleep for longer ISR handlers. The threshold is controlled by the SLEEPONEXIT number of cycles field in the Power Control Register (PCR).
For example, setting SLEEPONEXIT to 0x100 will only sleep for ISRs shorter than 256 cycles. The threshold can be tuned based on profiling ISR execution times.
Bypassing Sleep for Specific Interrupts
Sleep-on-exit can be bypassed for critical interrupts where response latency cannot be compromised. This is configured in the Interrupt Program Status Register (IPSR).
Setting the SLEEPONEXIT bit for a specific interrupt forces the processor to stay awake after handling that IRQ, while still sleeping for others. Multiple interrupts can be configured this way by setting multiple IPSR bits.
Atomic Sleep-on-Exit
By default, sleep-on-exit uses non-atomic “interruptable” mode which can be interrupted by a pending interrupt. This allows faster sleep entry but the processor may wake up again immediately.
For more power savings, atomic sleep mode forces the processor to fully enter sleep and ignore any further interrupts during the sequence. This guarantees longer sleep periods but has slightly higher latency.
Atomic sleep is enabled by setting the SLEEPDEEP bit in the SCR register.
Optimizing ISRs for Sleep-on-Exit
To maximize the benefits of sleep-on-exit, interrupt handlers can be optimized to avoid unnecessary delays:
- Avoid long running functions like print statements
- Minimize ISR processing cycles where possible
- Use fast ISR exit methods like tail-chaining
- Move non-critical work to the main loop
- Process serial data in bulk instead of byte-by-byte
Reducing the cycles from interrupt detect to sleep by even 100 cycles can have a measurable impact on power reduction. The goal is to sleep as early and often as possible between events.
Sleep Latency Overhead
The processor requires a certain number of cycles to enter and exit sleep modes which adds some latency overhead:
- Non-atomic sleep latency is 60-90 cycles
- Atomic sleep latency is 110-140 cycles
So it’s preferable to aggregate multiple short ISRs together rather than sleep very frequently. Tuning the SLEEPONEXIT threshold can find the right balance.
Compatibility Considerations
Sleep-on-exit is supported transparently across Cortex-M3 revisions and toolchains. But there are some points to keep in mind:
- Will not work as expected with some OS kernels
- Can conflict with debug halt modes
- Should be disabled when tracing interrupt behavior
- May require modifications to application context save/restore code
Check documentation for OS compatibility and validate debug behavior with sleep enabled. Context handling code may need adjustment if it makes assumptions about interrupt wakeups.
Debugging Sleep-on-Exit
Here are some techniques for debugging issues related to sleep-on-exit:
- Measure power consumption with and without sleep enabled
- Use oscilloscope to view sleep waveforms
- Use JTAG/SWD to step through ISR exit sequence
- Use debugger to view sleep statistics counters
- Insert test code to record timestamps around ISRs
If sleep-on-exit is not behaving as expected, the first steps are verifying it is enabled correctly and confirming the processor is actually sleeping. Measurement of current draw or the sleep waveform is the best indicator.
Debuggers that support halting immediately after interrupt detection can help observe the system right before it enters sleep. This can reveal issues like peripherals holding the processor awake unexpectedly.
Wakeup Sources and Latency
While in sleep mode, only enabled wakeup sources can interrupt the processor and trigger an exit from sleep. Minimizing sources improves power but can increase response latency.
The main wakeup sources are:
- Internal peripheral interrupts
- External interrupt inputs
- Watchdog timers
- Low power timers
With sleep-on-exit enabled, the interrupt detect to active latency depends on:
- Selected low power mode
- Interrupt priority
- Atomic vs non-atomic sleep
- Wakeup interrupt controller (WIC) usage
For normal operation, expect 1-3us wakeup latency from most low power modes before code starts running. Worst case latencies apply for lowest power modes.
Wakeup Interrupt Controller
A dedicated wake-up interrupt controller (WIC) peripheral is used in some MCUs to accelerate interrupt detection and reduce wakeup latency by up to 100x.
The WIC peripheral sniffs external interrupt lines while the main core is sleeping, allowing very fast wakeup response. It enables interrupt detection in under 10 processor cycles.
When low-latency wakeup is critical, using the WIC peripheral can enable more aggressive power savings by allowing the lowest sleep modes without sacrificing interrupt response time.
Sleep Modes for Cortex-M3
The Cortex-M3 processor supports several low power sleep modes that offer different levels of power savings:
- Sleep – CPU stopped, peripherals kept running
- Deep sleep – CPU and peripherals turned off
- Standby – External SRAM retained, all internal voltage rails off
- Shutdown – Complete power removal, memory state lost
Sleep-on-exit works with all these modes to minimize power between interrupt events. The different modes offer trade-offs between wakeup latency, peripherals active, and memory retention.
For example, “sleep” mode allows fast wakeup by keeping peripherals and SRAM powered, while “standby” offers the lowest power by removing power from internal voltage regulators but loses SRAM contents.
The optimal mode depends on the interrupt response requirement, wakeup sources, peripherals used, and whether full system state needs to be maintained.
Choosing Sleep vs Deep Sleep Mode
The most commonly used sleep modes are:
- Sleep – Retains peripherals and SRAM, 60-90 cycle wakeup
- Deep sleep – Retains SRAM, turns off peripherals, 90-140 cycle wakeup
Sleep allows peripherals like UARTs and timers to remain active and retain their internal state between sleep cycles, allowing very fast wakeup.
Deep sleep fully powers down peripherals and is preferable when peripherals are not needed or their state can be restored on each wakeup.
For intermittent sensor monitoring, sleep mode works well since peripherals like ADCs need to maintain calibration. For always-on low power operation, deep sleep removes peripheral leakage current.
Sleep Current Consumption
The Cortex-M3 processor can achieve extremely low power consumption while in sleep modes. Some example MCU sleep current levels:
- Sleep: 2-6 uA
- Deep-sleep: 1-3 uA
- Standby: 0.6-1 uA
- Shutdown: 0.1 uA
Exact current draw depends on the peripheral configuration, voltage regulator type, and silicon process used.
With sleep-on-exit minimizing the wake time between interrupts, the average current can approach these levels for low duty cycle applications.
For example, at 3V and 3 uA deep sleep current, average power can be under 1 uW. Enabling further voltage scaling brings this down to the nW range.
Impact of Peripherals
Enabled peripherals can contribute significant additional current draw in sleep modes by remaining powered on. For example:
- GPIO bank: 2-5 uA
- Flash memory: 5-10 uA
- High speed RTC: 1-3 uA
- PLL or oscillator: 1-2 uA
Managing peripherals usage and clock gating properly allows minimizing sleep current to reach the optimal system level.
Sleep Mode Comparison
Mode | Wakeup Time | Peripheral State | SRAM State |
Sleep | Fastest | Retained | Retained |
Deep Sleep | Fast | Powered off | Retained |
Standby | Very Fast | Powered off | Lost |
Shutdown | Slow | Powered off | Lost |
So in summary:
- Sleep – Fully transparent sleep with fastest wakeup
- Deep Sleep – Retains SRAM, loses peripheral state
- Standby – Lowest power, loses SRAM and peripherals
- Shutdown – Completely powers off, full reboot on wakeup
Sleep is best for lowest latency, while Deep Sleep offers a good balance of power savings and wakeup time. Standby and Shutdown are for maximizing power reduction when RAM retention is not needed.
Peripheral State in Sleep vs Deep Sleep
A key difference between Sleep and Deep Sleep modes is peripheral state retention:
- Sleep – All peripherals remain powered on and retain state
- Deep Sleep – Peripherals are powered off and lose state
For example, in Sleep mode:
- Timers continue counting and hold their configurations
- UARTs keep their baud rate, buffers and configuration settings
- ADC maintains its calibration and input mux selections
So peripherals are fully ready to use immediately on wakeup. This comes at the cost of extra power consumption to keep peripherals powered.
In Deep Sleep instead:
- Timers and counters reset to 0
- UARTs lose their buffered data, baud rate settings, etc
- ADCs lose calibration and need re-initialization
This requires re-configuring peripherals after each wake, but reduces sleep power significantly by removing peripheral leakage currents.
Choosing Between Sleep and Deep Sleep
The choice depends on several factors:
- How quickly peripherals need to be operational
- Is peripheral state important to retain
- Acceptable wakeup latency
- Availability of resets and re-initialization code
- Impact on overall power consumption
For applications where you need a peripheral like a UART to be immediately usable on wakeup, Sleep mode is preferable. But if startup latency is not critical, Deep Sleep removes peripheral overheads.
Testing current draw in both modes can guide the decision based on actual power consumption impact.
Leveraging Wakeup Interrupts
To fully optimize sleep current, peripherals that are not wakeup sources can be powered down or disabled when entering sleep modes.
For example, before deep sleep:
- Turn off ADC if not used as wakeup source
- Disable serial port if not needed for wakeup event
- Switch off GPIO banks not used for wakeup
- Minimize active wakeup sources to mandated set only
This allows maximizing power savings by removing any unused peripheral current draw. When coupled with sleep-on-exit, the processor quickly resumes peripherals only when required on wakeup.
Recommended Wakeup Sources
Typical recommended wakeup sources are:
- Low power timer for periodic events
- RTC for keeping time across sleep
- GPIO for external interrupts
- Comparator for analog threshold events
- WIC for high priority external interrupts
All other peripherals can generally be powered down before sleep. Only enabled wakeup sources will be capable of triggering a wakeup interrupt.
Sleep Mode Clocking
The processor and bus clocks are halted in all sleep modes. Only active asynchronous clocks like RTC run.
However oscillator and PLL configurations are maintained if left enabled:
- HSIRC high speed oscillator remains powered
- Main system PLL retains configurations
- Clock sources are quickly reactivated on wakeup
This allows the clocks to stabilize in background so system clocks can restart quickly when exiting sleep. PLL re-lock time is avoided on each wakeup.
If clock setup time is not critical, oscillators and PLL can be disabled before sleep to reduce power further.
Wakeup Scheduling
For periodic wakeups, low power timer peripherals or watchdogs allow scheduled wakeup events to trigger sleep mode exits.
Example uses of scheduled wakeups include:
- Wakeup every 50ms to sample a sensor
- Wakeup once per second to update an LED
- Wakeup every minute to transmit collected data
The wakeup timer runs asynchronously while the system sleeps, and generates an interrupt when it matches the programmed interval or count value.
Watchdog timers can act as a simple wakeup timer using the windowed watchdog mode, which triggers interrupts on rolling over instead of resetting the system.
Optimizing Scheduled Wakeups
Recommendations when using wakeup timers:
- Select low power clock source like 32kHz oscillator
- Minimize timer resolution to needed accuracy
- Disable peripherals not required for wakeup event handling
- Enter deep sleep mode to maximize power savings
- Combine timers to allow longer sleeps between wakeup ISRs
Tuning the wakeup points and peripheral usage can greatly reduce the power cost of periodic events.
Real-Time Clock
A real-time clock (RTC) peripheral is used to maintain timekeeping across sleep cycles. It remains powered in sleep mode.
Main uses of RTC with sleep modes:
- Maintain current time for data logging purposes
- Generate periodic wakeup interrupts for scheduled events
- Timeout long sleep durations
- Timestamp events across sleep periods
RTCs have dedicated low power clock sources like 32kHz crystals to allow continuous running even while the rest of the system is sleeping. However the RTC still contributes to sleep mode current draw.
Optimizing RTC Power
To optimize RTC power consumption:
- Disable RTC periphery like external tamper detection
- Run RTC from low frequency clock source
- Minimize active wakeup signals from RTC
- Disable RTC clock out signal if not used
- Enter deep sleep mode to power down excess RTC modules
Controlling the RTC configuration allows minimizing its sleep power impact for longest battery life.
Sleep Mode Example Code
Here is example code to enter different Cortex-M3 sleep modes, using sleep-on-exit:
Normal Sleep Mode
// Enable sleep-on-exit SCR |= SLEEPONEXIT; // Enter sleep __WFI();
Deep Sleep
// Enable sleep-on-exit SCR |= SLEEPONEXIT; // Disable peripherals Periph_Disable(); // Enter deep sleep SCR |= SLEEPDEEP; __WFI(); // Re-enable peripherals Periph_Enable();
Standby Mode
// Backup SRAM contents SRAM_Backup(); // Disable peripherals and SRAM Periph_Disable(); SRAM_Off(); // Enter standby PWR_EnterStandby(); // Restore peripherals and SRAM state PWR_ExitStandby(); SRAM_Restore(); Periph_Enable();
With appropriate peripherals handling, sleep-on-exit allows automatically sleeping on ISR exit with minimal code change.
Conclusion
In summary, the Cortex-M3 sleep-on-exit feature enables efficient automated use of sleep modes by avoiding unnecessary wakeups after interrupt handlers. This provides significant power savings for event-driven systems.
Coupled with additional peripherals management, developers can leverage the full benefits of the Cortex-M3 low power modes to maximize battery life for energy-constrained designs.
Sleep-on-exit makes integrating sleep into interrupt-heavy applications much easier. The Cortex-M3 provides very flexible sleep configuration options to balance power savings with application requirements like latency.
By following the best practices outlined here, you can efficiently apply sleep-on-exit to reduce power in your Cortex-M3 system and take advantage of the extensive low power capabilities of the architecture.