mirror of
https://github.com/espressif/esp-mqtt.git
synced 2026-08-03 20:14:15 +02:00
Merge branch 'feature-psram-memory-config' into 'master'
MR: feat: Allows esp-mqtt task and work buffers to be allocated in external memory See merge request espressif/esp-mqtt!323
This commit is contained in:
@@ -159,6 +159,31 @@ menu "ESP-MQTT Configurations"
|
||||
help
|
||||
Set to true to use external memory for outbox data.
|
||||
|
||||
config MQTT_BUFFERS_ON_EXTERNAL_MEMORY
|
||||
bool "Use external memory for the client buffers"
|
||||
default n
|
||||
depends on SPIRAM
|
||||
help
|
||||
Set to true to allocate the client input and output buffers (see buffer.size and
|
||||
buffer.out_size in the client configuration) in external memory.
|
||||
|
||||
config MQTT_TASK_STACK_ON_EXTERNAL_MEMORY
|
||||
bool "Use external memory for the MQTT task stack"
|
||||
default n
|
||||
depends on SPIRAM
|
||||
# FREERTOS_TASK_CREATE_ALLOW_EXT_MEM is the name from IDF v5.4 onwards, the other one is
|
||||
# used by IDF v5.3.
|
||||
depends on FREERTOS_TASK_CREATE_ALLOW_EXT_MEM || SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
help
|
||||
Set to true to allocate the MQTT task stack in external memory. The task control block
|
||||
is always kept in internal memory.
|
||||
|
||||
External memory is inaccessible while the flash cache is disabled, so with this option
|
||||
the MQTT task must not run any code that disables the cache. In particular, flash and
|
||||
NVS operations, and entering deep or light sleep, are not allowed from the MQTT task
|
||||
context. This includes user code running in an event handler dispatched by the MQTT
|
||||
task.
|
||||
|
||||
config MQTT_CUSTOM_OUTBOX
|
||||
bool "Enable custom outbox implementation"
|
||||
default n
|
||||
|
||||
@@ -236,6 +236,28 @@ The following settings are available:
|
||||
|
||||
- :ref:`CONFIG_MQTT_CUSTOM_OUTBOX`: disable default implementation of mqtt_outbox, so a specific implementation can be supplied
|
||||
|
||||
Memory placement
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
On targets with external RAM (PSRAM), the biggest allocations of the client can be moved out of
|
||||
internal RAM:
|
||||
|
||||
- :ref:`CONFIG_MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY`: place the payloads of the messages kept in the
|
||||
outbox in external memory.
|
||||
|
||||
- :ref:`CONFIG_MQTT_BUFFERS_ON_EXTERNAL_MEMORY`: place the client input and output buffers (sized by
|
||||
:cpp:member:`buffer.size <esp_mqtt_client_config_t::buffer_t::size>` and
|
||||
:cpp:member:`buffer.out_size <esp_mqtt_client_config_t::buffer_t::out_size>`) in external memory.
|
||||
|
||||
- :ref:`CONFIG_MQTT_TASK_STACK_ON_EXTERNAL_MEMORY`: place the MQTT task stack in external memory. The
|
||||
task control block always stays in internal RAM. This option requires
|
||||
:ref:`CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM`.
|
||||
|
||||
External memory is inaccessible while the flash cache is disabled. With the task stack in external
|
||||
memory, the MQTT task must therefore not run any code that disables the cache: flash and NVS
|
||||
operations, and entering deep or light sleep, are not allowed from the MQTT task context. This
|
||||
includes user code running in an event handler dispatched by the MQTT task.
|
||||
|
||||
Considerations when using ESP-MQTT with unstable network connection
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
When using ESP-MQTT with QoS>0 it does not send the message immediately, but keeps in in the outbox while it's being processed.
|
||||
|
||||
@@ -37,3 +37,7 @@ index.rst:line: WARNING: undefined label: 'config_mqtt_protocol_311'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_transport_ssl'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_transport_websocket'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_custom_outbox'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_outbox_data_on_external_memory'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_buffers_on_external_memory'
|
||||
index.rst:line: WARNING: undefined label: 'config_mqtt_task_stack_on_external_memory'
|
||||
index.rst:line: WARNING: undefined label: 'config_freertos_task_create_allow_ext_mem'
|
||||
|
||||
@@ -187,6 +187,24 @@ ESP-MQTT 库将始终重新传输未确认的 QoS 1 和 2 发布消息,以避
|
||||
|
||||
- :ref:`CONFIG_MQTT_CUSTOM_OUTBOX`:禁用 mqtt_outbox 默认实现,因此可以提供特定实现
|
||||
|
||||
内存分配位置
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
在具有外部 RAM(PSRAM)的芯片上,可以将客户端占用内存最多的部分从内部 RAM 移出:
|
||||
|
||||
- :ref:`CONFIG_MQTT_OUTBOX_DATA_ON_EXTERNAL_MEMORY`:将 outbox 中保存的消息负载分配在外部内存中。
|
||||
|
||||
- :ref:`CONFIG_MQTT_BUFFERS_ON_EXTERNAL_MEMORY`:将客户端的输入和输出缓冲区(大小由
|
||||
:cpp:member:`buffer.size <esp_mqtt_client_config_t::buffer_t::size>` 和
|
||||
:cpp:member:`buffer.out_size <esp_mqtt_client_config_t::buffer_t::out_size>` 决定)分配在外部内存中。
|
||||
|
||||
- :ref:`CONFIG_MQTT_TASK_STACK_ON_EXTERNAL_MEMORY`:将 MQTT 任务栈分配在外部内存中。任务控制块始终位于内部
|
||||
RAM 中。该选项需要启用 :ref:`CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM`。
|
||||
|
||||
flash cache 被禁用时无法访问外部内存。因此,当任务栈位于外部内存中时,MQTT 任务不能执行任何会禁用 cache 的代码:
|
||||
不允许在 MQTT 任务上下文中进行 flash 和 NVS 操作,也不允许进入 deep sleep 或 light sleep。这也包括由 MQTT
|
||||
任务分发的事件处理函数中运行的用户代码。
|
||||
|
||||
|
||||
事件
|
||||
------------
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -96,6 +96,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MQTT_CORE_SELECTION_ENABLED
|
||||
#define MQTT_TASK_AFFINITY MQTT_TASK_CORE
|
||||
#else
|
||||
#define MQTT_TASK_AFFINITY tskNO_AFFINITY
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS
|
||||
#define OUTBOX_EXPIRED_TIMEOUT_MS CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT_MS
|
||||
#else
|
||||
@@ -119,5 +125,17 @@
|
||||
#define MQTT_OUTBOX_MEMORY MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_BUFFERS_ON_EXTERNAL_MEMORY
|
||||
#define MQTT_BUFFER_MEMORY MALLOC_CAP_SPIRAM
|
||||
#else
|
||||
#define MQTT_BUFFER_MEMORY MALLOC_CAP_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MQTT_TASK_STACK_ON_EXTERNAL_MEMORY
|
||||
#define MQTT_TASK_STACK_ON_EXTERNAL_MEMORY 1
|
||||
#else
|
||||
#define MQTT_TASK_STACK_ON_EXTERNAL_MEMORY 0
|
||||
#endif
|
||||
|
||||
#define OUTBOX_MAX_SIZE (4*1024)
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "esp_heap_caps.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "mqtt_msg.h"
|
||||
#include "mqtt_config.h"
|
||||
@@ -633,7 +634,7 @@ int mqtt_has_valid_msg_hdr(uint8_t *buffer, size_t length)
|
||||
esp_err_t mqtt_msg_buffer_init(mqtt_connection_t *connection, int buffer_size)
|
||||
{
|
||||
memset(&connection->outbound_message, 0, sizeof(mqtt_message_t));
|
||||
connection->buffer = (uint8_t *)calloc(buffer_size, sizeof(uint8_t));
|
||||
connection->buffer = (uint8_t *)heap_caps_calloc(buffer_size, sizeof(uint8_t), MQTT_BUFFER_MEMORY);
|
||||
|
||||
if (!connection->buffer) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
+14
-6
@@ -488,7 +488,7 @@ esp_err_t esp_mqtt_set_config(esp_mqtt_client_handle_t client, const esp_mqtt_cl
|
||||
}
|
||||
|
||||
free(client->mqtt_state.in_buffer);
|
||||
client->mqtt_state.in_buffer = (uint8_t *)malloc(buffer_size);
|
||||
client->mqtt_state.in_buffer = (uint8_t *)heap_caps_malloc(buffer_size, MQTT_BUFFER_MEMORY);
|
||||
ESP_MEM_CHECK(TAG, client->mqtt_state.in_buffer, goto _mqtt_set_config_failed);
|
||||
client->mqtt_state.in_buffer_length = buffer_size;
|
||||
client->config->message_retransmit_timeout = config->session.message_retransmit_timeout;
|
||||
@@ -2186,7 +2186,11 @@ static void esp_mqtt_task(void *pv)
|
||||
outbox_delete_all_items(client->outbox);
|
||||
client->state = MQTT_STATE_DISCONNECTED;
|
||||
xEventGroupSetBits(client->status_bits, STOPPED_BIT);
|
||||
#if MQTT_TASK_STACK_ON_EXTERNAL_MEMORY
|
||||
vTaskDeleteWithCaps(NULL);
|
||||
#else
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client)
|
||||
@@ -2207,18 +2211,22 @@ esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_t client)
|
||||
esp_err_t err = ESP_OK;
|
||||
#if MQTT_CORE_SELECTION_ENABLED
|
||||
ESP_LOGD(TAG, "Core selection enabled on %u", MQTT_TASK_CORE);
|
||||
#else
|
||||
ESP_LOGD(TAG, "Core selection disabled");
|
||||
#endif
|
||||
#if MQTT_TASK_STACK_ON_EXTERNAL_MEMORY
|
||||
|
||||
if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio,
|
||||
&client->task_handle, MQTT_TASK_CORE) != pdTRUE) {
|
||||
if (xTaskCreatePinnedToCoreWithCaps(esp_mqtt_task, "mqtt_task", client->config->task_stack, client,
|
||||
client->config->task_prio, &client->task_handle, MQTT_TASK_AFFINITY,
|
||||
MALLOC_CAP_SPIRAM) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Error create mqtt task");
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
|
||||
#else
|
||||
ESP_LOGD(TAG, "Core selection disabled");
|
||||
|
||||
if (xTaskCreate(esp_mqtt_task, "mqtt_task", client->config->task_stack, client, client->config->task_prio,
|
||||
&client->task_handle) != pdTRUE) {
|
||||
if (xTaskCreatePinnedToCore(esp_mqtt_task, "mqtt_task", client->config->task_stack, client,
|
||||
client->config->task_prio, &client->task_handle, MQTT_TASK_AFFINITY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Error create mqtt task");
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user