The "Holy Bible" for embedded engineers
Comprehensive guide to implementing power management strategies including tickless idle, Dynamic Frequency Scaling (DFS), and sleep modes in embedded real-time systems with FreeRTOS examples
Power management in real-time systems is like having a smart thermostat that knows when you’re home and when you’re away. Instead of running at full power all the time, the system intelligently adjusts its power consumption based on what it needs to do, saving energy while still being ready to respond quickly when needed.
In battery-powered embedded systems, power consumption directly determines how long your device can run. Without good power management, your device might only last hours instead of days or weeks. But power management must be smart - it can’t save power at the expense of missing critical real-time deadlines.
// Tickless idle configuration in FreeRTOS
void vApplicationIdleHook(void) {
// Calculate how long we can sleep
uint32_t next_wake_time = xTaskGetNextWakeTime();
uint32_t current_time = xTaskGetTickCount();
uint32_t sleep_duration = next_wake_time - current_time;
if (sleep_duration > configMINIMAL_SLEEP_TIME) {
// Enter deep sleep mode
enter_deep_sleep(sleep_duration);
// Compensate for time spent sleeping
vTaskStepTick(sleep_duration);
}
}
// Dynamic frequency scaling
void adjust_cpu_frequency(uint32_t required_performance) {
if (required_performance < 25) {
// Low performance needed - reduce frequency
set_cpu_frequency(CPU_FREQ_LOW);
} else if (required_performance < 75) {
// Medium performance needed
set_cpu_frequency(CPU_FREQ_MEDIUM);
} else {
// High performance needed
set_cpu_frequency(CPU_FREQ_HIGH);
}
}
Good power management is about being smart about when to use power and when to save it, ensuring your system meets all its timing requirements while maximizing battery life.
Power management is critical in embedded real-time systems, especially battery-powered devices. Effective power management strategies like tickless idle and Dynamic Frequency Scaling can significantly extend battery life while maintaining real-time performance requirements.
1. CPU Power:
2. Memory Power:
3. Peripheral Power:
4. System Power:
1. Clock Management:
2. Voltage Management:
3. Sleep Mode Management:
Tickless idle allows the RTOS to enter deep sleep modes without periodic tick interrupts, significantly reducing power consumption during idle periods while maintaining real-time responsiveness.
Traditional vs Tickless:
Core Components:
Implementation Flow:
Idle Task → Calculate Sleep Time → Enter Sleep Mode → Wake on Event → Compensate Ticks
Configuration Options:
// FreeRTOSConfig.h
#define configUSE_TICKLESS_IDLE 1
#define configTICKLESS_IDLE_MS 1000
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 3
#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 1
Implementation Example:
// Tickless idle hook function
void vApplicationIdleHook(void) {
// Check if we can enter tickless mode
if (xTaskGetIdleRunTimeCounter() > configEXPECTED_IDLE_TIME_BEFORE_SLEEP) {
// Enter tickless idle mode
vEnterTicklessIdle();
}
}
// Enter tickless idle mode
void vEnterTicklessIdle(void) {
TickType_t expected_idle_time;
TickType_t actual_sleep_time;
// Calculate expected idle time
expected_idle_time = xTaskGetIdleRunTimeCounter();
// Configure wake-up timer
vConfigureWakeupTimer(expected_idle_time);
// Enter sleep mode
actual_sleep_time = vEnterSleepMode();
// Compensate for actual sleep time
vTicklessIdleCompensation(actual_sleep_time);
}
Timer Setup:
typedef struct {
TIM_HandleTypeDef htim;
uint32_t wakeup_time_ticks;
bool timer_configured;
} wakeup_timer_t;
wakeup_timer_t g_wakeup_timer = {0};
void vConfigureWakeupTimer(TickType_t sleep_ticks) {
uint32_t sleep_ms = pdTICKS_TO_MS(sleep_ticks);
// Configure timer for wake-up
g_wakeup_timer.htim.Instance = TIM2;
g_wakeup_timer.htim.Init.Prescaler = 83999; // 84MHz / 84000 = 1kHz
g_wakeup_timer.htim.Init.Period = sleep_ms - 1;
g_wakeup_timer.htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
g_wakeup_timer.htim.Init.CounterMode = TIM_COUNTERMODE_UP;
g_wakeup_timer.htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&g_wakeup_timer.htim) == HAL_OK) {
// Enable timer interrupt
HAL_TIM_Base_Start_IT(&g_wakeup_timer.htim);
g_wakeup_timer.timer_configured = true;
}
}
Sleep Mode Entry:
TickType_t vEnterSleepMode(void) {
TickType_t start_time = xTaskGetTickCount();
TickType_t sleep_duration = 0;
// Disable interrupts except wake-up source
__disable_irq();
// Configure system for sleep
vConfigureSystemForSleep();
// Enter sleep mode
__WFI(); // Wait for interrupt
// System has woken up
__enable_irq();
// Calculate actual sleep time
TickType_t end_time = xTaskGetTickCount();
sleep_duration = end_time - start_time;
// Restore system configuration
vRestoreSystemFromSleep();
return sleep_duration;
}
Dynamic Frequency Scaling (DFS) allows the CPU frequency to be adjusted at runtime based on system load, performance requirements, and power constraints.
DFS Benefits:
1. Load-Based Scaling:
2. Deadline-Based Scaling:
3. Power-Aware Scaling:
Clock Configuration:
typedef struct {
uint32_t frequency_hz;
uint32_t prescaler;
uint32_t period;
uint8_t power_level;
} frequency_config_t;
frequency_config_t frequency_levels[] = {
{84000000, 0, 0, 3}, // High performance
{42000000, 1, 0, 2}, // Medium performance
{21000000, 3, 0, 1}, // Low performance
{10500000, 7, 0, 0} // Power saving
};
uint8_t current_frequency_level = 0;
bool vSetCPUFrequency(uint8_t level) {
if (level >= sizeof(frequency_levels) / sizeof(frequency_levels[0])) {
return false;
}
frequency_config_t *config = &frequency_levels[level];
// Configure PLL for new frequency
if (vConfigurePLL(config->frequency_hz)) {
// Update system clock
SystemCoreClockUpdate();
// Update FreeRTOS tick frequency
vUpdateFreeRTOSClock();
current_frequency_level = level;
printf("CPU frequency set to %lu Hz\n", config->frequency_hz);
return true;
}
return false;
}
PLL Configuration:
bool vConfigurePLL(uint32_t target_frequency) {
RCC_OscInitTypeDef osc_init = {0};
RCC_ClkInitTypeDef clk_init = {0};
// Configure PLL
osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
osc_init.HSEState = RCC_HSE_ON;
osc_init.PLL.PLLState = RCC_PLL_ON;
osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
// Calculate PLL parameters
uint32_t hse_freq = 8000000; // 8MHz external crystal
uint32_t pll_m = 8; // HSE / 8 = 1MHz
uint32_t pll_n = target_frequency / 1000000; // Target frequency in MHz
uint32_t pll_p = 2; // PLL output / 2
osc_init.PLL.PLLM = pll_m;
osc_init.PLL.PLLN = pll_n;
osc_init.PLL.PLLP = pll_p;
if (HAL_RCC_OscConfig(&osc_init) != HAL_OK) {
return false;
}
// Configure system clock
clk_init.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
clk_init.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&clk_init, FLASH_LATENCY_2) != HAL_OK) {
return false;
}
return true;
}
CPU Load Monitoring:
typedef struct {
uint32_t total_idle_time;
uint32_t total_run_time;
uint32_t load_percentage;
uint32_t update_counter;
} cpu_load_monitor_t;
cpu_load_monitor_t g_cpu_load = {0};
void vUpdateCPULoad(void) {
static uint32_t last_idle_time = 0;
uint32_t current_idle_time = xTaskGetIdleRunTimeCounter();
// Calculate load over time window
uint32_t idle_delta = current_idle_time - last_idle_time;
uint32_t total_delta = pdMS_TO_TICKS(1000); // 1 second window
g_cpu_load.total_idle_time += idle_delta;
g_cpu_load.total_run_time += (total_delta - idle_delta);
g_cpu_load.update_counter++;
// Update load percentage every second
if (g_cpu_load.update_counter >= 1000) {
g_cpu_load.load_percentage = (g_cpu_load.total_run_time * 100) /
(g_cpu_load.total_idle_time + g_cpu_load.total_run_time);
// Reset counters
g_cpu_load.total_idle_time = 0;
g_cpu_load.total_run_time = 0;
g_cpu_load.update_counter = 0;
// Adjust frequency based on load
vAdjustFrequencyByLoad();
}
last_idle_time = current_idle_time;
}
Frequency Adjustment Logic:
void vAdjustFrequencyByLoad(void) {
uint8_t new_level = current_frequency_level;
if (g_cpu_load.load_percentage > 80) {
// High load - increase frequency
if (current_frequency_level > 0) {
new_level = current_frequency_level - 1;
}
} else if (g_cpu_load.load_percentage < 30) {
// Low load - decrease frequency
if (current_frequency_level < 3) {
new_level = current_frequency_level + 1;
}
}
// Apply frequency change if needed
if (new_level != current_frequency_level) {
vSetCPUFrequency(new_level);
}
}
1. Light Sleep:
2. Deep Sleep:
3. Hibernation:
Sleep Mode Configuration:
typedef enum {
SLEEP_MODE_ACTIVE,
SLEEP_MODE_LIGHT,
SLEEP_MODE_DEEP,
SLEEP_MODE_HIBERNATION
} sleep_mode_t;
typedef struct {
sleep_mode_t current_mode;
uint32_t wakeup_sources;
bool state_retention;
uint32_t wakeup_time_ms;
} sleep_config_t;
sleep_config_t g_sleep_config = {
.current_mode = SLEEP_MODE_ACTIVE,
.wakeup_sources = 0,
.state_retention = true,
.wakeup_time_ms = 1000
};
void vConfigureSleepMode(sleep_mode_t mode, uint32_t wakeup_sources) {
g_sleep_config.current_mode = mode;
g_sleep_config.wakeup_sources = wakeup_sources;
switch (mode) {
case SLEEP_MODE_LIGHT:
vConfigureLightSleep(wakeup_sources);
break;
case SLEEP_MODE_DEEP:
vConfigureDeepSleep(wakeup_sources);
break;
case SLEEP_MODE_HIBERNATION:
vConfigureHibernation(wakeup_sources);
break;
default:
break;
}
}
Light Sleep Implementation:
void vConfigureLightSleep(uint32_t wakeup_sources) {
// Configure wake-up sources
if (wakeup_sources & WAKEUP_SOURCE_TIMER) {
// Enable timer interrupt
HAL_TIM_Base_Start_IT(&g_wakeup_timer.htim);
}
if (wakeup_sources & WAKEUP_SOURCE_GPIO) {
// Configure GPIO interrupt
vConfigureGPIOWakeup();
}
if (wakeup_sources & WAKEUP_SOURCE_UART) {
// Configure UART interrupt
vConfigureUARTWakeup();
}
// Configure system for light sleep
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
}
Deep Sleep Implementation:
void vConfigureDeepSleep(uint32_t wakeup_sources) {
// Save critical system state
vSaveSystemState();
// Configure wake-up sources
vConfigureWakeupSources(wakeup_sources);
// Enter deep sleep mode
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// System has woken up
// Restore system state
vRestoreSystemState();
// Reconfigure system clock
SystemClock_Config();
}
typedef struct {
bool tickless_enabled;
bool dfs_enabled;
sleep_mode_t sleep_mode;
uint8_t frequency_level;
uint32_t power_consumption_mw;
uint32_t battery_level_percent;
} power_management_system_t;
power_management_system_t g_power_mgr = {0};
void vInitializePowerManagement(void) {
// Initialize power management system
g_power_mgr.tickless_enabled = true;
g_power_mgr.dfs_enabled = true;
g_power_mgr.sleep_mode = SLEEP_MODE_ACTIVE;
g_power_mgr.frequency_level = 0;
g_power_mgr.power_consumption_mw = 0;
g_power_mgr.battery_level_percent = 100;
// Configure tickless idle
if (g_power_mgr.tickless_enabled) {
vConfigureTicklessIdle();
}
// Configure DFS
if (g_power_mgr.dfs_enabled) {
vInitializeDFS();
}
// Start power monitoring task
xTaskCreate(vPowerMonitoringTask, "PowerMon", 256, NULL, 1, NULL);
printf("Power management system initialized\n");
}
void vPowerMonitoringTask(void *pvParameters) {
TickType_t last_wake_time = xTaskGetTickCount();
while (1) {
// Update CPU load
vUpdateCPULoad();
// Monitor battery level
vUpdateBatteryLevel();
// Adjust power management based on conditions
vAdjustPowerManagement();
// Update power consumption
vUpdatePowerConsumption();
// Wait for next monitoring cycle
vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(1000));
}
}
void vAdjustPowerManagement(void) {
// Adjust frequency based on battery level
if (g_power_mgr.battery_level_percent < 20) {
// Low battery - use power saving mode
if (g_power_mgr.frequency_level < 3) {
vSetCPUFrequency(3);
}
} else if (g_power_mgr.battery_level_percent < 50) {
// Medium battery - use balanced mode
if (g_power_mgr.frequency_level < 2) {
vSetCPUFrequency(2);
}
}
// Adjust sleep mode based on system activity
if (g_power_mgr.power_consumption_mw < 100) {
// Low power consumption - can use deeper sleep
if (g_power_mgr.sleep_mode != SLEEP_MODE_DEEP) {
vConfigureSleepMode(SLEEP_MODE_DEEP, WAKEUP_SOURCE_TIMER | WAKEUP_SOURCE_GPIO);
}
} else {
// Higher power consumption - use light sleep
if (g_power_mgr.sleep_mode != SLEEP_MODE_LIGHT) {
vConfigureSleepMode(SLEEP_MODE_LIGHT, WAKEUP_SOURCE_TIMER | WAKEUP_SOURCE_GPIO);
}
}
}
Tickless Idle Considerations:
DFS Considerations:
Optimization Strategies:
Objective: Implement basic tickless idle in FreeRTOS Steps:
Expected Outcome: Significant power savings during idle periods
Objective: Implement CPU frequency adjustment based on workload Steps:
Expected Outcome: Adaptive power management based on system needs
Objective: Implement multiple sleep modes with fast wake-up Steps:
Expected Outcome: Fast wake-up times while maintaining power savings
This comprehensive Power Management document provides embedded engineers with the theoretical foundation, practical implementation examples, and best practices needed to implement effective power management systems in real-time environments.