• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP32C3 заглушка DeepSleep перестала исполняться

pvvx

Активный участник сообщества
13 ms - это пробуждение (включение) самого чипа ESP-С3 из deep-sleep:
1746722868373.png
 

pvvx

Активный участник сообщества
По старту питания ситуация аналогична - те-же 12..13 ms на приход в себя у ESP32-C3:
1746723681510.png
 

pvvx

Активный участник сообщества
Т.е. в документации 280 мкс - это всего время работы кода до чего-то. А старт до запуска CPU из отключки - более 12 мс.

Deep-sleep

Средние 519 мкА на 10 циклов сна по 1 сек. В самом Deep-sleep + светодиод и прочее = 434 мкА.

Окно в 15 мс с активностью = 6.209 мА
1746728505255.png

Light-sleep

Средние 629 мкА на 10 циклов сна по 1 сек. В самом Light-sleep + светодиод и прочее = 623 мкА.

Окно в 15 мс с активностью = 1.141 мА (это с выбросом коммутации включения-заряда емкостей в ESP и прочего)

1746728537871.png

Итог

Примерный график тока потребления в зависимости от длительности sleep:
1746728459228.png
(Это с учетом, что в deep-sleep потребление устройства равно 10 мкА, в для Light-sleep соответственно 199 мкА.)

Имеем пересечение в области 400 мс.
Т.е. для WiFi при удержании соединения с AP лучше подойдет Light-sleep.
До этого deep-sleep имеет потребление более 6 раз от light-sleep.
 

pvvx

Активный участник сообщества
Для Zigbee, если у ESP32-S6 примерно тоже-самое, тогда когда идет общение с роутером или координатором меньшее потребление будет при light-sleep. Т.к. тик в Zigbee (QT) = 1/4 секунды.
Но всё равно всё это не имеет смысла для ESP - как только врубит RF на прием или передачу - кранты всем батарейкам. Долгую работу с ESP могут выдержать только сильноточные Li АКБ - а у них саморазряд сверх большой :) :)
 

pvvx

Активный участник сообщества
Пример потребления Zigbee роутера (20.2 мА 3.3V) и измерителя на TLSR8250 c INA226 (до 0.2мА 3.3V) от одного Li-ion 18550 (2Ач):
1746730968651.png
и зарядка. Итог до 3.47В - 2.01 Ач и работа ровно 100 часов до зарядки. Общее потребление ~20.5 мА. С него и приняты замеры BLE маяками в HA. А Zigbee (типовой от Tuya) роутер вечно принимает и передает без всяких снов.
Как это сделать на ESP?
 

nikolz

Well-known member
Спросим у DeepSeek
Можешь предложить программу для ESP32 заглушки для максимально быстрого выхода из сна ESP32C3 и возврата в сон и оценить время работы такой программы
DeepSeek отвечает:
Программа для ESP32-C3 с максимально быстрым выходом из сна и возвратом в режим глубокого сна (Deep Sleep)
ESP32-C3 поддерживает Ultra-Low-Power (ULP) режимы, включая Deep Sleep, из которого можно проснуться по таймеру или внешнему сигналу (например, GPIO).

1. Оптимальная схема работы:
  1. Просыпается по таймеру или внешнему прерыванию (например, кнопка).
  2. Выполняет минимальные действия (например, чтение датчика).
  3. Мгновенно возвращается в Deep Sleep.
2. Оценка времени работы:
  • Выход из Deep Sleep: ~2–5 мс (зависит от тактовой частоты).
  • Возврат в Deep Sleep: ~1–2 мс (после завершения кода).
  • Общее время бодрствования: 3–10 мс (если код минималистичный).
Код для ESP32-C3 (Arduino IDE)

#include <esp_sleep.h>

#define WAKEUP_PIN GPIO_NUM_2 // Пин для пробуждения (можно любой RTC)

void setup() {
Serial.begin(115200);

// Настройка пина для пробуждения (если нужно)
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN, LOW); // Просыпаться по LOW на GPIO2

// ИЛИ пробуждение по таймеру (например, каждые 10 секунд)
// esp_sleep_enable_timer_wakeup(10 * 1000000); // В микросекундах

Serial.println("Проснулся! Делаю полезную работу...");

// --- Минимальная полезная нагрузка (например, чтение ADC) ---
uint16_t adc_value = analogRead(A0);
Serial.printf("ADC: %d\n", adc_value);

// --- Возврат в Deep Sleep ---
Serial.println("Возвращаюсь в сон...");
delay(1); // Даём Serial завершить передачу (опционально)
esp_deep_sleep_start(); // Мгновенный сон
}

