异步内存复制
概述
ESP32-H2 有一个 DMA 引擎,能够以异步方式帮助 CPU 完成内部内存复制操作。
异步 memcpy API 中封装了所有 DMA 配置和操作,esp_async_memcpy() 的签名与标准 C 库的 memcpy 函数基本相同。
DMA 允许多个内存复制请求在首个请求完成之前排队,即允许计算和内存复制的重叠。此外,通过注册事件回调函数,还可以知道内存复制请求完成的准确时间。
配置并安装驱动
安装异步 memcpy 驱动的方法取决于底层 DMA 引擎:
- esp_async_memcpy_install_gdma_ahb()用于安装基于 AHB GDMA 引擎的异步 memcpy 驱动。
- esp_async_memcpy_install()是一个通用 API,用于安装带有默认 DMA 引擎的异步 memcpy 驱动。如果 SoC 具有 CP DMA 引擎,则默认 DMA 引擎为 CP DMA,否则,默认 DMA 引擎为 AHB GDMA。
在 async_memcpy_config_t 中设置驱动配置:
- backlog:此项用于配置首个请求完成前可以排队的最大内存复制事务数量。如果将此字段设置为零,会应用默认值 4。
- dma_burst_size:设置单次 DMA 传输中突发数据量的大小。
- flags:此项可以启用一些特殊的驱动功能。
async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG();
// 更新底层 DMA 引擎支持的最大数据流
config.backlog = 8;
async_memcpy_handle_t driver = NULL;
ESP_ERROR_CHECK(esp_async_memcpy_install(&config, &driver)); // 使用默认 DMA 引擎安装驱动
发送内存复制请求
使用 esp_async_memcpy() API 将内存复制请求发送到 DMA 引擎。在驱动程序成功安装后才能调用该 API。此 API 是线程安全的,因此可以从不同的任务中调用。
与 libc 版本的 memcpy 不同,你可以选择给 esp_async_memcpy() 设置一个回调函数,以便在内存复制完成时收到通知。注意,回调是在 ISR 上下文中执行的,请不要在回调中调用任何阻塞函数。
回调函数的原型是 async_memcpy_isr_cb_t。回调函数只有在借助 RTOS API(如 xSemaphoreGiveFromISR())唤醒了高优先级任务后才能返回 true。
// 回调实现,在 ISR 上下文中运行
static bool my_async_memcpy_cb(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(semphr, &high_task_wakeup); // 如果解锁了一些高优先级任务,则将 high_task_wakeup 设置为 pdTRUE
    return high_task_wakeup == pdTRUE;
}
// 创建一个信号量,在异步 memcpy 完成时进行报告
SemaphoreHandle_t semphr = xSemaphoreCreateBinary();
// 从用户的上下文中调用
ESP_ERROR_CHECK(esp_async_memcpy(driver_handle, to, from, copy_len, my_async_memcpy_cb, my_semaphore));
// 其他事项
xSemaphoreTake(my_semaphore, portMAX_DELAY); // 等待 buffer 复制完成
卸载驱动
使用 esp_async_memcpy_uninstall() 卸载异步 memcpy 驱动。无需在每次 memcpy 操作后手动卸载。如果你的应用程序不再需要此驱动,此 API 可以帮助回收内存和其他硬件资源。
ETM 事件
在异步 memcpy 操作完成时会生成一个事件,此事件能够与 ETM 模块进行交互。可以调用 esp_async_memcpy_new_etm_event() 获取 ETM 事件句柄。
如需了解如何将此事件连接到 ETM 通道,请参考文档 ETM。
API 参考
Header File
- This header file can be included with: - #include "esp_async_memcpy.h" 
Functions
- 
esp_err_t esp_async_memcpy_install_gdma_ahb(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp)
- Install async memcpy driver, with AHB-GDMA as the backend. - 参数
- config -- [in] Configuration of async memcpy 
- mcp -- [out] Returned driver handle 
 
