Запустить esp32 без FreeRTOS, чтобы выполнить что-то быстрее

В настоящее время я запускаю Arduino с этой конфигурацией (с использованием чипа atmega328p):

В принципе, моя программа просыпается каждые 2 секунды в течение 10 мс каждый раз. Если в течение этих 10 мс он найдет и событие, представляющее интерес, он выполнит некоторые действия. Поскольку для проверки этих событий требуется всего 10 мс, заряда батареи хватает более чем на год, даже если она просыпается каждые 2 секунды.

В любом случае, теперь я хочу перенести тот же проект на esp32. Я не могу этого сделать, потому что esp32 требуется около 40 мс для запуска функции запуска плюс 10 мс, которые требуются для проверки событий, это будет 50 мс. Пробуждение на 50 мс каждые 2 секунды приведет к быстрому разряду моей батареи! Есть ли способ запустить некоторый код перед функцией настройки? Я считаю, что причина, по которой это занимает 40 мс, заключается в том, что он использует бесплатные игры. Есть ли способ запустить esp32 без фриросов, как ATmega328P? Я не возражаю против потери функциональности Wi-Fi/bluetooth. Кроме того, чип esp32 способен работать при более низких напряжениях, чем atmega328p, и это делает его очень удобным при использовании батарей. Например, теперь я мог бы использовать 2 батарейки типа АА вместо 3, которые мне сейчас нужны.

, 👍2

Обсуждение

С вашей текущей настройкой Arduino вы внешне пробуждаете его (включаете питание) каждые две секунды? Или у вас есть скетч, который задерживается на две секунды?, @PMF

Приведенная выше картинка, похоже, вообще не имеет отношения к вашему вопросу. Это всего лишь базовая схема подключения чипа ATmega., @PMF

Вы можете запустить 328p на частоте 8 МГц и также с 2 батареями типа АА. Ядро Arduino для ESP32 основано на FreeRTOS. Ваш вопрос ОТ в Arduino.SE, @DataFiddler

У меня есть сторожевой таймер, который просыпается каждые 2 секунды @PMF., @Tono Nam

Если у вас есть 32, почему бы не использовать ULP для принятия этих решений, даже не просыпаясь? Тогда ваша батарея, скорее всего, прослужит намного дольше, чем год., @dandavis


1 ответ


1

То, что я ищу, - это "Заглушки для глубокого сна".

Вот пример, который работает, который я нашел в Интернете:

#include <Arduino.h>

#include "driver/rtc_io.h"
#include "rom/ets_sys.h"
#include "rom/rtc.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/timer_group_reg.h"
#include "soc/uart_reg.h"
#include <stdio.h>
#include <string.h>

RTC_IRAM_ATTR void deepsleep_for_us(uint64_t duration_us);

#define S_TO_NS 1000000ULL
// Boot counter value, stored in RTC_SLOW_MEM
static size_t RTC_DATA_ATTR boots;
static size_t RTC_DATA_ATTR max_boots;

// Function which runs after exit from deep sleep
static void RTC_IRAM_ATTR wake_stub();
void setup(){
  
}
void loop(void) {
  if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
    printf("I'm back! Wake up from (extended) deep sleep. Should be 60s elapsed.\n");
    printf("Boot count=%d\n", boots);
    while (1) {
      ;
    }
  } else {
    printf("Not a deep sleep wake up\n");
  }

  printf("Going to deep sleep for 5x12=60s second\n");
  boots = 0;
  max_boots = 12;
  // hold high during deep sleep
  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

  // Set the wake stub function
  esp_set_deep_sleep_wake_stub(&wake_stub);

  esp_sleep_enable_timer_wakeup(5 * S_TO_NS);
  esp_deep_sleep_start();
}

static const char RTC_RODATA_ATTR wake_fmt_str[] = "count=%d\n";
static const char RTC_RODATA_ATTR sleep_fmt_str[] = "sleeping\n";

static void RTC_IRAM_ATTR wake_stub() {
  // Increment the Boot counter
  boots++;
  // and print the Boot counter value:
  ets_printf(wake_fmt_str, boots);

  if (boots >= max_boots) {
    // On revision 0 of ESP32, this function must be called:
    esp_default_wake_deep_sleep();
    // Return from the wake stub function to continue
    // booting the firmware.
    return;
  }

  // Print status
  ets_printf(sleep_fmt_str);
  // Wait for UART to end transmitting.
  // feed the watchdog
  REG_WRITE(TIMG_WDTFEED_REG(0), 1);
  while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {

  }
  deepsleep_for_us(5 * S_TO_NS);

  // Set the pointer of the wake stub function.
  REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)&wake_stub);
  // Go to sleep.
  CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
  SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
  // A few CPU cycles may be necessary for the sleep to start...
  while (true) {
    ;
  }
  // never reaches here.
}

// Comment out this line if you're using the internal RTC RC (150KHz) oscillator.
//#define USE_EXTERNAL_RTC_CRYSTAL
#ifdef USE_EXTERNAL_RTC_CRYSTAL
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#else
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#endif // USE_EXTERNAL_RTC_CRYSTAL

RTC_IRAM_ATTR void deepsleep_for_us(uint64_t duration_us) {
  // Feed watchdog
  REG_WRITE(TIMG_WDTFEED_REG(0), 1);
  // Get RTC calibration
  uint32_t period = REG_READ(RTC_SLOW_CLK_CAL_REG);
  // Calculate sleep duration in microseconds
  int64_t sleep_duration = (int64_t)duration_us - (int64_t)DEEP_SLEEP_TIME_OVERHEAD_US;
  if (sleep_duration < 0) {
    sleep_duration = 0;
  }
  // Convert microseconds to RTC clock cycles
  int64_t rtc_count_delta = (sleep_duration << RTC_CLK_CAL_FRACT) / period;
  // Feed watchdog
  REG_WRITE(TIMG_WDTFEED_REG(0), 1);
  // Get current RTC time
  SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE);
  while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) {
    ets_delay_us(1);
  }
  SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_TIME_VALID_INT_CLR);
  uint64_t now = READ_PERI_REG(RTC_CNTL_TIME0_REG);
  now |= ((uint64_t)READ_PERI_REG(RTC_CNTL_TIME1_REG)) << 32;
  // Set wakeup time
  uint64_t future = now + rtc_count_delta;
  WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, future & UINT32_MAX);
  WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, future >> 32);
  // Start RTC deepsleep timer
  REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, RTC_TIMER_TRIG_EN); // Wake up on timer
  WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, 0);                                  // Clear sleep rejection cause
  // Go to sleep
  CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
  SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
}

Я попытаюсь понять, насколько сложно запустить мой код, который проверяет наличие событий в wake_stub, который запускается раньше всего остального.

,