mirror of
https://github.com/esphome/esphome.git
synced 2025-10-09 21:33:48 +01:00
add deep sleep
This commit is contained in:
@@ -438,6 +438,7 @@ void DebugComponent::dump_config() {
|
|||||||
|
|
||||||
void DebugComponent::loop() {
|
void DebugComponent::loop() {
|
||||||
//TODO move to logger
|
//TODO move to logger
|
||||||
|
//TOOD do not print when exit from deep sleep
|
||||||
static bool d = false;
|
static bool d = false;
|
||||||
if (d != Serial){
|
if (d != Serial){
|
||||||
if(false == d){
|
if(false == d){
|
||||||
|
@@ -16,6 +16,7 @@ from esphome.const import (
|
|||||||
CONF_WAKEUP_PIN,
|
CONF_WAKEUP_PIN,
|
||||||
PLATFORM_ESP32,
|
PLATFORM_ESP32,
|
||||||
PLATFORM_ESP8266,
|
PLATFORM_ESP8266,
|
||||||
|
PLATFORM_NRF52,
|
||||||
)
|
)
|
||||||
|
|
||||||
from esphome.components.esp32 import get_esp32_variant
|
from esphome.components.esp32 import get_esp32_variant
|
||||||
@@ -198,7 +199,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean),
|
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
|
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_NRF52]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
54
esphome/components/deep_sleep/deep_sleep_backend_nrf52.cpp
Normal file
54
esphome/components/deep_sleep/deep_sleep_backend_nrf52.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#ifdef USE_NRF52
|
||||||
|
#include "deep_sleep_backend_nrf52.h"
|
||||||
|
#include "nrf_power.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace deep_sleep {
|
||||||
|
|
||||||
|
#define DFU_MAGIC_SKIP 0x6d
|
||||||
|
|
||||||
|
static const char *const TAG = "deep_sleep.nrf52";
|
||||||
|
|
||||||
|
void Nrf52DeepSleepBackend::begin_sleep(const optional<uint64_t>& sleep_duration) {
|
||||||
|
// RTC works only during System On
|
||||||
|
if (sleep_duration.has_value())
|
||||||
|
{
|
||||||
|
// TinyUSBDevice.detach();
|
||||||
|
// TODO deinit USB
|
||||||
|
// TOOD and the rest of peripherals
|
||||||
|
uint32_t start_time = millis();
|
||||||
|
portSUPPRESS_TICKS_AND_SLEEP(ms2tick(*sleep_duration/1000));
|
||||||
|
last_sleep_duration_ = millis() - start_time;
|
||||||
|
// TinyUSBDevice.attach();
|
||||||
|
} else {
|
||||||
|
NRF_POWER->GPREGRET = DFU_MAGIC_SKIP;
|
||||||
|
// Enter System OFF.
|
||||||
|
#ifdef SOFTDEVICE_PRESENT
|
||||||
|
uint8_t sd_en = 0;
|
||||||
|
(void) sd_softdevice_is_enabled(&sd_en);
|
||||||
|
if (sd_en)
|
||||||
|
{
|
||||||
|
uint32_t ret_code = sd_power_system_off();
|
||||||
|
assert((ret_code == NRF_SUCCESS) || (ret_code == NRF_ERROR_SOFTDEVICE_NOT_ENABLED));
|
||||||
|
}
|
||||||
|
#endif // SOFTDEVICE_PRESENT
|
||||||
|
nrf_power_system_off(NRF_POWER);
|
||||||
|
// it should never reach here...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nrf52DeepSleepBackend::dump_config() {
|
||||||
|
if (last_sleep_duration_.has_value()) {
|
||||||
|
ESP_LOGD(TAG, "Last sleep duration: %lu ms", *last_sleep_duration_ );
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Last sleep duration: unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace deep_sleep
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
21
esphome/components/deep_sleep/deep_sleep_backend_nrf52.h
Normal file
21
esphome/components/deep_sleep/deep_sleep_backend_nrf52.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
|
||||||
|
#include "esphome/core/optional.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace deep_sleep {
|
||||||
|
|
||||||
|
class Nrf52DeepSleepBackend {
|
||||||
|
public:
|
||||||
|
void begin_sleep(const optional<uint64_t>& sleep_duration);
|
||||||
|
void dump_config();
|
||||||
|
protected:
|
||||||
|
optional<uint32_t> last_sleep_duration_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace deep_sleep
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
@@ -7,6 +7,10 @@
|
|||||||
#include <Esp.h>
|
#include <Esp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
#include "deep_sleep_backend_nrf52.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace deep_sleep {
|
namespace deep_sleep {
|
||||||
|
|
||||||
@@ -33,10 +37,9 @@ optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
|
|||||||
return this->run_duration_;
|
return this->run_duration_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeepSleepComponent::setup() {
|
void DeepSleepComponent::setup_deep_sleep_()
|
||||||
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
|
{
|
||||||
global_has_deep_sleep = true;
|
this->next_enter_deep_sleep_ = false;
|
||||||
|
|
||||||
const optional<uint32_t> run_duration = get_run_duration_();
|
const optional<uint32_t> run_duration = get_run_duration_();
|
||||||
if (run_duration.has_value()) {
|
if (run_duration.has_value()) {
|
||||||
ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %" PRIu32 " ms", *run_duration);
|
ESP_LOGI(TAG, "Scheduling Deep Sleep to start in %" PRIu32 " ms", *run_duration);
|
||||||
@@ -45,6 +48,14 @@ void DeepSleepComponent::setup() {
|
|||||||
ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
|
ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeepSleepComponent::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
|
||||||
|
global_has_deep_sleep = true;
|
||||||
|
|
||||||
|
setup_deep_sleep_();
|
||||||
|
}
|
||||||
|
|
||||||
void DeepSleepComponent::dump_config() {
|
void DeepSleepComponent::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
|
ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
|
||||||
if (this->sleep_duration_.has_value()) {
|
if (this->sleep_duration_.has_value()) {
|
||||||
@@ -65,6 +76,9 @@ void DeepSleepComponent::dump_config() {
|
|||||||
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
|
ESP_LOGCONFIG(TAG, " GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
backend_.dump_config();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
void DeepSleepComponent::loop() {
|
void DeepSleepComponent::loop() {
|
||||||
if (this->next_enter_deep_sleep_)
|
if (this->next_enter_deep_sleep_)
|
||||||
@@ -139,7 +153,7 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
|||||||
esp_sleep_enable_touchpad_wakeup();
|
esp_sleep_enable_touchpad_wakeup();
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // USE_ESP32_VARIANT_ESP32C3
|
||||||
#ifdef USE_ESP32_VARIANT_ESP32C3
|
#ifdef USE_ESP32_VARIANT_ESP32C3
|
||||||
if (this->sleep_duration_.has_value())
|
if (this->sleep_duration_.has_value())
|
||||||
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
|
esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
|
||||||
@@ -151,13 +165,17 @@ void DeepSleepComponent::begin_sleep(bool manual) {
|
|||||||
esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
|
esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
|
||||||
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
|
static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
|
||||||
}
|
}
|
||||||
#endif
|
#endif // USE_ESP32_VARIANT_ESP32C3
|
||||||
esp_deep_sleep_start();
|
esp_deep_sleep_start();
|
||||||
#endif
|
#endif // USE_ESP32
|
||||||
|
|
||||||
#ifdef USE_ESP8266
|
#ifdef USE_ESP8266
|
||||||
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
|
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
backend_.begin_sleep(this->sleep_duration_);
|
||||||
|
setup_deep_sleep_();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
|
float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
|
||||||
void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
|
void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
|
||||||
|
@@ -14,6 +14,10 @@
|
|||||||
#include "esphome/core/time.h"
|
#include "esphome/core/time.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
#include "deep_sleep_backend_nrf52.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@@ -106,6 +110,8 @@ class DeepSleepComponent : public Component {
|
|||||||
// duration before entering deep sleep.
|
// duration before entering deep sleep.
|
||||||
optional<uint32_t> get_run_duration_() const;
|
optional<uint32_t> get_run_duration_() const;
|
||||||
|
|
||||||
|
void setup_deep_sleep_();
|
||||||
|
|
||||||
optional<uint64_t> sleep_duration_;
|
optional<uint64_t> sleep_duration_;
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
InternalGPIOPin *wakeup_pin_;
|
InternalGPIOPin *wakeup_pin_;
|
||||||
@@ -117,6 +123,9 @@ class DeepSleepComponent : public Component {
|
|||||||
optional<uint32_t> run_duration_;
|
optional<uint32_t> run_duration_;
|
||||||
bool next_enter_deep_sleep_{false};
|
bool next_enter_deep_sleep_{false};
|
||||||
bool prevent_{false};
|
bool prevent_{false};
|
||||||
|
#ifdef USE_NRF52
|
||||||
|
Nrf52DeepSleepBackend backend_;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
@@ -13,6 +14,8 @@ from esphome.core import CORE, coroutine_with_priority
|
|||||||
# force import gpio to register pin schema
|
# force import gpio to register pin schema
|
||||||
from .gpio import nrf52_pin_to_code # noqa
|
from .gpio import nrf52_pin_to_code # noqa
|
||||||
|
|
||||||
|
AUTO_LOAD = ["nrf52_nrfx"]
|
||||||
|
|
||||||
|
|
||||||
def set_core_data(config):
|
def set_core_data(config):
|
||||||
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_NRF52
|
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_NRF52
|
||||||
@@ -84,6 +87,12 @@ async def to_code(config):
|
|||||||
cg.add_platformio_option("board_upload.use_1200bps_touch", "true")
|
cg.add_platformio_option("board_upload.use_1200bps_touch", "true")
|
||||||
cg.add_platformio_option("board_upload.require_upload_port", "true")
|
cg.add_platformio_option("board_upload.require_upload_port", "true")
|
||||||
cg.add_platformio_option("board_upload.wait_for_upload_port", "true")
|
cg.add_platformio_option("board_upload.wait_for_upload_port", "true")
|
||||||
|
# watchdog
|
||||||
cg.add_build_flag("-DNRFX_WDT_ENABLED=1")
|
cg.add_build_flag("-DNRFX_WDT_ENABLED=1")
|
||||||
cg.add_build_flag("-DNRFX_WDT0_ENABLED=1")
|
cg.add_build_flag("-DNRFX_WDT0_ENABLED=1")
|
||||||
cg.add_build_flag("-DNRFX_WDT_CONFIG_NO_IRQ=1")
|
cg.add_build_flag("-DNRFX_WDT_CONFIG_NO_IRQ=1")
|
||||||
|
# prevent setting up GPIO PINs
|
||||||
|
cg.add_platformio_option("board_build.variant", "nrf52840")
|
||||||
|
cg.add_platformio_option(
|
||||||
|
"board_build.variants_dir", os.path.dirname(os.path.realpath(__file__))
|
||||||
|
)
|
||||||
|
@@ -16,6 +16,7 @@ struct nrf5x_wdt_obj
|
|||||||
nrfx_wdt_t wdt;
|
nrfx_wdt_t wdt;
|
||||||
nrfx_wdt_channel_id ch;
|
nrfx_wdt_channel_id ch;
|
||||||
};
|
};
|
||||||
|
//TODO what value for watchdog?
|
||||||
static nrfx_wdt_config_t nrf5x_wdt_cfg = NRFX_WDT_DEFAULT_CONFIG;
|
static nrfx_wdt_config_t nrf5x_wdt_cfg = NRFX_WDT_DEFAULT_CONFIG;
|
||||||
|
|
||||||
static struct nrf5x_wdt_obj nrf5x_wdt = {
|
static struct nrf5x_wdt_obj nrf5x_wdt = {
|
||||||
@@ -24,6 +25,7 @@ static struct nrf5x_wdt_obj nrf5x_wdt = {
|
|||||||
|
|
||||||
void arch_init() {
|
void arch_init() {
|
||||||
//Configure WDT.
|
//Configure WDT.
|
||||||
|
nrf5x_wdt_cfg.behaviour = NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT;
|
||||||
nrfx_wdt_init(&nrf5x_wdt.wdt, &nrf5x_wdt_cfg, nullptr);
|
nrfx_wdt_init(&nrf5x_wdt.wdt, &nrf5x_wdt_cfg, nullptr);
|
||||||
nrfx_wdt_channel_alloc(&nrf5x_wdt.wdt, &nrf5x_wdt.ch);
|
nrfx_wdt_channel_alloc(&nrf5x_wdt.wdt, &nrf5x_wdt.ch);
|
||||||
nrfx_wdt_enable(&nrf5x_wdt.wdt);
|
nrfx_wdt_enable(&nrf5x_wdt.wdt);
|
||||||
@@ -42,7 +44,9 @@ void arch_feed_wdt() {
|
|||||||
nrfx_wdt_feed(&nrf5x_wdt.wdt);
|
nrfx_wdt_feed(&nrf5x_wdt.wdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void arch_restart() { /* TODO */ }
|
void arch_restart() {
|
||||||
|
NVIC_SystemReset();
|
||||||
|
}
|
||||||
|
|
||||||
void nrf52GetMacAddr(uint8_t *mac)
|
void nrf52GetMacAddr(uint8_t *mac)
|
||||||
{
|
{
|
||||||
|
15
esphome/components/nrf52/nrf52840/variant.cpp
Normal file
15
esphome/components/nrf52/nrf52840/variant.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "variant.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] =
|
||||||
|
{
|
||||||
|
// P0
|
||||||
|
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ,
|
||||||
|
8 , 9 , 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 17, 18, 19, 20, 21, 22, 23,
|
||||||
|
24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
|
||||||
|
// P1
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39,
|
||||||
|
40, 41, 42, 43, 44, 45, 46, 47
|
||||||
|
};
|
||||||
|
|
16
esphome/components/nrf52/nrf52840/variant.h
Normal file
16
esphome/components/nrf52/nrf52840/variant.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define LED_BUILTIN (64)
|
||||||
|
#if PINS_COUNT > LED_BUILTIN
|
||||||
|
#error LED_BUILTIN should be bigger than PINS_COUNT. To ignore settings.
|
||||||
|
#endif
|
||||||
|
#define LED_BLUE (LED_BUILTIN)
|
||||||
|
// TODO other are also needed?
|
||||||
|
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||||
|
#define LED_STATE_ON (1)
|
||||||
|
#define PIN_SERIAL1_RX (33) // P1.01
|
||||||
|
#define PIN_SERIAL1_TX (34) // P1.02
|
||||||
|
|
Reference in New Issue
Block a user