mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(esp_driver_dma): add blocking async memcpy API
Add a blocking wrapper for async memcpy so simple users can wait for one DMA copy without writing their own ISR callback and semaphore plumbing. Update functional tests and documentation to use the simpler API where async completion handling is not needed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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]")
|
||||
|
||||
Reference in New Issue
Block a user