Measuring the Power Cost of Serial Logging
Every milliampere counts when deploying battery-powered sensors in the field. Developers often spend weeks refining deep sleep cycles and optimizing radio transmissions while overlooking a silent energy thief: the UART peripheral. While serial logging helps during the prototyping phase, leaving diagnostic strings in production code creates a significant power penalty.
The Hidden Cost of UART Communication
The ESP32-C6 features a high-performance RISC-V core and a dedicated Low Power (LP) core. When the CPU executes a logging command, like ESP_LOGI or printf, it populates a hardware FIFO buffer. If the buffer fills up, the CPU blocks and waits for space. Even if the buffer does not fill, the UART peripheral requires a high-frequency clock source to maintain timing accuracy. This requirement keeps internal oscillators and power domains active far longer than the application logic requires, preventing the SoC from entering light sleep or deep sleep.
Consider a device that wakes up once per hour to report a sensor reading to the Hubble Network. If the code prints ten lines of status updates, the device spends an extra 70 milliseconds in a high-current state. For a sensor powered by a small coin cell, these milliseconds represent months of lost battery life over a year of deployment.
Measuring the Serial Penalty
To see this drain in real-time, you can use the Nordic Power Profiler Kit II (PPK2). It provides the resolution needed to see the micro-ampere spikes caused by UART activity. By measuring current at the 3.3V rail, you can compare the power profile of a chatty application against a silent one.
Before you start writing code, modify your project’s global log level in menuconfig. Navigate to Component config > Log output > Default log verbosity (CONFIG_LOG_DEFAULT_LEVEL) and switch to Info to enable serial logging and No output to disable it.
Then, you can use the following code to see the power usage of every log statement. It contains a GPIO signal to mark the start and end of a logging event so that you can easily identify it in your power trace. By using uart_wait_tx_idle_polling, we force the CPU to stay active until the transmission is physically complete, ensuring the power profiler captures the true energy cost of the UART hardware.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "esp_rom_sys.h"
#define MARKER_GPIO GPIO_NUM_2
static const char *TAG = "PowerTest";
void app_main(void) {
gpio_reset_pin(MARKER_GPIO);
gpio_set_direction(MARKER_GPIO, GPIO_MODE_OUTPUT);
while (1) {
// Set the GPIO pin to HIGH
gpio_set_level(MARKER_GPIO, 1);
// Forced pulse keeps this block visible in the power curve even when logging is disabled
esp_rom_delay_us(100);
// This line is removed by the preprocessor if log level is set to NONE
ESP_LOGI(TAG, "Measuring true UART power penalty including hardware TX time.");
// Wait for UART hardware to finish to see the full power plateau
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
// Set the GPIO pin to LOW
gpio_set_level(MARKER_GPIO, 0);
// Delay for 1 second so the logging power curve is easily distinguishable from baseline
vTaskDelay(pdMS_TO_TICKS(1000));
}
}Logging Enabled: The “Plateau” Effect
When logging is active, you’ll notice that your power curve shows a sustained plateau. Even after the CPU has finished executing the ESP_LOGI instruction, the current draw remains high for the entire duration of the hardware transmission, which is around 7 milliseconds. This occurs because the APB_CLK must remain active to drive the UART baud rate generator, effectively locking the SoC out of low-power sleep states.

Logging Disabled: The “Spike” Effect
With logging disabled, you’ll notice the plateau disappears. In its place, you will see a sharp, narrow pulse where the CPU briefly wakes to process logic before immediately dropping back to a micro-ampere baseline. By removing the UART dependency, you allow the hardware power management unit (PMU) to gate the high-frequency oscillators the moment the application code finishes, saving thousands of micro-joules per wake cycle.

Production Workflow Strategies
Managing logs during development requires a balanced approach. You need information to debug issues, but you cannot afford the energy cost in the final product.
- Global Log Level Control: In
menuconfig, setCONFIG_LOG_DEFAULT_LEVELtoNONE. This instruction tells the compiler to exclude all logging macros from the binary. - Bootloader Logging: Set
CONFIG_BOOTLOADER_LOG_LEVELtoNONEto save energy during the initial startup sequence. - Increase Baud Rates: If you must keep logging enabled, increase the baud rate to 921600. A faster bit rate allows the UART FIFO to empty sooner, letting the SoC enter a sleep state faster.
Field-ready hardware requires an uncompromising focus on efficiency. Removing serial logging is a simple change that produces immediate, measurable improvements in battery longevity. By verifying the results with a power profiler and syncing your measurements with GPIO markers, you ensure your project is optimized for the Hubble Network.
Ready to connect your devices anywhere on Earth? Get started with Hubble Network for free →