• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Дикое потребление ESP32-C3 в BLE (Arduino)

pvvx

Активный участник сообщества
Модули ESP32-C3S от Ai-Thinker...
Потребовалось слепить экономичный приемник BLE рекламы с одного устройства...
В качестве испытуемого передатчика BLE рекламы взял Xiaomi LYWSD03MMC.
Код:
/*
 * Test Advertisements Scanning
 */
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEScan.h>
#include "BLEDevice.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/gpio_ll.h" 
#define USE_LIGH_SLEEP 1 // 1 - on, 0 - off
#if USE_LIGH_SLEEP
#define eprintf // no printf
#else
#define eprintf printf
#endif
#define SCAN_TIME_DEF 21 // seconds
int scanTime = SCAN_TIME_DEF; // seconds
int stage = 0;
int delay_ms = 50;
uint32_t period_min_ms, period_max_ms;
BLEAddress inMacAddress = BLEAddress("a4:c1:38:0b:5e:ed"); // The remote data device MAC
uint32_t tik_scan, rx_all_count = 0, rx_err_count = 0;
boolean flag_delay = false;
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      if (inMacAddress.equals(advertisedDevice.getAddress())) {
        uint32_t tt = millis();
        uint32_t delta = tt - tik_scan;
        tik_scan = tt;
        pBLEScan->stop();
        pBLEScan->clearResults();
        flag_delay = true;
        if(stage) {
          if (stage == 1) {
            period_min_ms = delta;
            period_max_ms = delta;
            delay_ms = delta - 20;
            scanTime = 1 + (period_max_ms + 250)/500; // sec 
            eprintf("Sheck period: %u ms, delay: %u, scanTime: %d\n", delta, delay_ms, scanTime);
            stage = 2;
          }          
          if(rx_all_count++) {
            if(delta > period_max_ms) {
              if(delta > period_max_ms + (period_max_ms>>2)) {
                rx_err_count++;
              } else 
                period_max_ms = delta;
            } else if (delta < period_min_ms) {
              period_min_ms = delta;
              delay_ms = period_min_ms - 20;
              scanTime = 1 + (period_max_ms + 250)/500; // sec
              eprintf("Correct min period: %u ms, delay: %u, scanTime: %d\n", delta, delay_ms, scanTime);
            }
          }
          eprintf("delta: %d ms (%u..%u), lost: %u, total: %u\n", delta, period_min_ms, period_max_ms, rx_err_count, rx_all_count);
        } else {
            eprintf("Start calk delta...\n");
            stage = 1;
        } 
      }
    }
};
void setup() {
  CLEAR_PERI_REG_MASK(USB_DEVICE_CONF0_REG, USB_DEVICE_USB_PAD_ENABLE);
#if (!USE_LIGH_SLEEP)
  pinMode(PIN_X, OUTPUT);
  digitalWrite(PIN_X, LOW); 
  Serial.begin(115200);
  Serial.println("Test Scanning");
#endif  
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true);
  //pBLEScan->setInterval(100); // default 100
  //pBLEScan->setWindow(100);  // default 100, less or equal setInterval value
  eprintf("Start scan (%u sec).\n", scanTime);
  tik_scan = millis();
}
void LSleep(uint32_t ms) {
#if (!USE_LIGH_SLEEP)
  Serial.flush( true ); // wait for all data to be sent out UART
#else 
  for (int gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
    if (GPIO_IS_VALID_GPIO(gpio_num)) {
      if (gpio_num <= GPIO_NUM_5) {
        REG_CLR_BIT(RTC_CNTL_PAD_HOLD_REG, BIT(gpio_num));
      } else {
        CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
      }
    }
  }
#endif  
  esp_sleep_enable_timer_wakeup (ms * 1000); 
  esp_light_sleep_start();
#if (USE_LIGH_SLEEP)  
  CLEAR_PERI_REG_MASK(USB_DEVICE_CONF0_REG, USB_DEVICE_USB_PAD_ENABLE);
#endif
}
void loop() {
  pBLEScan->setActiveScan(false);
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  if(flag_delay) {
    flag_delay = false;
#if (USE_LIGH_SLEEP)
    if(delay_ms > 5)
      LSleep(delay_ms);
    else
#endif
    if(delay_ms > 0)
      delay(delay_ms);
  } else {
     eprintf("Timeout scan! Last scan %u ms.\n", millis() - tik_scan);
     stage = 0;
     scanTime = SCAN_TIME_DEF; // sec
  }
}
В принципе работает - вычисляет длительность advertising interval у передатчика и далее пытается окном принимать рекламные пакеты, а в остальное время спит (если нет пропусков и не нужна новая подстройка интервала). Спит и окном - чтобы меньше жрал.
Но ничего хорошего, как всегда c ESP, не вышло.
1641838562082.png
Вот так оно входит в light_sleep - что-то тама в черном ящике заряжается и не успевает упасть до обещанных Espressif в PDF значений в режиме light_sleep, как надо уже новую рекламку принимать...
Окно приема кушает примерно так:
1641838919359.png
Снижение частоты CPU с 160 на 80МГц ничего существенного не дает - среднее потребление в 15 мА (при приеме рекламы с интервалом 2.5 сек, как на диаграммах) падает не более чем на 1 мА.
На плате ESP32-C3-32S_Kit всё ещё хуже - при включении любого sleep врубается что-то в SERIAL_USB_JTAG и выставляет на ногу GPIO19 "1" и светит светодиодом :)

Что надо сделать, чтобы ток упал до обещанных Espressif для ESP3-C3?
Иначе это какой-то кошмар, т.к. любой другой чип имеет потребление при включенном BLE приемнике 5..6 мА, а если ещё держать прием окном - выйдет менее 1 мА (т.е. не менее чем в 15 раз меньше чем у ESP32-C3).
 

pvvx

Активный участник сообщества
К примеру приемник всех BLE реклам на TLSR825x с одновременно включенным BLE device выдающем advertising c интервалом 1 сек, работающем CPU на 24MHz без всяких sleep, вечно включенном приемнике RF:
1642094732658.png
потребляет всего в среднем 5.87 мА.
Мелкие пички вниз на графике - это прием и обработка принятых BLE реклам, большие - передача рекламы устройства...

Что такого наворотили в ESP32-C3, что он жрет за 80 мА при тех-же действиях?
 
Сверху Снизу