# TQ CatN 轻待机低功耗优化说明 ## 1. 文档范围 本文整理以下五个低功耗相关提交的设计和最终实现: | 提交 | 内容 | | --- | --- | | `988dc92` | 增加 LCD 背光 PWM 亮度控制 | | `6a11aca` | 增加轻待机状态协调器和活动事件接入 | | `baad9dc` | 增加背光、扬声器功放和电机的待机策略 | | `e773ebc` | 增加 Wi-Fi、电池检测和内存监控的待机策略(远程日志部分现已移除) | | `cb203a7` | 进入轻待机前播放提示音,并等待真实播放完成 | `bba99a0 fix(control-plane): trigger PTT on short press` 是独立的按键行为修复,不属于低功耗改动,因此不在本文范围内。 ## 2. 需求与问题原因 设备需要在 5 分钟无交互后降低功耗,同时满足以下约束: 1. 基础表情必须持续显示。 2. 唤醒词检测必须持续工作。 3. 按键和 SW2 抽签操作必须能够快速唤醒。 4. 进入待机前必须完整播放 `standby_5min.opus`。 这些约束决定了设备不能直接进入 ESP Light Sleep 或 Deep Sleep: - 基础表情当前由 LCD 渲染任务循环播放,需要 CPU、LCD 控制器和 SPI 链路继续工作。 - 唤醒词依赖麦克风采集、I2S RX、AFE 和本地识别任务持续运行。 - 设备还需要及时响应按键、抽签和业务事件。 因此,本次实现的是“轻待机”,即系统仍保持运行,只关闭或降低非必要硬件和周期任务的功耗。优化前存在以下主要问题: - LCD 背光只有开关控制,无法在保留画面的同时降低背光功耗。 - 扬声器功放在无音频播放时仍可能保持供电。 - 步进电机完成动作后可能继续保持线圈电流。 - Wi-Fi 始终使用活跃策略。 - 电池检测和内存监控仍按活跃周期运行。 - 缺少统一的待机状态、空闲计时、唤醒入口和失败回滚机制。 - 如果进入待机时立即关闭功放,待机提示音将无法完整播放。 ## 3. 总体解决方式 系统增加统一的轻待机状态协调器,状态变化如下: ```text ACTIVE | 5 分钟无交互,且当前业务允许待机 v ENTERING | 播放 standby_5min.opus,并等待真实播放完成 | 再依次应用硬件和运行时低功耗策略 v STANDBY | 唤醒词、按键、抽签、模型命令或语音活动 v WAKING | 恢复背光、功放、Wi-Fi 和周期任务策略 v ACTIVE ``` 进入待机前还会检查远端回复、用户讲话、待发送请求、配网等运行状态。播放期间如果出现新活动,或提示音播放失败、停止、卡死、被其他播放抢占,本次进入待机将被取消。应用低功耗策略中途失败时,已修改的策略会尽量恢复,避免设备停留在半待机状态。 ## 4. 默认配置 当前默认配置如下,均可通过 `menuconfig` 或 `sdkconfig.defaults` 调整: ```ini CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT=100 CONFIG_TQ_LIGHT_STANDBY_ENABLE=y CONFIG_TQ_LIGHT_STANDBY_IDLE_TIMEOUT_MS=300000 CONFIG_TQ_LIGHT_STANDBY_DIM_BACKLIGHT=y CONFIG_TQ_LIGHT_STANDBY_BACKLIGHT_PERCENT=10 CONFIG_TQ_LIGHT_STANDBY_PROMPT_ENABLE=y CONFIG_TQ_LIGHT_STANDBY_PROMPT_FILE="audio_prompts/standby_5min.opus" CONFIG_TQ_LIGHT_STANDBY_DISABLE_SPEAKER_OUTPUT=y CONFIG_TQ_LIGHT_STANDBY_RELEASE_MOTOR_HOLD=y CONFIG_TQ_LIGHT_STANDBY_WIFI_POWER_SAVE=y CONFIG_TQ_LIGHT_STANDBY_BATTERY_INTERVAL_SEC=300 CONFIG_TQ_LIGHT_STANDBY_MEMORY_SAMPLE_INTERVAL_MS=10000 CONFIG_TQ_LIGHT_STANDBY_MEMORY_REPORT_INTERVAL_MS=300000 CONFIG_TQ_LIGHT_STANDBY_TASK_STACK_BYTES=4096 CONFIG_TQ_LIGHT_STANDBY_TASK_PRIORITY=3 ``` 其中: - 活跃状态背光默认 100%。 - 轻待机背光默认 10%,仍保持基础表情可见。 - 空闲超时默认 300000 ms,即 5 分钟。 - 协调器任务栈为 4096 字节。原 3072 字节配置在日志压力场景下出现过 `cp_light_standby` 栈溢出,增大后解决该问题。 ## 5. 各项优化及具体代码 ### 5.1 LCD 背光 PWM #### 问题原因 背光 GPIO 原先只能输出固定电平。基础表情必须保留,因此不能直接关闭 LCD;若背光一直保持全亮,LCD 背光会成为待机阶段的主要持续耗电项之一。 #### 解决方式 使用 ESP-IDF LEDC 输出 20 kHz、10 位 PWM,并兼容背光高电平有效和低电平有效。提供运行时亮度接口,活跃状态使用正常亮度,待机状态切换为配置的 10%。 #### 具体代码 ```c #define LCD_DIRECT_BACKLIGHT_PWM_FREQUENCY_HZ 20000U #define LCD_DIRECT_BACKLIGHT_PWM_DUTY_RESOLUTION LEDC_TIMER_10_BIT #define LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX ((1U << 10U) - 1U) #define LCD_DIRECT_BACKLIGHT_PWM_TIMER LEDC_TIMER_0 #define LCD_DIRECT_BACKLIGHT_PWM_CHANNEL LEDC_CHANNEL_0 static uint32_t lcd_direct_backlight_duty(uint8_t brightness_percent) { uint32_t duty = ((uint32_t)brightness_percent * LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX + 50U) / 100U; #if !CONFIG_TQ_SCREEN_BACKLIGHT_ACTIVE_HIGH duty = LCD_DIRECT_BACKLIGHT_PWM_DUTY_MAX - duty; #endif return duty; } static esp_err_t lcd_direct_backlight_init(void) { const ledc_timer_config_t timer_config = { .speed_mode = LEDC_LOW_SPEED_MODE, .duty_resolution = LCD_DIRECT_BACKLIGHT_PWM_DUTY_RESOLUTION, .timer_num = LCD_DIRECT_BACKLIGHT_PWM_TIMER, .freq_hz = LCD_DIRECT_BACKLIGHT_PWM_FREQUENCY_HZ, .clk_cfg = LEDC_AUTO_CLK, }; ESP_RETURN_ON_ERROR(ledc_timer_config(&timer_config), TAG, "backlight PWM timer config failed"); const ledc_channel_config_t channel_config = { .gpio_num = CONFIG_TQ_SCREEN_BACKLIGHT_GPIO, .speed_mode = LEDC_LOW_SPEED_MODE, .channel = LCD_DIRECT_BACKLIGHT_PWM_CHANNEL, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LCD_DIRECT_BACKLIGHT_PWM_TIMER, .duty = lcd_direct_backlight_duty( CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT), .hpoint = 0, }; return ledc_channel_config(&channel_config); } esp_err_t lcd_direct_set_backlight_brightness(uint8_t brightness_percent) { ESP_RETURN_ON_FALSE(brightness_percent <= 100U, ESP_ERR_INVALID_ARG, TAG, "backlight brightness must be between 0 and 100 percent"); esp_err_t err = ledc_set_duty( LEDC_LOW_SPEED_MODE, LCD_DIRECT_BACKLIGHT_PWM_CHANNEL, lcd_direct_backlight_duty(brightness_percent)); if (err == ESP_OK) { err = ledc_update_duty( LEDC_LOW_SPEED_MODE, LCD_DIRECT_BACKLIGHT_PWM_CHANNEL); } return err; } ``` #### 功耗与影响 - 降低 LED 背光平均电流,是本方案中最直接的节电项。 - LCD 控制器、SPI 传输和基础表情渲染仍在运行,因此并未消除显示链路功耗。 - 亮度百分比与实际电流通常不是严格线性关系,需要真机测量后确定最佳值。 ### 5.2 扬声器功放与音频输出链路 #### 问题原因 待机期间不需要声音输出,但仍要保留麦克风和唤醒词。直接关闭整套音频设备会破坏快速语音唤醒;只停止播放又不能保证外部功放已断电。 #### 解决方式 待机时先将 Codec 下行输出静音,再关闭 PA GPIO。唤醒时重新打开 PA。麦克风采集、I2S RX、AFE 和唤醒词保持运行。 #### 具体代码 ```c esp_err_t multimodal_audio_set_speaker_output_enabled(bool enabled) { multimodal_audio_ctx_t *ctx = &s_audio; if (!ctx->initialized || ctx->codec_dev == NULL || ctx->gpio_if == NULL || ctx->gpio_if->set == NULL) { return ESP_ERR_INVALID_STATE; } if (!enabled) { esp_err_t mute_err = set_downstream_output_mute_if_needed( ctx, true, "Light standby"); if (mute_err != ESP_OK) { return mute_err; } } int ret = ctx->gpio_if->set(CONFIG_MULTIMODAL_AUDIO_PA_GPIO, enabled); if (ret != ESP_CODEC_DEV_OK) { return (esp_err_t)ret; } return ESP_OK; } ``` #### 功耗与影响 - 降低外部扬声器功放的静态功耗。 - 不关闭音频输入侧,因此语音唤醒能力不受该策略影响。 - I2S TX、解码和下行缓冲相关任务未完全停用,仍有进一步优化空间。 - 唤醒后 PA 恢复存在很短的硬件稳定时间,首段声音需要在真机上确认是否完整。 ### 5.3 待机提示音完整播放 #### 问题原因 如果空闲时间到达后立即关闭功放,`standby_5min.opus` 无法播放。仅按音频时长固定延时也不可靠,因为缓冲、解码、播放被打断或管线卡死都会使预计时长与真实播放状态不一致。 #### 解决方式 提示音发送完成后,以本次播放的 generation 为标识等待真实终止事件: - `PLAYBACK_COMPLETED`:允许继续进入待机。 - `PLAYBACK_STOPPED`:取消进入待机。 - `PLAYBACK_STALLED` 或等待超时:取消进入待机。 - 播放期间出现新用户活动:提示音结束后重新检查活动时间,取消进入待机。 超时时间只作为故障保护上限,不是用来代替播放完成事件的固定等待。 #### 具体代码 ```c esp_err_t voice_prompt_play_file(const char *file_name) { /* 省略文件读取和 Opus 包发送过程。 */ esp_err_t finish_err = multimodal_audio_finish_downstream_response(); if (err == ESP_OK) { err = finish_err; } if (err == ESP_OK) { uint64_t timeout_ms = (uint64_t)packet_count * VOICE_PROMPT_OPUS_FRAME_MS + VOICE_PROMPT_COMPLETION_TIMEOUT_MARGIN_MS; if (timeout_ms > INT32_MAX) { timeout_ms = INT32_MAX; } err = multimodal_audio_wait_downstream_playback_complete( playback_generation, (int)timeout_ms); } return err; } static esp_err_t downstream_terminal_type_to_error( multimodal_audio_downstream_playback_event_type_t type) { switch (type) { case MULTIMODAL_AUDIO_DOWNSTREAM_PLAYBACK_COMPLETED: return ESP_OK; case MULTIMODAL_AUDIO_DOWNSTREAM_PLAYBACK_STALLED: return ESP_ERR_TIMEOUT; case MULTIMODAL_AUDIO_DOWNSTREAM_PLAYBACK_STOPPED: default: return ESP_ERR_INVALID_STATE; } } ``` 待机协调器按“先播报、后关功放”的顺序执行: ```c esp_err_t policy_err = control_plane_light_standby_play_entry_prompt(); bool entry_current = policy_err == ESP_OK && control_plane_light_standby_entry_is_current(entry_activity_ms); bool runtime_eligible = entry_current && control_plane_light_standby_runtime_is_eligible(); if (runtime_eligible) { policy_applied = true; policy_err = control_plane_light_standby_apply_entry_policy(); } ``` #### 功耗与影响 - 提示音播放期间仍保持正常音频输出功耗。 - 实际进入轻待机的时间为“5 分钟空闲时间 + 提示音实际播放时间”。 - 播放异常时宁可取消本次待机,也不会在提示音未完成时关闭功放。 ### 5.4 电机驱动 #### 问题原因 步进电机停止移动后,如果线圈仍保持励磁,会持续产生保持电流。轻待机期间没有必要维持该静态扭矩。 #### 解决方式 进入待机时获取运动互斥锁并释放线圈;后续运动命令会按原有流程重新驱动电机。 #### 具体代码 ```c esp_err_t platform_stepper_driver_release_hold(int timeout_ms) { if (timeout_ms < 0) { return ESP_ERR_INVALID_ARG; } if (!ensure_stepper_motion_mutex()) { return ESP_ERR_INVALID_STATE; } TickType_t lock_ticks = pdMS_TO_TICKS(timeout_ms); if (timeout_ms > 0 && lock_ticks == 0) { lock_ticks = 1; } if (xSemaphoreTake(s_stepper_motion_mutex, lock_ticks) != pdTRUE) { return ESP_ERR_TIMEOUT; } portENTER_CRITICAL(&s_stepper_mux); stepper_release_locked(); portEXIT_CRITICAL(&s_stepper_mux); xSemaphoreGive(s_stepper_motion_mutex); return ESP_OK; } ``` #### 功耗与影响 - 消除电机线圈的待机保持电流。 - 电机不再提供静态保持扭矩,外力可能改变机构位置。 - 唤醒本身不重新励磁;下一次实际运动时才恢复驱动,避免无意义耗电。 ### 5.5 Wi-Fi 省电 #### 问题原因 设备需要保留网络连接,但活跃 Wi-Fi 策略会使射频和基带更频繁工作。 #### 解决方式 进入待机后切换为 `WIFI_PS_MIN_MODEM`,保留 STA 和 WebSocket 连接。唤醒后恢复项目配置的正常策略;当前默认正常策略为 `WIFI_PS_NONE`。 #### 具体代码 ```c esp_err_t platform_wifi_portal_set_light_standby(bool standby) { wifi_ps_type_t ps_type = standby ? WIFI_PS_MIN_MODEM : (CONFIG_TQ_WIFI_STA_POWER_SAVE ? WIFI_PS_MIN_MODEM : WIFI_PS_NONE); return esp_wifi_set_ps(ps_type); } ``` #### 功耗与影响 - 保持联网能力的同时降低 Wi-Fi 平均功耗。 - 可能增加网络首包延迟,实际幅度受 AP 的 DTIM、信号质量和网络负载影响。 - 不等同于关闭 Wi-Fi,网络任务和 WebSocket 仍会消耗资源。 ### 5.7 电池检测 #### 问题原因 电池 ADC 和状态处理在待机期间没有必要保持活跃状态下的采样频率。 #### 解决方式 普通采样周期在轻待机时切换为 300 秒。充电状态 GPIO 中断仍可立即唤醒电池检测任务并进行防抖后的新采样,满电确认和测量受限时的重试周期也保持原有优先级。 #### 具体代码 ```c uint32_t delay_ms; if (status_err == ESP_OK && status.measurement_suppressed) { delay_ms = BATTERY_SUPPRESSED_RETRY_MS; } else if (full_hint_candidate) { delay_ms = BATTERY_FULL_CONFIRM_RETRY_MS; } else if (battery_light_standby()) { delay_ms = (uint32_t)CONFIG_TQ_LIGHT_STANDBY_BATTERY_INTERVAL_SEC * 1000U; } else { delay_ms = (uint32_t)CONFIG_TQ_BATTERY_SAMPLE_INTERVAL_SEC * 1000U; } uint32_t notifications = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(delay_ms)); if (notifications > 0U && !battery_stop_requested()) { vTaskDelay(pdMS_TO_TICKS(BATTERY_CHARGE_DEBOUNCE_MS)); ulTaskNotifyTake(pdTRUE, 0U); } ``` #### 功耗与影响 - 减少 ADC 采样、状态计算和相关日志频率。 - 普通电量百分比更新变慢,最长可能接近配置的 300 秒。 - 插拔充电等 GPIO 边沿仍会触发及时检测,不受普通采样周期影响。 ### 5.8 内存监控 #### 问题原因 内存监控在活跃状态下每 1 秒采样、每 30 秒报告。待机期间这种诊断频率会造成不必要的 CPU 唤醒和日志输出。 #### 解决方式 待机时改为每 10 秒采样、每 300 秒周期报告。内存分配失败仍会绕过普通采样周期并立即处理。 #### 具体代码 ```c uint32_t sample_interval_ms = light_standby ? CONFIG_TQ_LIGHT_STANDBY_MEMORY_SAMPLE_INTERVAL_MS : CONFIG_TQ_MEMORY_MONITOR_SAMPLE_INTERVAL_MS; uint32_t report_interval_ms = light_standby ? CONFIG_TQ_LIGHT_STANDBY_MEMORY_REPORT_INTERVAL_MS : CONFIG_TQ_MEMORY_MONITOR_REPORT_INTERVAL_MS; uint32_t alloc_fail_count = __atomic_load_n(&s_alloc_fail_count, __ATOMIC_ACQUIRE); bool unreported_alloc_failure = alloc_fail_count != s_memory_monitor.reported_alloc_fail_count; if (!force && !unreported_alloc_failure && s_memory_monitor.initialized && (now_tick - s_memory_monitor.last_sample_tick) < sample_ticks) { return; } ``` #### 功耗与影响 - 减少堆信息采集和周期日志带来的 CPU 开销。 - 常规内存水位变化的可见时间变长。 - 分配失败仍立即上报,关键故障检测没有被普通周期限制。 ### 5.9 BLE 广播 #### 当前处理 本次没有增加轻待机下的 BLE 广播切换逻辑。项目的 BLE 广播只在小程序配网期间使用,而配网期间轻待机资格检查会直接返回不允许进入待机: ```c static bool control_plane_light_standby_runtime_is_eligible(void) { if (control_plane_is_reset_in_progress() || control_plane_is_mini_program_provisioning_running()) { return false; } /* 继续检查语音会话和远端回复状态。 */ return true; } ``` #### 功耗与影响 - 正常业务状态没有持续 BLE 广播,因此没有可应用的待机节电策略。 - 配网状态优先保证 BLE 配网可用性,不进入轻待机。 - 如果后续增加常驻 BLE 广播,需要重新设计待机广播间隔和连接参数。 ## 6. 统一进入、回滚和唤醒策略 ### 6.1 进入策略 进入顺序为:释放电机保持电流、关闭扬声器输出、降低背光、应用运行时策略。任一步骤失败都会阻止状态进入 `STANDBY`,必要时恢复此前已修改的项目。 ```c static esp_err_t control_plane_light_standby_apply_entry_policy(void) { #if CONFIG_TQ_LIGHT_STANDBY_RELEASE_MOTOR_HOLD ESP_RETURN_ON_ERROR( domain_direction_release_motor_hold(MOTOR_RELEASE_WAIT_MS), TAG, "release motor hold failed"); #endif #if CONFIG_TQ_LIGHT_STANDBY_DISABLE_SPEAKER_OUTPUT ESP_RETURN_ON_ERROR( domain_runtime_multimodal_audio_set_speaker_output_enabled(false), TAG, "disable speaker output failed"); #endif #if CONFIG_TQ_LIGHT_STANDBY_DIM_BACKLIGHT esp_err_t backlight_err = domain_runtime_set_lcd_backlight_brightness( CONFIG_TQ_LIGHT_STANDBY_BACKLIGHT_PERCENT); if (backlight_err != ESP_OK) { domain_runtime_multimodal_audio_set_speaker_output_enabled(true); return backlight_err; } #endif esp_err_t runtime_err = control_plane_light_standby_apply_runtime_policy(true); if (runtime_err != ESP_OK) { domain_runtime_set_lcd_backlight_brightness( CONFIG_TQ_SCREEN_BACKLIGHT_BRIGHTNESS_PERCENT); domain_runtime_multimodal_audio_set_speaker_output_enabled(true); } return runtime_err; } ``` 以上代码为便于阅读的等价摘录,实际代码还包含每个配置项的条件编译和详细错误日志。 ### 6.2 运行时策略 ```c static esp_err_t control_plane_light_standby_apply_runtime_policy(bool standby) { control_plane_battery_service_set_light_standby(standby); control_plane_runtime_diagnostics_set_light_standby(standby); if (control_plane_is_sta_connected()) { esp_err_t wifi_err = domain_runtime_wifi_portal_set_light_standby(standby); if (wifi_err != ESP_OK && standby) { control_plane_battery_service_set_light_standby(false); control_plane_runtime_diagnostics_set_light_standby(false); return wifi_err; } } return ESP_OK; } ``` ### 6.3 唤醒来源 当前活动类型包括: ```c typedef enum { CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_UNSPECIFIED = 0, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_KEY, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_LOCAL_WAKE, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_VOICE_INPUT, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_VOICE_OUTPUT, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_MODEL_COMMAND, CONTROL_PLANE_LIGHT_STANDBY_ACTIVITY_EXTERNAL, } control_plane_light_standby_activity_t; ``` - 唤醒词对应 `LOCAL_WAKE`。 - 普通按键和 SW2 抽签按键对应 `KEY`。 - 麦克风语音活动对应 `VOICE_INPUT`。 - 远端回复对应 `VOICE_OUTPUT`。 - 本地识别的抽签、方向等命令对应 `MODEL_COMMAND`。 记录活动时会立即刷新空闲计时。如果已经处于 `STANDBY`,状态切换为 `WAKING`,恢复运行时策略、正常背光和扬声器功放后返回 `ACTIVE`。 ```c esp_err_t control_plane_light_standby_record_activity( control_plane_light_standby_activity_t activity) { uint64_t now_ms = control_plane_light_standby_now_ms(); portENTER_CRITICAL(&s_standby_lock); s_standby.last_activity = activity; s_standby.last_activity_ms = now_ms; bool wake_required = s_standby.state == CONTROL_PLANE_LIGHT_STANDBY_STATE_STANDBY; portEXIT_CRITICAL(&s_standby_lock); if (!wake_required) { return ESP_OK; } s_standby.state = CONTROL_PLANE_LIGHT_STANDBY_STATE_WAKING; esp_err_t wake_err = control_plane_light_standby_apply_wake_policy(); s_standby.state = CONTROL_PLANE_LIGHT_STANDBY_STATE_ACTIVE; return wake_err; } ``` 以上为突出主流程的等价摘录;实际实现使用临界区和转换互斥锁保护状态,避免进入待机和唤醒同时修改硬件策略。 ## 7. 解决成果 本轮改动已经实现: 1. 5 分钟无交互后自动进入轻待机。 2. 基础表情保持显示,待机背光默认降至 10%。 3. 进入待机前完整播放 `standby_5min.opus`,等待真实播放完成事件后才关闭功放。 4. 待机时 Codec 输出静音并关闭扬声器 PA,同时保留麦克风、AFE 和唤醒词。 5. 释放步进电机线圈保持电流。 6. Wi-Fi 切换为最小 Modem 省电,同时保留连接。 8. 电池常规采样周期放宽到 300 秒,充电状态边沿仍及时处理。 9. 内存监控采样放宽到 10 秒、周期报告放宽到 300 秒,分配失败仍及时处理。 10. 支持唤醒词、按键、SW2 抽签、模型命令和语音活动快速唤醒。 11. 唤醒后恢复正常背光、功放、Wi-Fi、电池和内存监控策略。 12. 增加进入失败回滚和状态竞态保护。 13. 将轻待机任务栈增至 4096 字节,解决已观察到的任务栈溢出。 ## 8. 验证情况 已完成的软件侧验证: - ESP-IDF 5.5.4 完整构建通过。 - 当前构建生成的应用固件约 2.08 MiB,应用分区剩余约 41%。 - `audio_prompts/standby_5min.opus` 已纳入应用镜像中的音频素材包。 - 源码差异格式检查通过。 - 已确认提示音等待的是播放管线终止事件,而不是固定时长硬等待。 当前尚未完成以下真机量化测试: - 活跃状态和轻待机状态的整机电流对比。 - 各单项策略分别节省的电流。 - 不同 AP/DTIM 条件下的网络首包延迟。 - 唤醒词、按键和抽签从触发到完全恢复的耗时。 - PA 恢复后第一段声音是否存在削头或延迟。 因此,目前只能确认节电机制已生效,不能在没有仪器数据的情况下声称降低了具体多少 mA 或百分比。 ## 9. 后续影响与剩余优化空间 ### 9.1 明确的行为影响 | 项目 | 后续影响 | | --- | --- | | LCD | 画面继续刷新,背光变暗,但 LCD 控制器、SPI 和渲染功耗仍存在 | | 扬声器 | 待机无声音输出;唤醒后 PA 需要短暂恢复时间 | | 麦克风 | 保持运行,以满足唤醒词快速唤醒要求 | | 电机 | 待机不保持静态扭矩,机构可能被外力移动 | | Wi-Fi | 保持连接,但首包延迟可能增加 | | 电池检测 | 普通电量更新变慢,充电状态边沿仍及时检测 | | 内存监控 | 普通水位报告变慢,分配失败仍及时处理 | | 提示音 | 真正进入待机的时间会比 5 分钟多出提示音播放时间 | | BLE | 配网期间禁止进入轻待机,因此本次不修改 BLE 广播 | ### 9.2 仍可继续优化的项目 在“不关闭基础表情”和“不关闭唤醒词”的约束下,仍有以下优化空间: 1. 避免 LCD 重复传输完全相同的画面。 2. 轻待机时降低基础表情动画帧率,或停在静态基础帧。 3. 在确保提示音和唤醒后首包完整的前提下,进一步暂停 I2S TX、解码器和下行音频任务。 4. 继续检查任务监控、网络保活、传感器和其他周期诊断任务的唤醒频率。 5. 通过功耗仪逐项关闭策略,建立各模块的实际 mA 收益表,再决定优化优先级。 受持续显示和持续唤醒词约束,ESP Light Sleep/Deep Sleep 目前不适合直接使用。若未来允许基础表情静止、LCD 使用自刷新能力,或增加独立低功耗唤醒芯片,才有机会进入更深的睡眠状态并获得数量级更高的节电收益。 ## 10. 结论 本次改动已经完成当前产品约束下的主要轻待机优化:保留基础表情、唤醒词和按键响应,同时降低背光、功放、电机、Wi-Fi、电池检测和内存监控的持续功耗。实现具备统一状态管理、真实音频完成等待、进入失败回滚和快速唤醒恢复。 下一步重点不是继续盲目关闭模块,而是进行真机电流和唤醒延迟测试。测试数据可以确认主要耗电来源,并判断 LCD 刷新和音频下行链路是否值得进入下一轮优化。