Merge branch 'feat/esp_async_memcpy_blocking_api' into 'master'

feat(esp_driver_dma): add blocking async memcpy API

See merge request espressif/esp-idf!49295
This commit is contained in:
morris
2026-06-08 22:24:09 +08:00
5 changed files with 73 additions and 19 deletions
@@ -174,6 +174,25 @@ esp_err_t esp_async_memcpy_uninstall(async_memcpy_handle_t mcp);
*/
esp_err_t esp_async_memcpy(async_memcpy_handle_t mcp, void *dst, void *src, size_t n, async_memcpy_isr_cb_t cb_isr, void *cb_args);
/**
* @brief Blocking memory copy function with timeout
*
* @note This function is blocking and should not be called from interrupt context.
* @note Only `timeout_ms=-1` is supported, which means waiting indefinitely.
*
* @param[in] mcp Handle of async memcpy driver that returned from `esp_async_memcpy_install`
* @param[in] dst Destination address (copy to)
* @param[in] src Source address (copy from)
* @param[in] n Number of bytes to copy
* @param[in] timeout_ms Timeout in milliseconds. Only -1 is supported.
* @return
* - ESP_OK: Copy memory successfully
* - ESP_ERR_INVALID_ARG: Copy memory failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Function called from ISR context or driver in invalid state
* - ESP_FAIL: Copy memory failed because of other error
*/
esp_err_t esp_memcpy_blocking(async_memcpy_handle_t mcp, void *dst, void *src, size_t n, int32_t timeout_ms);
#if SOC_ETM_SUPPORTED
/**
* @brief Async memory copy specific events that supported by the ETM module
@@ -4,6 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "esp_check.h"
#include "esp_async_memcpy.h"
#include "esp_async_memcpy_priv.h"
@@ -22,6 +25,38 @@ esp_err_t esp_async_memcpy(async_memcpy_handle_t asmcp, void *dst, void *src, si
return asmcp->memcpy(asmcp, dst, src, n, cb_isr, cb_args);
}
typedef struct {
SemaphoreHandle_t semaphore;
StaticSemaphore_t semaphore_buffer;
} memcpy_blocking_context_t;
static bool memcpy_blocking_callback(async_memcpy_handle_t mcp_hdl, async_memcpy_event_t *event, void *user_data)
{
BaseType_t task_woken = pdFALSE;
memcpy_blocking_context_t *ctx = (memcpy_blocking_context_t *)user_data;
(void)mcp_hdl;
(void)event;
xSemaphoreGiveFromISR(ctx->semaphore, &task_woken);
return task_woken == pdTRUE;
}
esp_err_t esp_memcpy_blocking(async_memcpy_handle_t asmcp, void *dst, void *src, size_t n, int32_t timeout_ms)
{
ESP_RETURN_ON_FALSE(asmcp && dst && src && n, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(!xPortInIsrContext(), ESP_ERR_INVALID_STATE, TAG, "called from ISR context is not allowed");
ESP_RETURN_ON_FALSE(timeout_ms == -1, ESP_ERR_INVALID_ARG, TAG, "only timeout_ms=-1 is supported");
memcpy_blocking_context_t ctx = {};
ctx.semaphore = xSemaphoreCreateBinaryStatic(&ctx.semaphore_buffer);
ESP_RETURN_ON_ERROR(esp_async_memcpy(asmcp, dst, src, n, memcpy_blocking_callback, &ctx), TAG, "failed to start memory copy");
xSemaphoreTake(ctx.semaphore, portMAX_DELAY);
return ESP_OK;
}
#if SOC_ETM_SUPPORTED
esp_err_t esp_async_memcpy_new_etm_event(async_memcpy_handle_t asmcp, async_memcpy_etm_event_t event_type, esp_etm_event_handle_t *out_event)
{
@@ -12,7 +12,6 @@
#include "soc/soc_caps.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "ccomp_timer.h"
#include "esp_async_memcpy.h"
@@ -102,8 +101,7 @@ static void test_memory_copy_with_same_buffer(async_memcpy_handle_t driver, asyn
TEST_ASSERT_NOT_NULL(dbuf);
for (int j = 0; j < 20; j++) {
TEST_ESP_OK(esp_async_memcpy(driver, dbuf, sbuf, 256, NULL, NULL));
vTaskDelay(pdMS_TO_TICKS(10));
TEST_ESP_OK(esp_memcpy_blocking(driver, dbuf, sbuf, 256, -1));
for (int i = 0; i < 256; i++) {
if (sbuf[i] != dbuf[i]) {
printf("location[%d]:s=%d,d=%d\r\n", i, sbuf[i], dbuf[i]);
@@ -151,17 +149,8 @@ TEST_CASE("memory copy the same buffer with different content", "[async mcp]")
#endif // SOC_HAS(LP_AHB_GDMA)
}
static bool test_async_memcpy_cb_v1(async_memcpy_handle_t mcp_hdl, async_memcpy_event_t *event, void *cb_args)
{
SemaphoreHandle_t sem = (SemaphoreHandle_t)cb_args;
BaseType_t high_task_wakeup = pdFALSE;
xSemaphoreGiveFromISR(sem, &high_task_wakeup);
return high_task_wakeup == pdTRUE;
}
static void test_memory_copy_blocking(async_memcpy_handle_t driver)
{
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
const uint32_t test_buffer_size[] = {256, 512, 1024, 2048, 4096, 5008};
memcpy_testbench_context_t test_context = {
.align = 16,
@@ -177,13 +166,11 @@ static void test_memory_copy_blocking(async_memcpy_handle_t driver)
}
async_memcpy_setup_testbench(&test_context);
TEST_ESP_OK(esp_async_memcpy(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, test_async_memcpy_cb_v1, sem));
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(10)));
TEST_ESP_OK(esp_memcpy_blocking(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, -1));
async_memcpy_verify_and_clear_testbench(test_context.copy_size, test_context.src_buf, test_context.dst_buf,
test_context.from_addr, test_context.to_addr);
}
}
vSemaphoreDelete(sem);
}
TEST_CASE("memory copy by DMA (blocking)", "[async mcp]")
@@ -225,7 +212,6 @@ TEST_CASE("memory copy by DMA (blocking)", "[async mcp]")
[[maybe_unused]] static void test_memcpy_with_dest_addr_unaligned(async_memcpy_handle_t driver, bool src_in_psram, bool dst_in_psram)
{
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
const uint32_t test_buffer_size[] = {256, 512, 1024, 2048, 4096, 5012};
memcpy_testbench_context_t test_context = {
.align = 4,
@@ -241,13 +227,11 @@ TEST_CASE("memory copy by DMA (blocking)", "[async mcp]")
test_context.dst_offset = off + 1;
async_memcpy_setup_testbench(&test_context);
TEST_ESP_OK(esp_async_memcpy(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, test_async_memcpy_cb_v1, sem));
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(10)));
TEST_ESP_OK(esp_memcpy_blocking(driver, test_context.to_addr, test_context.from_addr, test_context.copy_size, -1));
async_memcpy_verify_and_clear_testbench(test_context.copy_size, test_context.src_buf, test_context.dst_buf,
test_context.from_addr, test_context.to_addr);
}
}
vSemaphoreDelete(sem);
}
TEST_CASE("memory copy with dest address unaligned", "[async mcp]")