- 返回
- ESP_OK: Install async memcpy driver successfully 
- ESP_ERR_INVALID_ARG: Install async memcpy driver failed because of invalid argument 
- ESP_ERR_NO_MEM: Install async memcpy driver failed because out of memory 
- ESP_FAIL: Install async memcpy driver failed because of other error 
 
 
- 
esp_err_t esp_async_memcpy_install(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp)
- Install async memcpy driver with the default DMA backend. - 备注 - On chip with CPDMA support, CPDMA is the default choice. On chip with AHB-GDMA support, AHB-GDMA is the default choice. - 参数
- config -- [in] Configuration of async memcpy 
- mcp -- [out] Returned driver handle 
 
- 返回
- ESP_OK: Install async memcpy driver successfully 
- ESP_ERR_INVALID_ARG: Install async memcpy driver failed because of invalid argument 
- ESP_ERR_NO_MEM: Install async memcpy driver failed because out of memory 
- ESP_FAIL: Install async memcpy driver failed because of other error 
 
 
- 
esp_err_t esp_async_memcpy_uninstall(async_memcpy_handle_t mcp)
- Uninstall async memcpy driver. - 参数
- mcp -- [in] Handle of async memcpy driver that returned from - esp_async_memcpy_install
- 返回
- ESP_OK: Uninstall async memcpy driver successfully 
- ESP_ERR_INVALID_ARG: Uninstall async memcpy driver failed because of invalid argument 
- ESP_FAIL: Uninstall async memcpy driver failed because of other error 
 
 
- 
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)
- Send an asynchronous memory copy request. - 备注 - The callback function is invoked in interrupt context, never do blocking jobs in the callback. - 参数
- mcp -- [in] Handle of async memcpy driver that returned from - esp_async_memcpy_install
- dst -- [in] Destination address (copy to) 
- src -- [in] Source address (copy from) 
- n -- [in] Number of bytes to copy 
- cb_isr -- [in] Callback function, which got invoked in interrupt context. Set to NULL can bypass the callback. 
- cb_args -- [in] User defined argument to be passed to the callback function 
 
- 返回
- ESP_OK: Send memory copy request successfully 
- ESP_ERR_INVALID_ARG: Send memory copy request failed because of invalid argument 
- ESP_FAIL: Send memory copy request failed because of other error 
 
 
- 
esp_err_t esp_async_memcpy_new_etm_event(async_memcpy_handle_t mcp, async_memcpy_etm_event_t event_type, esp_etm_event_handle_t *out_event)
- Get the ETM event handle for async memcpy done signal. - 备注 - The created ETM event object can be deleted later by calling - esp_etm_del_event- 参数
- mcp -- [in] Handle of async memcpy driver that returned from - esp_async_memcpy_install
- event_type -- [in] ETM event type 
- out_event -- [out] Returned ETM event handle 
 
- 返回
- ESP_OK: Get ETM event successfully 
- ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument 
- ESP_ERR_NOT_SUPPORTED: Get ETM event failed because the DMA hardware doesn't support ETM submodule 
- ESP_FAIL: Get ETM event failed because of other error 
 
 
Structures
- 
struct async_memcpy_config_t
- Type of async memcpy configuration. - Public Members - 
uint32_t backlog
- Maximum number of transactions that can be prepared in the background 
 - 
size_t sram_trans_align
- DMA transfer alignment (both in size and address) for SRAM memory 
 - 
size_t psram_trans_align
- DMA transfer alignment (both in size and address) for PSRAM memory 
 - 
size_t dma_burst_size
- DMA transfer burst size, in bytes 
 - 
uint32_t flags
- Extra flags to control async memcpy feature 
 
- 
uint32_t backlog
Macros
- 
ASYNC_MEMCPY_DEFAULT_CONFIG()
- Default configuration for async memcpy. 
Type Definitions
- 
typedef struct async_memcpy_context_t *async_memcpy_handle_t
- Async memory copy driver handle. 
- 
typedef bool (*async_memcpy_isr_cb_t)(async_memcpy_handle_t mcp_hdl, async_memcpy_event_t *event, void *cb_args)
- Type of async memcpy interrupt callback function. - 备注 - User can call OS primitives (semaphore, mutex, etc) in the callback function. Keep in mind, if any OS primitive wakes high priority task up, the callback should return true. - Param mcp_hdl
- Handle of async memcpy 
- Param event
- Event object, which contains related data, reserved for future 
- Param cb_args
- User defined arguments, passed from esp_async_memcpy function 
- Return
- Whether a high priority task is woken up by the callback function