Power Management¶
Comprehensive guide to power management and optimization for Nexus embedded applications.
Overview¶
Power management is critical for battery-powered embedded systems. This guide covers power optimization strategies, sleep modes, and energy-efficient design.
Power Management Goals:
Minimize power consumption
Extend battery life
Reduce heat generation
Meet power budgets
Maintain performance requirements
Power Consumption Sources:
CPU execution
Peripheral operation
Memory access
Clock generation
I/O pin states
Leakage current
Power Modes¶
ARM Cortex-M Power Modes¶
Available Modes:
Mode |
CPU |
Peripherals |
Wake-up Time |
|---|---|---|---|
Run |
Active |
Active |
N/A |
Sleep |
Stopped |
Active |
Fast (<1µs) |
Stop |
Stopped |
Stopped |
Medium (5-50µs) |
Standby |
Off |
Off |
Slow (50-500µs) |
Power Consumption (Typical STM32F4):
Run Mode: 50-100 mA @ 168 MHz
Sleep Mode: 30-50 mA
Stop Mode: 100-500 µA
Standby Mode: 1-10 µA
Sleep Mode¶
Enter Sleep Mode:
#include "hal/nx_power.h"
void enter_sleep_mode(void)
{
/* Configure wake-up sources */
nx_power_config_wakeup(WAKEUP_UART | WAKEUP_GPIO);
/* Enter sleep mode */
nx_power_enter_sleep();
/* CPU stops here until interrupt */
/* Resume execution after wake-up */
LOG_INFO("Woke up from sleep");
}
Sleep-on-Exit (Cortex-M):
/* Enable sleep-on-exit for interrupt-driven systems */
void enable_sleep_on_exit(void)
{
SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk;
/* CPU sleeps after returning from ISR */
/* Wakes up on next interrupt */
}
FreeRTOS Idle Hook:
void vApplicationIdleHook(void)
{
/* Enter sleep when idle */
__WFI(); /* Wait For Interrupt */
}
Stop Mode¶
Enter Stop Mode:
void enter_stop_mode(void)
{
/* Save peripheral state */
save_peripheral_state();
/* Configure wake-up sources */
nx_power_config_wakeup(WAKEUP_RTC | WAKEUP_BUTTON);
/* Enter stop mode */
nx_power_enter_stop();
/* CPU and most peripherals stopped */
/* Wake up on configured interrupt */
/* Restore peripheral state */
restore_peripheral_state();
LOG_INFO("Woke up from stop mode");
}
RTC Wake-up:
void setup_rtc_wakeup(uint32_t seconds)
{
nx_rtc_t* rtc = nx_factory_rtc(0);
/* Configure RTC wake-up timer */
nx_rtc_wakeup_config_t config = {
.period = seconds,
.callback = rtc_wakeup_callback,
.user_data = NULL,
};
rtc->configure_wakeup(rtc, &config);
rtc->enable_wakeup(rtc);
nx_factory_rtc_release(rtc);
}
void rtc_wakeup_callback(void* user_data)
{
LOG_INFO("RTC wake-up triggered");
}
Standby Mode¶
Enter Standby Mode:
void enter_standby_mode(void)
{
/* Save critical data to backup SRAM or Flash */
save_critical_data();
/* Configure wake-up pin */
nx_power_config_wakeup_pin(WAKEUP_PIN_1, RISING_EDGE);
/* Enter standby mode */
nx_power_enter_standby();
/* System resets on wake-up */
/* Execution starts from reset vector */
}
Check Wake-up Source:
void check_wakeup_source(void)
{
if (nx_power_is_wakeup_from_standby()) {
uint32_t source = nx_power_get_wakeup_source();
if (source & WAKEUP_PIN_1) {
LOG_INFO("Woke up from button press");
} else if (source & WAKEUP_RTC) {
LOG_INFO("Woke up from RTC alarm");
}
/* Restore critical data */
restore_critical_data();
}
}
Clock Management¶
Dynamic Frequency Scaling¶
Adjust Clock Frequency:
typedef enum {
CLOCK_SPEED_LOW = 0, /* 16 MHz */
CLOCK_SPEED_MEDIUM, /* 84 MHz */
CLOCK_SPEED_HIGH, /* 168 MHz */
} clock_speed_t;
void set_clock_speed(clock_speed_t speed)
{
switch (speed) {
case CLOCK_SPEED_LOW:
/* Configure PLL for 16 MHz */
nx_clock_set_frequency(16000000);
LOG_INFO("Clock: 16 MHz (low power)");
break;
case CLOCK_SPEED_MEDIUM:
/* Configure PLL for 84 MHz */
nx_clock_set_frequency(84000000);
LOG_INFO("Clock: 84 MHz (balanced)");
break;
case CLOCK_SPEED_HIGH:
/* Configure PLL for 168 MHz */
nx_clock_set_frequency(168000000);
LOG_INFO("Clock: 168 MHz (high performance)");
break;
}
/* Update SystemCoreClock variable */
SystemCoreClockUpdate();
/* Reconfigure peripherals if needed */
reconfigure_peripherals();
}
Adaptive Frequency:
void adaptive_frequency_task(void* arg)
{
while (1) {
uint32_t cpu_usage = get_cpu_usage_percent();
if (cpu_usage > 80) {
/* High load - increase frequency */
set_clock_speed(CLOCK_SPEED_HIGH);
} else if (cpu_usage < 20) {
/* Low load - decrease frequency */
set_clock_speed(CLOCK_SPEED_LOW);
} else {
/* Medium load - balanced frequency */
set_clock_speed(CLOCK_SPEED_MEDIUM);
}
osal_task_delay(1000);
}
}
Peripheral Clock Gating¶
Disable Unused Peripherals:
void disable_unused_peripherals(void)
{
/* Disable unused peripheral clocks */
nx_clock_disable_peripheral(PERIPHERAL_SPI2);
nx_clock_disable_peripheral(PERIPHERAL_I2C2);
nx_clock_disable_peripheral(PERIPHERAL_USART3);
nx_clock_disable_peripheral(PERIPHERAL_TIM3);
nx_clock_disable_peripheral(PERIPHERAL_TIM4);
LOG_INFO("Disabled unused peripheral clocks");
}
Dynamic Clock Control:
void use_spi_with_clock_control(void)
{
/* Enable SPI clock before use */
nx_clock_enable_peripheral(PERIPHERAL_SPI1);
/* Use SPI */
nx_spi_t* spi = nx_factory_spi(0);
spi->transfer(spi, tx_data, rx_data, len, 1000);
nx_factory_spi_release(spi);
/* Disable SPI clock after use */
nx_clock_disable_peripheral(PERIPHERAL_SPI1);
}
Peripheral Power Management¶
GPIO Power Optimization¶
Configure GPIO for Low Power:
void configure_gpio_low_power(void)
{
/* Set unused pins to analog input (lowest power) */
for (uint8_t pin = 0; pin < 16; pin++) {
if (!is_pin_used('A', pin)) {
nx_gpio_t* gpio = nx_factory_gpio('A', pin);
gpio->set_mode(gpio, NX_GPIO_MODE_ANALOG);
nx_factory_gpio_release(gpio);
}
}
/* Disable pull-ups/pull-downs on unused pins */
/* Configure output pins to known state */
}
Output Pin States:
void set_output_pins_low_power(void)
{
/* Set output pins to low to minimize current */
nx_gpio_write_t* led = nx_factory_gpio_write('D', 12);
led->write(led, 0); /* Turn off LED */
nx_factory_gpio_release((nx_gpio_t*)led);
/* Or configure as input to save power */
nx_gpio_t* gpio = nx_factory_gpio('D', 13);
gpio->set_mode(gpio, NX_GPIO_MODE_INPUT);
nx_factory_gpio_release(gpio);
}
UART Power Management¶
UART Sleep Mode:
void uart_power_management(void)
{
nx_uart_t* uart = nx_factory_uart(0);
/* Use UART */
nx_tx_sync_t* tx = uart->get_tx_sync(uart);
tx->send(tx, data, len, 1000);
/* Enter low power mode when idle */
nx_power_t* power = uart->get_power(uart);
power->set_mode(power, NX_POWER_MODE_SLEEP);
/* UART wakes up automatically on RX activity */
nx_factory_uart_release(uart);
}
DMA for Power Savings¶
Use DMA to Allow CPU Sleep:
void uart_send_with_dma_sleep(nx_uart_t* uart,
const uint8_t* data,
size_t len)
{
/* Start DMA transfer */
nx_tx_dma_t* tx_dma = uart->get_tx_dma(uart);
tx_dma->send(tx_dma, data, len);
/* CPU can sleep while DMA transfers data */
while (!tx_dma->is_complete(tx_dma)) {
__WFI(); /* Sleep until DMA interrupt */
}
LOG_INFO("DMA transfer complete");
}
Battery Monitoring¶
Battery Voltage Measurement¶
Measure Battery Voltage:
float measure_battery_voltage(void)
{
nx_adc_t* adc = nx_factory_adc(0);
/* Configure ADC for battery measurement */
nx_adc_config_t config = {
.resolution = ADC_RESOLUTION_12BIT,
.sampling_time = ADC_SAMPLING_480_CYCLES,
};
adc->configure(adc, &config);
/* Read battery voltage (with voltage divider) */
uint16_t raw_value = adc->read(adc, ADC_CHANNEL_VBAT);
/* Convert to voltage (assuming 12-bit ADC, 3.3V ref) */
float voltage = (raw_value * 3.3f) / 4096.0f;
/* Account for voltage divider (if used) */
voltage *= 2.0f; /* Example: 1:2 divider */
nx_factory_adc_release(adc);
return voltage;
}
Battery Level Estimation:
typedef enum {
BATTERY_CRITICAL = 0, /* < 10% */
BATTERY_LOW, /* 10-25% */
BATTERY_MEDIUM, /* 25-75% */
BATTERY_HIGH, /* > 75% */
} battery_level_t;
battery_level_t get_battery_level(void)
{
float voltage = measure_battery_voltage();
/* LiPo battery voltage ranges */
const float V_MIN = 3.0f; /* Empty */
const float V_MAX = 4.2f; /* Full */
if (voltage < V_MIN) {
return BATTERY_CRITICAL;
}
float percent = ((voltage - V_MIN) / (V_MAX - V_MIN)) * 100.0f;
if (percent < 10.0f) {
return BATTERY_CRITICAL;
} else if (percent < 25.0f) {
return BATTERY_LOW;
} else if (percent < 75.0f) {
return BATTERY_MEDIUM;
} else {
return BATTERY_HIGH;
}
}
Battery Monitoring Task:
void battery_monitor_task(void* arg)
{
while (1) {
float voltage = measure_battery_voltage();
battery_level_t level = get_battery_level();
LOG_INFO("Battery: %.2fV (%s)",
voltage, battery_level_to_string(level));
if (level == BATTERY_CRITICAL) {
LOG_WARN("Battery critical - entering low power mode");
enter_emergency_low_power_mode();
} else if (level == BATTERY_LOW) {
LOG_WARN("Battery low - reducing power consumption");
reduce_power_consumption();
}
/* Check every 60 seconds */
osal_task_delay(60000);
}
}
Power Optimization Strategies¶
Interrupt-Driven Design¶
Avoid Polling:
/* Bad: Polling wastes power */
void check_button_polling(void)
{
while (1) {
if (read_button() == PRESSED) {
handle_button_press();
}
osal_task_delay(10); /* Still wastes power */
}
}
/* Good: Interrupt-driven */
void button_interrupt_handler(void* ctx)
{
handle_button_press();
}
void setup_button_interrupt(void)
{
nx_gpio_t* button = nx_factory_gpio('A', 0);
button->set_mode(button, NX_GPIO_MODE_INPUT);
button->set_exti(button, NX_GPIO_EXTI_FALLING,
button_interrupt_handler, NULL);
nx_factory_gpio_release(button);
/* CPU can sleep until button press */
}
Efficient Task Scheduling¶
Consolidate Wake-ups:
/* Bad: Multiple tasks with different periods */
void sensor_task_1(void* arg)
{
while (1) {
read_sensor_1();
osal_task_delay(100); /* Wake every 100ms */
}
}
void sensor_task_2(void* arg)
{
while (1) {
read_sensor_2();
osal_task_delay(150); /* Wake every 150ms */
}
}
/* Good: Single task with synchronized periods */
void sensor_task_combined(void* arg)
{
uint32_t count = 0;
while (1) {
if (count % 100 == 0) {
read_sensor_1();
}
if (count % 150 == 0) {
read_sensor_2();
}
count += 50;
osal_task_delay(50); /* Single wake-up period */
}
}
Batch Processing¶
Batch Operations:
/* Bad: Process data immediately */
void data_callback(uint8_t byte)
{
process_single_byte(byte); /* Frequent wake-ups */
}
/* Good: Batch processing */
#define BATCH_SIZE 64
static uint8_t batch_buffer[BATCH_SIZE];
static size_t batch_count = 0;
void data_callback_batched(uint8_t byte)
{
batch_buffer[batch_count++] = byte;
if (batch_count >= BATCH_SIZE) {
/* Process entire batch at once */
process_batch(batch_buffer, batch_count);
batch_count = 0;
}
}
Tickless Idle¶
FreeRTOS Tickless Idle:
/* Enable tickless idle in FreeRTOSConfig.h */
#define configUSE_TICKLESS_IDLE 1
/* Implement tickless idle hook */
void vApplicationSleep(TickType_t xExpectedIdleTime)
{
/* Calculate sleep duration */
uint32_t sleep_ms = xExpectedIdleTime * portTICK_PERIOD_MS;
/* Configure wake-up timer */
setup_wakeup_timer(sleep_ms);
/* Enter low power mode */
enter_stop_mode();
/* Adjust tick count after wake-up */
vTaskStepTick(xExpectedIdleTime);
}
Power Profiling¶
Measuring Power Consumption¶
Hardware Setup:
Power supply with current measurement
Multimeter or oscilloscope
Current sense resistor
Data logging
Software Profiling:
void profile_power_modes(void)
{
LOG_INFO("Starting power profiling...");
/* Measure run mode */
LOG_INFO("Run mode - measure current now");
osal_task_delay(5000);
/* Measure sleep mode */
LOG_INFO("Sleep mode - measure current now");
for (int i = 0; i < 50; i++) {
__WFI();
osal_task_delay(100);
}
/* Measure stop mode */
LOG_INFO("Stop mode - measure current now");
enter_stop_mode();
osal_task_delay(5000);
LOG_INFO("Power profiling complete");
}
Energy Calculation¶
Calculate Energy Consumption:
typedef struct {
const char* mode;
float current_ma;
uint32_t duration_ms;
} power_profile_t;
float calculate_energy(power_profile_t* profile, size_t count)
{
float total_energy_mah = 0.0f;
for (size_t i = 0; i < count; i++) {
/* Energy (mAh) = Current (mA) × Time (h) */
float time_hours = profile[i].duration_ms / 3600000.0f;
float energy = profile[i].current_ma * time_hours;
total_energy_mah += energy;
LOG_INFO("%s: %.2f mA × %.2f h = %.4f mAh",
profile[i].mode,
profile[i].current_ma,
time_hours,
energy);
}
return total_energy_mah;
}
void estimate_battery_life(void)
{
power_profile_t profile[] = {
{"Active", 50.0f, 1000}, /* 1s active */
{"Sleep", 5.0f, 9000}, /* 9s sleep */
};
/* Calculate energy per cycle (10 seconds) */
float energy_per_cycle = calculate_energy(profile, 2);
/* Calculate daily energy */
float cycles_per_day = (24.0f * 3600.0f) / 10.0f;
float energy_per_day = energy_per_cycle * cycles_per_day;
/* Estimate battery life */
float battery_capacity = 2000.0f; /* 2000 mAh */
float battery_life_days = battery_capacity / energy_per_day;
LOG_INFO("Estimated battery life: %.1f days", battery_life_days);
}
Best Practices¶
Design for Low Power from Start * Choose low-power MCU * Plan power modes * Design for sleep * Consider battery capacity
Use Appropriate Power Modes * Sleep for short idle periods * Stop for medium idle periods * Standby for long idle periods * Match mode to wake-up latency requirements
Optimize Clock Usage * Use lowest frequency that meets requirements * Disable unused peripheral clocks * Use dynamic frequency scaling * Consider external oscillator power
Minimize Active Time * Process data efficiently * Use DMA for transfers * Batch operations * Use hardware acceleration
Configure Peripherals Properly * Disable unused peripherals * Use low-power peripheral modes * Configure GPIO for low power * Use pull-ups/pull-downs appropriately
Monitor and Measure * Measure actual power consumption * Profile different modes * Calculate battery life * Optimize based on measurements
Test in Real Conditions * Test with actual battery * Test temperature effects * Test aging effects * Verify wake-up reliability
Power Optimization Checklist¶
Hardware:
[ ] Low-power MCU selected
[ ] Appropriate voltage regulator
[ ] Battery capacity adequate
[ ] Power measurement capability
Software:
[ ] Sleep modes implemented
[ ] Unused peripherals disabled
[ ] GPIO configured for low power
[ ] Interrupt-driven design
[ ] DMA used where appropriate
Testing:
[ ] Power consumption measured
[ ] Battery life calculated
[ ] Wake-up latency verified
[ ] Temperature effects tested
Optimization:
[ ] Clock frequency optimized
[ ] Active time minimized
[ ] Batch processing implemented
[ ] Tickless idle enabled
See Also¶
Performance Optimization - Performance Optimization
Memory Management - Memory Management
Best Practices - Best Practices
Platform Guides - Platform-Specific Power Features