From 1cb1f5de64ccfbc4295455682c64fa72ee41418a Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 25 Feb 2026 18:12:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=86=85=E5=AD=98=E5=8D=A0?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../internal/voice_interaction_internal.h | 2 + main/domain/src/image_generation.c | 3 +- main/domain/src/printer_protocol.c | 51 ++++++++++++++----- main/domain/src/voice_interaction.c | 6 ++- main/domain/src/voice_interaction_common.c | 6 ++- main/domain/src/voice_interaction_ws.c | 32 ++++++++++++ main/platform/src/platform_bootstrap.c | 31 +++++++++++ 7 files changed, 114 insertions(+), 17 deletions(-) diff --git a/main/domain/internal/voice_interaction_internal.h b/main/domain/internal/voice_interaction_internal.h index aef072b..959a162 100644 --- a/main/domain/internal/voice_interaction_internal.h +++ b/main/domain/internal/voice_interaction_internal.h @@ -122,5 +122,7 @@ void voice_websocket_event_handler(void *handler_args, int32_t event_id, void *event_data); +void voice_interaction_ws_init_cjson_hooks(void); + void voice_uplink_task(void *arg); void voice_heartbeat_task(void *arg); diff --git a/main/domain/src/image_generation.c b/main/domain/src/image_generation.c index 4db6473..2174825 100644 --- a/main/domain/src/image_generation.c +++ b/main/domain/src/image_generation.c @@ -380,7 +380,7 @@ void image_generation_schedule_prewarm(void) { s_prewarm_running = true; xSemaphoreGive(s_prewarm_lock); - image_prewarm_task_arg_t *arg = (image_prewarm_task_arg_t *)calloc(1, sizeof(*arg)); + image_prewarm_task_arg_t *arg = (image_prewarm_task_arg_t *)malloc_prefer_psram(sizeof(*arg)); if (arg == NULL) { if (xSemaphoreTake(s_prewarm_lock, pdMS_TO_TICKS(100)) == pdTRUE) { s_prewarm_running = false; @@ -390,6 +390,7 @@ void image_generation_schedule_prewarm(void) { } return; } + memset(arg, 0, sizeof(*arg)); image_generation_copy_oss_origin(arg->oss_origin, sizeof(arg->oss_origin)); BaseType_t ok = xTaskCreatePinnedToCore(image_generation_prewarm_task, diff --git a/main/domain/src/printer_protocol.c b/main/domain/src/printer_protocol.c index 5eff99b..1b86475 100644 --- a/main/domain/src/printer_protocol.c +++ b/main/domain/src/printer_protocol.c @@ -5,6 +5,7 @@ #include #include "ble_printer_client.h" +#include "esp_heap_caps.h" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" @@ -39,6 +40,34 @@ static const char *TAG = "printer_protocol"; #define PRINT_WORKER_CORE_ID 1 #endif +static BaseType_t printer_create_task_prefer_psram(TaskFunction_t task_fn, + const char *name, + uint32_t stack_size, + UBaseType_t priority) { +#if defined(CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) && \ + defined(CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM) && \ + (configSUPPORT_STATIC_ALLOCATION == 1) + BaseType_t rc = xTaskCreatePinnedToCoreWithCaps(task_fn, + name, + (configSTACK_DEPTH_TYPE)stack_size, + NULL, + priority, + NULL, + PRINT_WORKER_CORE_ID, + MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if (rc == pdPASS) { + return pdPASS; + } +#endif + return xTaskCreatePinnedToCore(task_fn, + name, + (configSTACK_DEPTH_TYPE)stack_size, + NULL, + priority, + NULL, + PRINT_WORKER_CORE_ID); +} + void printer_protocol_set_status_poll_paused(bool paused) { if (s_mutex == NULL) { return; @@ -332,24 +361,18 @@ esp_err_t printer_protocol_init(void) { return err; } - BaseType_t ok = xTaskCreatePinnedToCore(printer_protocol_worker_task, - "print_worker", - 6144, - NULL, - 6, - NULL, - PRINT_WORKER_CORE_ID); + BaseType_t ok = printer_create_task_prefer_psram(printer_protocol_worker_task, + "print_worker", + 6144, + 6); if (ok != pdPASS) { return ESP_ERR_NO_MEM; } - ok = xTaskCreatePinnedToCore(status_poll_task, - "status_poll", - 4096, - NULL, - 4, - NULL, - PRINT_WORKER_CORE_ID); + ok = printer_create_task_prefer_psram(status_poll_task, + "status_poll", + 4096, + 4); if (ok != pdPASS) { return ESP_ERR_NO_MEM; } diff --git a/main/domain/src/voice_interaction.c b/main/domain/src/voice_interaction.c index 0e6443c..43bc26f 100644 --- a/main/domain/src/voice_interaction.c +++ b/main/domain/src/voice_interaction.c @@ -80,6 +80,8 @@ esp_err_t voice_interaction_start(char *err, size_t err_len) { return ESP_OK; } + voice_interaction_ws_init_cjson_hooks(); + ESP_LOGI(TAG, "[stage] opus_setup_begin"); esp_err_t opus_setup_err = voice_setup_opus(err, err_len); if (opus_setup_err != ESP_OK) { @@ -138,7 +140,7 @@ esp_err_t voice_interaction_start(char *err, size_t err_len) { ESP_LOGI(TAG, "[stage] ws_init_ok"); size_t auth_len = strlen(CONFIG_TQ_VOICE_API_KEY) + 8; - char *auth_value = (char *)malloc(auth_len); + char *auth_value = (char *)voice_malloc_prefer_psram(auth_len); if (auth_value == NULL) { voice_fill_err(err, err_len, "no memory for auth header"); ESP_LOGE(TAG, "[stage] ws_auth_header_alloc_failed"); @@ -360,9 +362,11 @@ esp_err_t voice_interaction_tap_start(char *err, size_t err_len) { } voice_unlock(); + voice_log_heap_snapshot("tap_start_before_audio_open"); esp_err_t audio_err = voice_open_audio_for_dialog(err, err_len); if (audio_err != ESP_OK) { + voice_log_heap_snapshot("tap_start_audio_open_failed"); return audio_err; } diff --git a/main/domain/src/voice_interaction_common.c b/main/domain/src/voice_interaction_common.c index b3fcf68..b2b8eef 100644 --- a/main/domain/src/voice_interaction_common.c +++ b/main/domain/src/voice_interaction_common.c @@ -71,18 +71,22 @@ void voice_log_status_snapshot(const char *stage) { void voice_log_heap_snapshot(const char *stage) { size_t free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); size_t free_internal = heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t free_dma = heap_caps_get_free_size(MALLOC_CAP_DMA | MALLOC_CAP_8BIT); size_t free_spiram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); size_t largest_8bit = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); size_t largest_internal = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t largest_dma = heap_caps_get_largest_free_block(MALLOC_CAP_DMA | MALLOC_CAP_8BIT); size_t largest_spiram = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); ESP_LOGI(TAG, - "[stage] %s heap: free8=%u free_internal=%u free_spiram=%u largest8=%u largest_internal=%u largest_spiram=%u", + "[stage] %s heap: free8=%u free_internal=%u free_dma=%u free_spiram=%u largest8=%u largest_internal=%u largest_dma=%u largest_spiram=%u", stage, (unsigned)free_8bit, (unsigned)free_internal, + (unsigned)free_dma, (unsigned)free_spiram, (unsigned)largest_8bit, (unsigned)largest_internal, + (unsigned)largest_dma, (unsigned)largest_spiram); } diff --git a/main/domain/src/voice_interaction_ws.c b/main/domain/src/voice_interaction_ws.c index 979f918..967e824 100644 --- a/main/domain/src/voice_interaction_ws.c +++ b/main/domain/src/voice_interaction_ws.c @@ -6,7 +6,11 @@ #include #include +#define cJSON_malloc voice_malloc_prefer_psram +#define cJSON_realloc voice_realloc_prefer_psram #include "cJSON.h" +#undef cJSON_realloc +#undef cJSON_malloc #include "esp_audio_dec.h" #include "esp_audio_enc.h" #include "esp_log.h" @@ -25,9 +29,33 @@ typedef struct { char dialog_id[40]; } voice_image_generation_task_arg_t; +static void *voice_cjson_malloc_hook(size_t size) { + return voice_malloc_prefer_psram(size); +} + +static void voice_cjson_init_hooks_once(void) { + static bool s_cjson_hooks_ready; + if (s_cjson_hooks_ready) { + return; + } + + cJSON_Hooks hooks = { + .malloc_fn = voice_cjson_malloc_hook, + .free_fn = free, + }; + cJSON_InitHooks(&hooks); + s_cjson_hooks_ready = true; +} + +void voice_interaction_ws_init_cjson_hooks(void) { + voice_cjson_init_hooks_once(); +} + static char *voice_build_directive_message(const char *action, const char *directive, bool with_dialog_id) { + voice_cjson_init_hooks_once(); + cJSON *root = cJSON_CreateObject(); if (root == NULL) { return NULL; @@ -51,6 +79,8 @@ static char *voice_build_directive_message(const char *action, } static char *voice_build_start_message(void) { + voice_cjson_init_hooks_once(); + cJSON *root = cJSON_CreateObject(); if (root == NULL) { return NULL; @@ -617,6 +647,8 @@ static void voice_handle_output_event(cJSON *output) { } static void voice_handle_text_message(const char *text, size_t len) { + voice_cjson_init_hooks_once(); + cJSON *root = cJSON_ParseWithLength(text, len); if (root == NULL) { ESP_LOGW(TAG, "Invalid ws text payload"); diff --git a/main/platform/src/platform_bootstrap.c b/main/platform/src/platform_bootstrap.c index 542f493..f79a031 100644 --- a/main/platform/src/platform_bootstrap.c +++ b/main/platform/src/platform_bootstrap.c @@ -2,9 +2,25 @@ #include +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "mbedtls/platform.h" #include "nvs_flash.h" static bool s_initialized; +static const char *TAG = "platform_bootstrap"; + +static void *tls_calloc_prefer_psram(size_t n, size_t size) { + void *ptr = heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + if (ptr == NULL) { + ptr = heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + } + return ptr; +} + +static void tls_free(void *ptr) { + heap_caps_free(ptr); +} esp_err_t platform_bootstrap_init(void) { if (s_initialized) { @@ -18,6 +34,21 @@ esp_err_t platform_bootstrap_init(void) { } ESP_ERROR_CHECK(err); +#if CONFIG_SPIRAM_USE_MALLOC + // Keep very small allocations on internal RAM, push larger generic mallocs to PSRAM. + heap_caps_malloc_extmem_enable(4096); + ESP_LOGI(TAG, "extmem malloc threshold set to 4096 bytes"); +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) + int tls_rc = mbedtls_platform_set_calloc_free(tls_calloc_prefer_psram, tls_free); + if (tls_rc == 0) { + ESP_LOGI(TAG, "mbedtls calloc/free redirected to PSRAM-preferred allocator"); + } else { + ESP_LOGW(TAG, "mbedtls calloc/free redirect failed: rc=%d", tls_rc); + } +#endif + s_initialized = true; return ESP_OK; }