void loop() {} // Не используется (ESP сразу уходит в сон)
Как ускорить процесс:
  1. Отключите Serial (если не нужен) — экономит ~2–5 мс.
  2. Используйте RTC-память для сохранения данных между циклами сна.
  3. Минимизируйте код между setup() и esp_deep_sleep_start().
Пример без Serial (рекордное время бодрствования ~1–3 мс):

#include <esp_sleep.h>

void setup() {
// Полезная нагрузка (например, включить светодиод на 1 мс)
pinMode(GPIO_NUM_8, OUTPUT);
digitalWrite(GPIO_NUM_8, HIGH);
delay(1);
digitalWrite(GPIO_NUM_8, LOW);

// Сон до следующего прерывания
esp_deep_sleep_enable_timer_wakeup(1000000); // 1 секунда
esp_deep_sleep_start();
}

void loop() {}
Измерение времени бодрствования
Чтобы точно замерить, сколько времени ESP32-C3 находится в активном режиме:

  1. Подключите осциллограф к GPIO (например, включать его при старте и выключать перед сном).
  2. Или используйте RTC-таймер:

    uint64_t start_time = esp_timer_get_time();
    // ... полезный код ...
    uint64_t duration = esp_timer_get_time() - start_time;
    Энергопотребление
    Deep Sleep: ~20–50 мкА (зависит от конфигурации).
    • Активный режим (на 3 мс): ~40–80 мА (на частоте 160 МГц).
  3. Итог: ESP32-C3 может просыпаться каждые 0.1 секунды и работать годами от батарейки, если код оптимизирован.
Если нужно ещё больше ускорения — можно использовать Light Sleep (просыпается за ~500 мкс, но потребляет больше энергии).
 

pvvx

Активный участник сообщества
Врет. Считает только время исполнения кода без учета старта SoC в 12 ms.
 

pvvx

Активный участник сообщества
Итог: ESP32-C3 может просыпаться каждые 0.1 секунды и работать годами от батарейки, если код оптимизирован.
И тут совравши.
CR2032 при указанных 20 мкА и импульсе за 16 мА не отработает и 8 месяцев.
CR2450 наверно протянет год, если будет всё по минимуму - до 20 мкА и никакого кода кроме входа и выхода из deep-sleep каждые пару сек.
 

pvvx

Активный участник сообщества
Для средней паршивости CR2032 всё просто - после 60% разряда у неё внутренне сопротивление будет к 100 Ом. А при токе 16 мА это составит падение в 1.6В от химии в 3.0В и выйдет всего 1.4В, чего ну ни как не достаточно для работы ESP-С3. В итоге выкачав половину заряда из CR2032 ESP-C3 просто не сможет стартануть.
 

pvvx

Активный участник сообщества
У EFR32MG21 старт из отключки SoC аж 17.8 ms до старта исполнения кода из Flash.
Но для deep-sleep предусмотрено сохранение внутренних потрохов для быстрого рестарта уже в 12.2 us.
Всё это типично, но с плюс - минус для других специализированных для быстрого пробуждения чипов.
А в ESP этого не предусмотрено - при deep-sleep вырубается всё и новый старт обходится от 12 ms, как при первом включении питания на SoC.
По рестарту надо включить и питание на Flash - на это так-же уходит время...
 

pvvx

Активный участник сообщества
Включение питания на SPI-Flash (в доках для низковольтных Flash) параметр времени старта указан как 1..10 ms. Т.е. минимум 1 ms !
"Program, Erase and Write command are ignored" в течении до 10ms.
В BLE/Zigbee чипах питание FLash и RAM (если выставлены флаги) на deep-sleep не отключается. А дается команда перехода в сон и напряжение питания понижается для минимизации утечки.
 

pvvx

Активный участник сообщества
На другом модуле ESP32-C3 c внешней Flash наблюдаем те-же 12..13 ms на время пробуждения SoC:
1746783393134.png
 

pvvx

Активный участник сообщества
Ущё враньё DeepSeek. Но это не ИИ врет, а пользователи ESP создали такой спам :)

Указанный пример:
Код:
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  1          /* Time ESP32 will go to sleep (in seconds) */

void setup() {
  // Полезная нагрузка (например, включить светодиод на 1 мс)
  pinMode(GPIO_NUM_8, OUTPUT);
  digitalWrite(GPIO_NUM_8, HIGH);
  delay(1);
  digitalWrite(GPIO_NUM_8, LOW);
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
}

void loop() {
}
Итог:
1746786879190.png
1. Всё те-же 13 ms прихода в себя SoC.
2. До старта инициализации в Arduino проходит 26 ms
3. Вывод нуля на GPIO наблюдаем через 40 ms от начала пробуждения SoC по таймеру.

Работа с GPIO в ESP как всегда некорректна. При инициализации GPIO возникает импульс.
 

pvvx

