Стремительный рост IoT сместил фокус с простого подключения к интернету на энергоэффективность. Микроконтроллеры вроде ESP32-C6 с архитектурой RISC-V и поддержкой Wi-Fi 6, Thread и BLE всё чаще работают на границе сети там, где замена батарейки — целая проблема. Железо проектируют с оглядкой на низкое потребление, но программная прослойка SDK часто сводит эти старания на нет. Плохой софт держит периферию активной, промахивается с частотами ядра или будит процессор без нужды — и миллиамперы утекают впустую.
В свежем тесте сравнили три фреймворка: Arduino (простота), Zephyr RTOS (портируемость) и ESP-IDF (прямой доступ к железу). Всё замеряли на плате ESP32-C6, запитав её от профилировщика Otii Ace стабильными 3.6 В. Данные снимали по четырём синхронизированным каналам: основной ток, мощность, напряжение и UART RX. Сами сценарии построили по слоям. Сначала «пустой» скетч с бесконечным циклом — чтобы увидеть фоновую активность SDK и состояние клоков без задач. Затем опорный тест, где работал только UART с командами STR и END — он показал цену самой синхронизации. Активные нагрузки имитировали типичные задачи периферийных вычислений: мигание светодиодом (работа с GPIO), расчёт CRC8 (проверка данных датчиков) и умножение чисел с плавающей точкой (калибровка сенсоров, простейшая аналитика). Важно: Wi-Fi и BLE не инициализировались ни в одном тесте.
Чтобы исключить ошибки ручных замеров, написали Python-движок на базе Otii TCP API. Каждую нагрузку гоняли пять итераций по 60 секунд с 20-секундным отключением питания для охлаждения. Движок автоматически отсекал стартовые всплески тока по стационарному участку, а сырые данные сохранял в NumPy .npy-файлах для точности.
Жёсткое правило — заводские настройки «из коробки», никаких ручных правок флагов компилятора, линковщика или режимов питания. Это означает, что лёгкий сон, глубокий сон и пробуждение от RTC не включались, так что замеры показывают стандартное поведение в активном/холостом режиме, а не предельно достижимые микроамперы. За кулисами же компиляторы отличались заметно: ESP-IDF v5.5 Master использовал GCC 14.2.0 с ключом -O3 (оптимизация по скорости), Arduino Core v3.3.5 — GCC 12.2.0 с -Os (оптимизация по размеру), Zephyr RTOS v4.3.99 — тоже GCC 12.2.0 с -Os через West.
Цифры получились показательные. Пустой цикл ESP-IDF держал в среднем 24.77 мА, Arduino — 33.57 мА, Zephyr — 31.53 мА. Активные тесты ESP-IDF выполнял стабильно в районе 24.77–25.50 мА. Arduino на мигании светодиодом внезапно показал чуть меньше, чем ESP-IDF (25.35 мА против 25.50), — вероятно, из-за более плотного кода обёрток GPIO под -Os. Но главный сюрприз преподнёс пустой цикл Arduino: он потреблял на 35% больше, чем в активных тестах. Похоже, init() оставляет фоновые службы вроде радиостэка или скоростных клоков в боевой готовности, и холостая петля только жжёт энергию.
Zephyr RTOS стабильно проигрывал ESP-IDF 2–3 мА на всех активных нагрузках. Это плата за аппаратную абстракцию и модульный планировщик — для простых однотипных задач батарейка сядет примерно на 10–12% быстрее по сравнению с нативной разработкой.
Самый драматичный момент случился при умножении float в Arduino. На всех пяти итерациях ровно между 49.38 и 49.41 секунды происходил стабильный крах — Stack Overflow. Анализ кода выявил две ошибки: передачу форматной строки “%.4f” напрямую в Serial1.write() вместо функции форматированного вывода (указатель полез не туда) и отсутствие return в не-void-функции, что разрушало стек постепенно. Прошивка не просто падала — моменту сбоя предшествовали броски тока, а обработка исключений не дала чипу остаться в номинальном режиме. Иными словами, баг — это ещё и энергетическое событие, а профиль питания может работать как побочный канал обнаружения нестабильности кода.
Итог однозначен: ESP-IDF лидирует по стабильности и низкому потреблению без допиливания, Arduino хорош в активных сценариях, но требует осторожности со стеком и фоновыми процессами, Zephyr самый прожорливый, зато даёт переносимость между чипами. Исследование провёл Кевин Леон, специалист по встраиваемой и космической безопасности.