feat(power): add controlled low-battery shutdown

This commit is contained in:
chenjintao
2026-08-24 15:06:02 +08:00
parent 96e975d84c
commit 23f4969404
13 changed files with 467 additions and 19 deletions
@@ -11,6 +11,7 @@
#include "driver/gpio.h"
#include "esp_app_desc.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "platform_internal.h"
@@ -20,6 +21,18 @@
#ifndef CONFIG_TQ_STEPPER_ENABLE
#define CONFIG_TQ_STEPPER_ENABLE 1
#endif
#ifndef CONFIG_MULTIMODAL_AUDIO_PA_GPIO
#define CONFIG_MULTIMODAL_AUDIO_PA_GPIO -1
#endif
#ifndef CONFIG_TQ_SCREEN_BACKLIGHT_GPIO
#define CONFIG_TQ_SCREEN_BACKLIGHT_GPIO -1
#endif
#ifndef CONFIG_TQ_STEPPER_IN1_GPIO
#define CONFIG_TQ_STEPPER_IN1_GPIO -1
#define CONFIG_TQ_STEPPER_IN2_GPIO -1
#define CONFIG_TQ_STEPPER_IN3_GPIO -1
#define CONFIG_TQ_STEPPER_IN4_GPIO -1
#endif
static const char *TAG = "platform_core";
static bool s_initialized;
@@ -35,6 +48,106 @@ static const char *const s_known_nvs_namespaces[] = {
"fortune",
};
bool platform_power_woke_from_deep_sleep(void)
{
return esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED;
}
static void platform_power_set_output_low_and_hold(int gpio)
{
if (gpio < 0 || gpio >= GPIO_NUM_MAX) {
return;
}
(void)gpio_hold_dis((gpio_num_t)gpio);
(void)gpio_set_direction((gpio_num_t)gpio, GPIO_MODE_OUTPUT);
(void)gpio_set_level((gpio_num_t)gpio, 0);
(void)gpio_hold_en((gpio_num_t)gpio);
}
static void platform_power_set_board_outputs_held(bool held)
{
const int output_gpios[] = {
CONFIG_MULTIMODAL_AUDIO_PA_GPIO,
CONFIG_TQ_SCREEN_BACKLIGHT_GPIO,
CONFIG_TQ_STEPPER_IN1_GPIO,
CONFIG_TQ_STEPPER_IN2_GPIO,
CONFIG_TQ_STEPPER_IN3_GPIO,
CONFIG_TQ_STEPPER_IN4_GPIO,
};
for (size_t i = 0; i < sizeof(output_gpios) / sizeof(output_gpios[0]); ++i) {
int gpio = output_gpios[i];
if (gpio < 0 || gpio >= GPIO_NUM_MAX) {
continue;
}
if (held) {
platform_power_set_output_low_and_hold(gpio);
} else {
(void)gpio_hold_dis((gpio_num_t)gpio);
}
}
if (held) {
gpio_deep_sleep_hold_en();
} else {
gpio_deep_sleep_hold_dis();
}
}
void platform_power_release_deep_sleep_holds(void)
{
platform_power_set_board_outputs_held(false);
}
esp_err_t platform_power_enter_deep_sleep(int charger_gpio, int button_gpio)
{
uint64_t wake_mask = 0U;
const int wake_gpios[] = {charger_gpio, button_gpio};
for (size_t i = 0; i < sizeof(wake_gpios) / sizeof(wake_gpios[0]); ++i) {
int gpio = wake_gpios[i];
if (gpio < 0) {
continue;
}
if (gpio >= GPIO_NUM_MAX ||
!esp_sleep_is_valid_wakeup_gpio((gpio_num_t)gpio)) {
ESP_LOGE(TAG, "Invalid deep-sleep wake GPIO: %d", gpio);
return ESP_ERR_INVALID_ARG;
}
gpio_config_t input_config = {
.pin_bit_mask = 1ULL << (uint32_t)gpio,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
esp_err_t gpio_err = gpio_config(&input_config);
if (gpio_err != ESP_OK) {
return gpio_err;
}
wake_mask |= 1ULL << (uint32_t)gpio;
}
if (wake_mask == 0U) {
ESP_LOGE(TAG, "Deep sleep requires at least one wake GPIO");
return ESP_ERR_INVALID_STATE;
}
esp_err_t wake_err = esp_sleep_enable_ext1_wakeup_io(
wake_mask,
ESP_EXT1_WAKEUP_ANY_LOW);
if (wake_err != ESP_OK) {
return wake_err;
}
platform_power_set_board_outputs_held(true);
ESP_LOGW(TAG,
"Entering deep sleep wake_mask=0x%llx",
(unsigned long long)wake_mask);
esp_deep_sleep_start();
return ESP_ERR_INVALID_STATE;
}
static esp_err_t platform_gpio_isr_service_init(void)
{
if (s_gpio_isr_service_installed) {