Активный участник сообщества
Не тот диапазон тока включил (срабатывало ограничение в 24 мА).
На большем диапазоне, чтобы видно было ток работы в Arduino:
1746787574937.png
Клетка тока как и указано для синего - 5 мА.
 

pvvx

Активный участник сообщества
И для сравнения в nRF Power Profiler Kit II (PPK2) тоже самое (при установке напряжения 3.3В):
1746789331644.png
В низу график GPIO вывода...

1746789508678.png
 

pvvx

Активный участник сообщества
И расчет сколько это проработает от батарейки CR2032 указывает на 7 дней :ROFLMAO: Далее сбой из-за просадки напряжения ниже 1.6B при токе в 32 мА на старте инициализации Arduino.
 

pvvx

Активный участник сообщества
А вы знаете чип nRF или TLSR и т.д. с таким RAM и FLASH и скоростью процессора? И по таким ценам?
Кто-то там говорил о производительности ESP32-C3.
Попробуем посчитать реальную производительность ESP32-C3 для больших объемов кода или для задач, где фигурирует чтение-запись Flash (вызывающая полное опустошение кэша CPU).
Для примера создадим задачу из трех сумм и одного умножения 32-х битного числа со знаком...
И сделаем это 10 раз и надеемся, что компилятор не оптимизировал добирающуюся последовательность.
Плюс для анализа времени выполнения вывода GPIO добавим тестовые переключения.
Скетч
Код:
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  1          /* Time ESP32 will go to sleep (in seconds) */

int speed_test(int a) {
  volatile int b = 0;
  volatile int c;
  a++;
  b++;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  c = a + b;
  a = c + b;
  b = a - c;
  b = b * c;

  return b;
}

void setup() {
  // Полезная нагрузка (например, включить светодиод на 1 мс)
  pinMode(GPIO_NUM_8, OUTPUT); // стартовый импульс в "0"
  // вывод импулса в "0" длительностью 1 us -_-
  digitalWrite(GPIO_NUM_8, HIGH);
  digitalWrite(GPIO_NUM_8, LOW);
  // кривая задержка != 1
  delay(1);
  digitalWrite(GPIO_NUM_8, HIGH); // фронт в "1" старта отсчета времени испольнения теста
  speed_test(22); // время исполнения 11.8 мкс !
  // импульс в "0" -_-  длительностью 1 мкс
  digitalWrite(GPIO_NUM_8, LOW);
  // импульс "1" _-_ длительностью 1 мкс
  digitalWrite(GPIO_NUM_8, HIGH);
  // импульс "0" -_ длительностью до выхода в deep-sleep (до отключения SoC)
  digitalWrite(GPIO_NUM_8, LOW);
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
}

void loop() {
}
Соберем с максимальными частотами и QIO к Flash.
1746795146815.png
В итоге получаем такой тайминг GPIO:
1746795187949.png

Анализируем и получаем время переключения GPIO = чуть менее 1 мкс.
1746795214269.png
Время исполнения тестовой процедуры выходит 11.9 - 0.9 = 11 мкс

Делим на количество арифметических операции в тесте (42) и получаем 11/42=0.262 мкс.

Итог:

Среднее время выполнения одной операции целочисленной числодробилки на ESP32-C3 равно 260 нс.

= 3846154 операций в секунду.
Т.е. производительность ESP32-C3 на CLK в 160 MHz не более чем у CPU в 4..6 MHz типа Cortex M0.

Это при условии размещения программы в Flash и частичного не попадания в кэш CPU. В реальных вычислениях может быть всё гораздо хуже.
 

aZholtikov

Active member
Уважаемый @pvvx.
А если этот тест запустить не в столь Вами "обожаемом" Arduino, а в ESP-IDF с установленным флагом CONFIG_COMPILER_OPTIMIZATION_PERF=y?
Разница будет?
 

pvvx

Активный участник сообщества
Уважаемый @pvvx.
А если этот тест запустить не в столь Вами "обожаемом" Arduino, а в ESP-IDF с установленным флагом CONFIG_COMPILER_OPTIMIZATION_PERF=y?
Разница будет?
Разницы не должно быть. Производится измерение времени выполнения процедуры, а тип среды IDE тут ни при чем.
Цель тут в том, чтобы добиться линейного кода, когда отрабатывается заполнение кэш. Хорошая оптимизация компилятором может оптимизировать данный код вообще в nop, т.к. результат вызова процедуры не используется. А надо проверить производительность списка команд и лучше вообще выключить любую оптимизацию компилятору...

И разница будет если разместить все коды в IRAM. Но это не задача для данного теста, т.к. нужно измерить производительность кода из Flash.
Реальные задачи могут содержать множество вызовов отдельных процедур, которые будут кэшироваться по мере их вызова.
 
Последнее редактирование:
Сверху Снизу