diff --git a/docs/conf_common.py b/docs/conf_common.py
index fffb030bdde..9a55a42645d 100644
--- a/docs/conf_common.py
+++ b/docs/conf_common.py
@@ -388,6 +388,7 @@ conditional_include_dict = {
'SOC_HMAC_SUPPORTED': ['api-reference/peripherals/hmac.rst'],
'SOC_GDMA_SUPPORT_CRC': ['api-reference/peripherals/async_crc.rst'],
'SOC_ASYNC_MEMCPY_SUPPORTED': ['api-reference/peripherals/async_memcpy.rst'],
+ 'SOC_DMA2D_SUPPORTED': ['api-reference/peripherals/async_color_convert.rst'],
'SOC_KEY_MANAGER_SUPPORTED': ['api-reference/peripherals/key_manager.rst'],
'CONFIG_IDF_TARGET_ARCH_XTENSA': XTENSA_DOCS,
'CONFIG_IDF_TARGET_ARCH_RISCV': RISCV_DOCS,
diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile
index 5dd1f69b4ba..b35db72b09f 100644
--- a/docs/doxygen/Doxyfile
+++ b/docs/doxygen/Doxyfile
@@ -126,6 +126,7 @@ INPUT = \
$(PROJECT_PATH)/components/esp_driver_dac/include/driver/dac_oneshot.h \
$(PROJECT_PATH)/components/esp_driver_dac/include/driver/dac_types.h \
$(PROJECT_PATH)/components/esp_driver_dma/include/esp_async_crc.h \
+ $(PROJECT_PATH)/components/esp_driver_dma/include/esp_async_color_convert.h \
$(PROJECT_PATH)/components/esp_driver_dma/include/esp_async_memcpy.h \
$(PROJECT_PATH)/components/esp_driver_gpio/include/driver/dedic_gpio.h \
$(PROJECT_PATH)/components/esp_driver_gpio/include/driver/gpio.h \
diff --git a/docs/en/api-reference/peripherals/async_color_convert.rst b/docs/en/api-reference/peripherals/async_color_convert.rst
new file mode 100644
index 00000000000..548468053ab
--- /dev/null
+++ b/docs/en/api-reference/peripherals/async_color_convert.rst
@@ -0,0 +1,295 @@
+=============================
+Asynchronous Color Conversion
+=============================
+
+:link_to_translation:`zh_CN:[中文]`
+
+This document introduces the Async Color Convert driver in ESP-IDF. The table of contents is as follows:
+
+.. contents::
+ :local:
+ :depth: 2
+
+Overview
+========
+
+{IDF_TARGET_NAME} provides a DMA2D engine that can offload 2D copy and color conversion work from the CPU.
+
+This driver is useful when your application needs to:
+
+- convert an image from one pixel format to another
+- copy only a window of a larger image
+- queue multiple conversions without doing the work on the CPU
+- move between RGB and UYVY formats while selecting the RGB/YUV conversion standard
+
+The Async Color Convert driver wraps DMA2D request preparation, queueing, and completion handling into a small API that supports both:
+
+- asynchronous submission with an ISR callback
+- a simpler blocking API built on top of the same request path
+
+Quick Start
+===========
+
+If you are new to this driver, start with the simplest workflow:
+
+1. Install the driver
+2. Prepare one :cpp:type:`async_color_convert_request_t`
+3. Submit the conversion through either the blocking or non-blocking API
+4. Consume the converted output buffer after the conversion completes
+5. Either submit another request or uninstall the driver when finished
+
+The typical usage flow is:
+
+.. mermaid::
+
+ flowchart TD
+ install["Install driver
esp_async_color_convert_install_dma2d"] --> request["Prepare request
async_color_convert_request_t"]
+ request --> blocking["Blocking path
esp_color_convert_blocking"]
+ request --> nonBlocking["Non-blocking path
esp_async_color_convert"]
+ nonBlocking --> callback["Wait for callback or task notification"]
+ blocking --> result["Use converted buffer"]
+ callback --> result
+ result --> request
+ result --> uninstall["Optional cleanup
esp_async_color_convert_uninstall"]
+
+Scenario 1: Start with One Blocking Conversion
+==============================================
+
+The easiest way to learn the API is to convert one image and wait until the conversion is complete.
+
+The following flow mirrors the :example:`peripherals/dma/async_color_convert` example. It converts one embedded UYVY422 image into BGR24 and then lets the application consume the converted output:
+
+.. code:: c
+
+ async_color_convert_handle_t conv_hdl = NULL; // Driver handle returned by the install API
+ async_color_convert_config_t config = {
+ .backlog = 1, // One in-flight request is enough for this simple blocking example
+ .dma_burst_size = 16, // Start with the default burst size used by the example
+ };
+ // Create one Async Color Convert driver instance backed by DMA2D.
+ ESP_ERROR_CHECK(esp_async_color_convert_install_dma2d(&config, &conv_hdl));
+
+ async_color_convert_request_t req = {
+ .src_buffer = sample_96x64_uyvy_yuv_start, // Source image can be in flash or RAM, as long as DMA can access it
+ .src_stride = 96, // Source image row stride, in pixels
+ .src_height = 64, // Source image height, in pixels
+ .src_x = 0, // Start from the left edge of the source image
+ .src_y = 0,
+ .dst_buffer = dst_bgr, // Destination buffer in DMA-capable RAM
+ .dst_stride = 96, // Destination image row stride, in pixels
+ .dst_height = 64, // Destination image height, in pixels
+ .dst_x = 0, // Write the converted output from the top-left corner
+ .dst_y = 0,
+ .copy_width = 96, // Convert the full image width, in pixels
+ .copy_height = 64, // Convert the full image height, in pixels
+ .src_color_format = ESP_COLOR_FOURCC_UYVY, // Source pixels are UYVY422
+ .dst_color_format = ESP_COLOR_FOURCC_BGR24, // Destination pixels are BGR24 (used as RGB888 in this driver)
+ .color_conv_std = COLOR_CONV_STD_RGB_YUV_BT601, // RGB/YUV standard used for this conversion pair
+ };
+
+ // Wait until DMA2D finishes the conversion. -1 means wait forever.
+ ESP_ERROR_CHECK(esp_color_convert_blocking(conv_hdl, &req, -1));
+
+ // Release the driver after all conversions are done.
+ ESP_ERROR_CHECK(esp_async_color_convert_uninstall(conv_hdl));
+
+This flow introduces the most important ideas:
+
+- :cpp:func:`esp_async_color_convert_install_dma2d` creates the driver instance
+- :cpp:type:`async_color_convert_request_t` describes the source image, destination image, and conversion window
+- :cpp:func:`esp_color_convert_blocking` waits until the hardware finishes the conversion
+- :cpp:func:`esp_async_color_convert_uninstall` releases the driver resources
+
+For the blocking API, ``timeout_ms = -1`` means wait forever. Other timeout values are currently unsupported and return ``ESP_ERR_INVALID_ARG``.
+
+Understanding ``async_color_convert_request_t``
+-----------------------------------------------
+
+Most application issues come from building the request incorrectly, so it is worth understanding the structure carefully.
+
+.. important::
+
+ In :cpp:type:`async_color_convert_request_t`, all geometry fields are measured in **pixels**, not bytes. This includes ``src_stride``, ``src_height``, ``src_x``, ``src_y``, ``dst_stride``, ``dst_height``, ``dst_x``, ``dst_y``, ``copy_width``, and ``copy_height``.
+
+ ``src_stride`` and ``dst_stride`` are row strides, not conversion widths. They describe how many pixels each full image row spans in memory, so they can be larger than ``copy_width`` when converting a window inside a larger image.
+
+The structure describes two things at the same time:
+
+- the full source and destination images in memory
+- the rectangular window that should be converted
+
+The key fields are:
+
+- :cpp:member:`async_color_convert_request_t::src_buffer`
+ Base address of the source image
+- :cpp:member:`async_color_convert_request_t::src_stride`
+ Source image row stride in pixels
+- :cpp:member:`async_color_convert_request_t::src_height`
+ Source image height in pixels
+- :cpp:member:`async_color_convert_request_t::src_x` and :cpp:member:`async_color_convert_request_t::src_y`
+ Top-left corner of the source window
+- :cpp:member:`async_color_convert_request_t::dst_buffer`
+ Base address of the destination image
+- :cpp:member:`async_color_convert_request_t::dst_stride`
+ Destination image row stride in pixels
+- :cpp:member:`async_color_convert_request_t::dst_height`
+ Destination image height in pixels
+- :cpp:member:`async_color_convert_request_t::dst_x` and :cpp:member:`async_color_convert_request_t::dst_y`
+ Top-left corner of where the converted window should be written
+- :cpp:member:`async_color_convert_request_t::copy_width` and :cpp:member:`async_color_convert_request_t::copy_height`
+ Size of the rectangle to convert
+- :cpp:member:`async_color_convert_request_t::src_color_format` and :cpp:member:`async_color_convert_request_t::dst_color_format`
+ Source and destination pixel formats
+- :cpp:member:`async_color_convert_request_t::color_conv_std`
+ RGB/YUV conversion standard, used for RGB <-> YUV conversions
+
+Both the source window and destination window must stay within the bounds of their corresponding images.
+
+Supported Conversions
+---------------------
+
+The following format pairs are supported by this driver:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Source format
+ - Destination format
+ - Conversion standard
+ * - same as destination (skip conversion)
+ - same as source (skip conversion)
+ - N/A
+ * - RGB565
+ - RGB888
+ - N/A
+ * - RGB888
+ - RGB565
+ - N/A
+ * - RGB888
+ - UYVY422
+ - BT.601
+ * - RGB888
+ - UYVY422
+ - BT.709
+ * - UYVY422
+ - RGB888
+ - BT.601
+ * - UYVY422
+ - RGB888
+ - BT.709
+
+.. note::
+
+ In this driver, RGB888 uses ``ESP_COLOR_FOURCC_BGR24`` and UYVY422 uses ``ESP_COLOR_FOURCC_UYVY``.
+
+ Always set :cpp:member:`async_color_convert_request_t::src_color_format` and
+ :cpp:member:`async_color_convert_request_t::dst_color_format`.
+ Set :cpp:member:`async_color_convert_request_t::color_conv_std` when converting between RGB and YUV.
+
+Scenario 2: Use the Asynchronous API with a Callback
+====================================================
+
+Once the blocking flow is clear, the next step is to queue a request and let the driver notify you from interrupt context when it is finished.
+
+.. code:: c
+
+ static bool color_conv_done_cb(async_color_convert_handle_t conv_hdl,
+ async_color_convert_event_data_t *edata,
+ void *cb_args)
+ {
+ BaseType_t high_task_wakeup = pdFALSE; // Required by FreeRTOS when an ISR wakes a task
+ SemaphoreHandle_t sem = (SemaphoreHandle_t)cb_args; // User context passed at submit time
+ // Notify a waiting task that the conversion has finished.
+ xSemaphoreGiveFromISR(sem, &high_task_wakeup);
+ // Return true when the unblocked task should run immediately after the ISR.
+ return high_task_wakeup == pdTRUE;
+ }
+
+ async_color_convert_request_t req = {
+ .src_buffer = src_buf, // Source image base address
+ .src_stride = src_width, // Source image row stride, in pixels
+ .src_height = src_height,
+ .src_x = 0,
+ .src_y = 0,
+ .dst_buffer = dst_buf, // Destination image base address
+ .dst_stride = dst_width, // Destination image row stride, in pixels
+ .dst_height = dst_height,
+ .dst_x = 0,
+ .dst_y = 0,
+ .copy_width = copy_width,
+ .copy_height = copy_height,
+ .src_color_format = ESP_COLOR_FOURCC_RGB16,
+ .dst_color_format = ESP_COLOR_FOURCC_BGR24,
+ };
+
+ // Queue one asynchronous request. The callback runs later in ISR context.
+ ESP_ERROR_CHECK(esp_async_color_convert(conv_hdl, &req, color_conv_done_cb, sem));
+ // Wait in task context until the callback gives the semaphore.
+ xSemaphoreTake(sem, portMAX_DELAY);
+
+The callback runs in ISR context, so keep it short and only use ISR-safe APIs such as ``xSemaphoreGiveFromISR`` or ``xQueueSendFromISR``.
+
+Operational Notes
+=================
+
+Driver Configuration
+--------------------
+
+The driver configuration fields are:
+
+- :cpp:member:`async_color_convert_config_t::backlog`
+ Maximum number of in-flight or pending requests. ``0`` uses a driver default.
+- :cpp:member:`async_color_convert_config_t::dma_burst_size`
+ DMA burst size in bytes. ``0`` uses a driver default.
+- :cpp:member:`async_color_convert_config_t::intr_priority`
+ DMA2D interrupt priority. ``0`` uses the default low/medium priority.
+
+DMA Burst Size
+--------------
+
+The ``dma_burst_size`` affects DMA transfer efficiency:
+
+- Larger burst sizes may improve throughput
+- Larger burst sizes can also increase bus occupancy, so they are not always best for every workload
+- Common starting values are 16, 32, and 64 bytes
+
+The best value depends on the chip's DMA controller capabilities and how much memory bandwidth is shared with other active components in the system.
+
+Thread Safety and ISR Rules
+---------------------------
+
+- The driver is thread-safe. Requests from different tasks are serialized through the internal queue.
+- :cpp:func:`esp_async_color_convert` can be called from tasks to enqueue requests.
+- The callback type :cpp:type:`async_color_convert_isr_cb_t` runs in ISR context.
+- Do not call blocking APIs from the callback.
+- :cpp:func:`esp_color_convert_blocking` must not be called from ISR context.
+
+Uninstalling the Driver
+-----------------------
+
+When the driver is no longer needed:
+
+.. code:: c
+
+ // Uninstall only after all queued conversions have completed.
+ ESP_ERROR_CHECK(esp_async_color_convert_uninstall(conv_hdl));
+
+If requests are still pending, :cpp:func:`esp_async_color_convert_uninstall` returns :c:macro:`ESP_ERR_INVALID_STATE`.
+
+Application Example
+===================
+
+- :example:`peripherals/dma/async_color_convert` shows a beginner-friendly blocking conversion flow:
+
+ - an embedded ``.yuv`` image is read directly from mapped flash
+ - DMA2D converts the image from UYVY422 to BGR24
+ - the converted output is base64-encoded and printed to the console
+ - pytest reconstructs the image as a PNG artifact and compares it against a golden reference image
+
+API Reference
+=============
+
+Async Color Convert Driver Functions
+------------------------------------
+
+.. include-build-file:: inc/esp_async_color_convert.inc
diff --git a/docs/en/api-reference/peripherals/async_crc.rst b/docs/en/api-reference/peripherals/async_crc.rst
index fe2b4c21c43..b22fc3a9db7 100644
--- a/docs/en/api-reference/peripherals/async_crc.rst
+++ b/docs/en/api-reference/peripherals/async_crc.rst
@@ -1,5 +1,5 @@
============================
-Asynchronous CRC (Async CRC)
+Asynchronous CRC Calculation
============================
:link_to_translation:`zh_CN:[中文]`
diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst
index 3dcd8684769..f6459453860 100644
--- a/docs/en/api-reference/peripherals/index.rst
+++ b/docs/en/api-reference/peripherals/index.rst
@@ -9,6 +9,7 @@ Peripherals API
:SOC_ADC_SUPPORTED: adc/index
:SOC_ANA_CMPR_SUPPORTED: ana_cmpr
:SOC_GDMA_SUPPORT_CRC: async_crc
+ :SOC_DMA2D_SUPPORTED: async_color_convert
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
:SOC_BITSCRAMBLER_SUPPORTED: bitscrambler
:SOC_MIPI_CSI_SUPPORTED: camera_driver
diff --git a/docs/zh_CN/api-reference/peripherals/async_color_convert.rst b/docs/zh_CN/api-reference/peripherals/async_color_convert.rst
new file mode 100644
index 00000000000..21041f6b634
--- /dev/null
+++ b/docs/zh_CN/api-reference/peripherals/async_color_convert.rst
@@ -0,0 +1,295 @@
+================
+异步色彩格式转换
+================
+
+:link_to_translation:`en:[English]`
+
+本文介绍 ESP-IDF 中的异步色彩转换驱动。目录如下:
+
+.. contents::
+ :local:
+ :depth: 2
+
+概述
+====
+
+{IDF_TARGET_NAME} 提供 DMA2D 引擎,可以把 2D 拷贝和色彩转换工作从 CPU 卸载到硬件执行。
+
+这个驱动适合用于:
+
+- 将图像从一种像素格式转换为另一种像素格式
+- 只转换大图中的一个矩形窗口
+- 将多个转换请求排队,而不是让 CPU 自己做像素搬运
+- 在 RGB 和 UYVY 格式之间转换,并选择 RGB/YUV 转换标准
+
+异步色彩转换驱动对 DMA2D 的请求准备、队列管理和完成通知做了封装,同时提供两种使用方式:
+
+- 带 ISR 回调通知的异步提交接口
+- 基于同一路径实现、对新手更友好的阻塞接口
+
+快速开始
+========
+
+如果你是第一次使用这个驱动,建议从最简单的流程开始:
+
+1. 安装驱动
+2. 准备一个 :cpp:type:`async_color_convert_request_t`
+3. 通过阻塞或非阻塞 API 发起转换
+4. 在转换完成后使用输出 buffer
+5. 继续提交新请求,或在结束时卸载驱动
+
+典型使用流程如下:
+
+.. mermaid::
+
+ flowchart TD
+ install["安装驱动
esp_async_color_convert_install_dma2d"] --> request["准备请求
async_color_convert_request_t"]
+ request --> blocking["阻塞路径
esp_color_convert_blocking"]
+ request --> nonBlocking["非阻塞路径
esp_async_color_convert"]
+ nonBlocking --> callback["等待回调或任务通知"]
+ blocking --> result["使用转换结果 buffer"]
+ callback --> result
+ result --> request
+ result --> uninstall["可选清理
esp_async_color_convert_uninstall"]
+
+场景 1:先从一次阻塞转换开始
+============================
+
+理解这个驱动的最简单方式,就是先完成一次转换,并在函数返回时直接拿到结果。
+
+下面的流程与 :example:`peripherals/dma/async_color_convert` 示例一致。它把一个嵌入在 flash 中的 UYVY422 图像转换为 BGR24,然后由应用继续处理转换后的输出:
+
+.. code:: c
+
+ async_color_convert_handle_t conv_hdl = NULL; // 安装驱动后返回的句柄,后续 API 都要用到它
+ async_color_convert_config_t config = {
+ .backlog = 1, // 这个阻塞示例一次只处理一个请求,因此 1 就够了
+ .dma_burst_size = 16, // 先使用示例里的默认 burst 大小即可
+ };
+ // 创建一个基于 DMA2D 后端的异步色彩转换驱动实例。
+ ESP_ERROR_CHECK(esp_async_color_convert_install_dma2d(&config, &conv_hdl));
+
+ async_color_convert_request_t req = {
+ .src_buffer = sample_96x64_uyvy_yuv_start, // 源图像可以在 flash 或者 RAM 中,只要 DMA 可访问即可
+ .src_stride = 96, // 源图像的行跨度,单位是像素
+ .src_height = 64, // 源图像高度,单位是像素
+ .src_x = 0, // 从源图像左上角开始取窗口
+ .src_y = 0,
+ .dst_buffer = dst_bgr, // 目标 buffer 位于 DMA 可访问的 RAM 中
+ .dst_stride = 96, // 目标图像的行跨度,单位是像素
+ .dst_height = 64, // 目标图像高度,单位是像素
+ .dst_x = 0, // 从目标图像左上角开始写入结果
+ .dst_y = 0,
+ .copy_width = 96, // 转换整张图的宽度,单位是像素
+ .copy_height = 64, // 转换整张图的高度,单位是像素
+ .src_color_format = ESP_COLOR_FOURCC_UYVY, // 源像素格式为 UYVY422
+ .dst_color_format = ESP_COLOR_FOURCC_BGR24, // 目标像素格式为 BGR24(本驱动里用它表示 RGB888)
+ .color_conv_std = COLOR_CONV_STD_RGB_YUV_BT601, // 该 RGB/YUV 转换使用的标准
+ };
+
+ // 阻塞等待 DMA2D 完成转换。-1 表示一直等到完成为止。
+ ESP_ERROR_CHECK(esp_color_convert_blocking(conv_hdl, &req, -1));
+
+ // 所有转换结束后,释放驱动资源。
+ ESP_ERROR_CHECK(esp_async_color_convert_uninstall(conv_hdl));
+
+这个流程里最重要的概念有:
+
+- :cpp:func:`esp_async_color_convert_install_dma2d` 创建驱动实例
+- :cpp:type:`async_color_convert_request_t` 描述源图像、目标图像以及要转换的窗口
+- :cpp:func:`esp_color_convert_blocking` 会一直等待,直到硬件完成转换
+- :cpp:func:`esp_async_color_convert_uninstall` 释放驱动资源
+
+对于阻塞 API,``timeout_ms = -1`` 表示永久等待。其他 timeout 值目前不支持,会返回 ``ESP_ERR_INVALID_ARG``。
+
+理解 ``async_color_convert_request_t``
+--------------------------------------
+
+这个驱动最容易出错的地方,通常不是安装驱动,而是请求参数填写不正确,因此理解 :cpp:type:`async_color_convert_request_t` 很重要。
+
+.. important::
+
+ 在 :cpp:type:`async_color_convert_request_t` 中,所有几何相关字段的单位都是 **像素**,不是字节。包括 ``src_stride``、``src_height``、``src_x``、``src_y``、``dst_stride``、``dst_height``、``dst_x``、``dst_y``、``copy_width`` 和 ``copy_height``。
+
+ ``src_stride`` 和 ``dst_stride`` 表示的是每一整行在内存中跨越多少像素,也就是行跨度,不是本次转换窗口的宽度。当你只转换大图中的一个窗口时,它们可以大于 ``copy_width``。
+
+这个结构体同时描述了两件事:
+
+- 源图像和目标图像在内存中的完整布局
+- 本次实际要转换的矩形窗口
+
+关键字段含义如下:
+
+- :cpp:member:`async_color_convert_request_t::src_buffer`
+ 源图像基地址
+- :cpp:member:`async_color_convert_request_t::src_stride`
+ 源图像的行跨度,单位为像素
+- :cpp:member:`async_color_convert_request_t::src_height`
+ 源图像高度,单位为像素
+- :cpp:member:`async_color_convert_request_t::src_x` 和 :cpp:member:`async_color_convert_request_t::src_y`
+ 源窗口左上角坐标
+- :cpp:member:`async_color_convert_request_t::dst_buffer`
+ 目标图像基地址
+- :cpp:member:`async_color_convert_request_t::dst_stride`
+ 目标图像的行跨度,单位为像素
+- :cpp:member:`async_color_convert_request_t::dst_height`
+ 目标图像高度,单位为像素
+- :cpp:member:`async_color_convert_request_t::dst_x` 和 :cpp:member:`async_color_convert_request_t::dst_y`
+ 转换结果写入目标图像时的左上角坐标
+- :cpp:member:`async_color_convert_request_t::copy_width` 和 :cpp:member:`async_color_convert_request_t::copy_height`
+ 本次要转换的矩形窗口尺寸
+- :cpp:member:`async_color_convert_request_t::src_color_format` 和 :cpp:member:`async_color_convert_request_t::dst_color_format`
+ 源和目标像素格式
+- :cpp:member:`async_color_convert_request_t::color_conv_std`
+ RGB/YUV 转换标准,用于 RGB 和 YUV 之间的转换
+
+源窗口和目标窗口都必须完整落在各自图像的边界之内。
+
+支持的转换格式
+--------------
+
+本驱动支持以下格式组合:
+
+.. list-table::
+ :header-rows: 1
+
+ * - 源格式
+ - 目标格式
+ - 转换标准
+ * - 与目标格式相同(跳过转换)
+ - 与源格式相同(跳过转换)
+ - 不适用
+ * - RGB565
+ - RGB888
+ - 不适用
+ * - RGB888
+ - RGB565
+ - 不适用
+ * - RGB888
+ - UYVY422
+ - BT.601
+ * - RGB888
+ - UYVY422
+ - BT.709
+ * - UYVY422
+ - RGB888
+ - BT.601
+ * - UYVY422
+ - RGB888
+ - BT.709
+
+.. note::
+
+ 在本驱动中,RGB888 使用 ``ESP_COLOR_FOURCC_BGR24``,UYVY422 使用 ``ESP_COLOR_FOURCC_UYVY``。
+
+ 所有请求都需要设置 :cpp:member:`async_color_convert_request_t::src_color_format` 和
+ :cpp:member:`async_color_convert_request_t::dst_color_format`。
+ 当在 RGB 和 YUV 之间转换时,还需要设置 :cpp:member:`async_color_convert_request_t::color_conv_std`。
+
+场景 2:使用异步接口和回调函数
+==============================
+
+理解了阻塞流程之后,下一步就是把请求排入队列,并在硬件完成后由中断上下文中的回调通知你。
+
+.. code:: c
+
+ static bool color_conv_done_cb(async_color_convert_handle_t conv_hdl,
+ async_color_convert_event_data_t *edata,
+ void *cb_args)
+ {
+ BaseType_t high_task_wakeup = pdFALSE; // FreeRTOS 在 ISR 中唤醒任务时需要这个变量
+ SemaphoreHandle_t sem = (SemaphoreHandle_t)cb_args; // 提交请求时传进来的用户上下文
+ // 用 ISR-safe 的方式通知等待中的任务:这次转换已经完成。
+ xSemaphoreGiveFromISR(sem, &high_task_wakeup);
+ // 如果刚才唤醒了更高优先级任务,就请求在 ISR 退出后立刻切换过去。
+ return high_task_wakeup == pdTRUE;
+ }
+
+ async_color_convert_request_t req = {
+ .src_buffer = src_buf, // 源图像基地址
+ .src_stride = src_width, // 源图像的行跨度,单位是像素
+ .src_height = src_height,
+ .src_x = 0,
+ .src_y = 0,
+ .dst_buffer = dst_buf, // 目标图像基地址
+ .dst_stride = dst_width, // 目标图像的行跨度,单位是像素
+ .dst_height = dst_height,
+ .dst_x = 0,
+ .dst_y = 0,
+ .copy_width = copy_width,
+ .copy_height = copy_height,
+ .src_color_format = ESP_COLOR_FOURCC_RGB16,
+ .dst_color_format = ESP_COLOR_FOURCC_BGR24,
+ };
+
+ // 提交一个异步请求。函数返回时,硬件可能还在执行转换。
+ ESP_ERROR_CHECK(esp_async_color_convert(conv_hdl, &req, color_conv_done_cb, sem));
+ // 在任务上下文中等待回调释放信号量。
+ xSemaphoreTake(sem, portMAX_DELAY);
+
+回调运行在 ISR 上下文中,因此应尽量保持简短,并且只调用 ISR-safe API,例如 ``xSemaphoreGiveFromISR`` 或 ``xQueueSendFromISR``。
+
+运行注意事项
+============
+
+驱动配置
+--------
+
+驱动配置字段如下:
+
+- :cpp:member:`async_color_convert_config_t::backlog`
+ 最大待处理请求数。``0`` 表示使用驱动默认值。
+- :cpp:member:`async_color_convert_config_t::dma_burst_size`
+ DMA burst 大小,单位为字节。``0`` 表示使用驱动默认值。
+- :cpp:member:`async_color_convert_config_t::intr_priority`
+ DMA2D 中断优先级。``0`` 表示使用默认低/中优先级。
+
+DMA 突发大小
+------------
+
+``dma_burst_size`` 会影响 DMA 传输效率:
+
+- 较大的突发大小可能提高吞吐量
+- 较大的突发大小也可能增加总线占用,因此并不一定适合所有工作负载
+- 常见的起始取值有 16、32 和 64 字节
+
+最佳取值取决于芯片的 DMA 控制器能力,以及系统中其他活跃组件对内存带宽的共享情况。
+
+线程安全与 ISR 规则
+-------------------
+
+- 驱动是线程安全的。不同任务提交的请求会通过内部队列串行化。
+- :cpp:func:`esp_async_color_convert` 可以在任务上下文中调用,用于排队请求。
+- 回调类型 :cpp:type:`async_color_convert_isr_cb_t` 运行在 ISR 上下文中。
+- 不要在回调里调用阻塞 API。
+- :cpp:func:`esp_color_convert_blocking` 不能在 ISR 上下文中调用。
+
+卸载驱动
+--------
+
+当驱动不再需要时:
+
+.. code:: c
+
+ // 只有在所有排队请求都完成后,才能安全卸载驱动。
+ ESP_ERROR_CHECK(esp_async_color_convert_uninstall(conv_hdl));
+
+如果仍有请求未完成,:cpp:func:`esp_async_color_convert_uninstall` 会返回 :c:macro:`ESP_ERR_INVALID_STATE`。
+
+应用示例
+========
+
+- :example:`peripherals/dma/async_color_convert` 展示了一个面向初学者的阻塞转换流程:
+
+ - 从映射到 flash 的嵌入式 ``.yuv`` 图像直接读取输入
+ - 使用 DMA2D 将图像从 UYVY422 转换为 BGR24
+ - 将转换结果做 base64 编码后输出到控制台
+ - 由 pytest 重建为 PNG 工件,并与 golden 参考图进行比对
+
+API 参考
+========
+
+异步颜色转换驱动程序函数
+------------------------
+
+.. include-build-file:: inc/esp_async_color_convert.inc
diff --git a/docs/zh_CN/api-reference/peripherals/async_crc.rst b/docs/zh_CN/api-reference/peripherals/async_crc.rst
index b257d027d9c..79f42f44c60 100644
--- a/docs/zh_CN/api-reference/peripherals/async_crc.rst
+++ b/docs/zh_CN/api-reference/peripherals/async_crc.rst
@@ -1,6 +1,6 @@
-====================
-异步 CRC (Async CRC)
-====================
+=============
+异步 CRC 计算
+=============
:link_to_translation:`en:[English]`
diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst
index ba506840eed..e0de40dd7c1 100644
--- a/docs/zh_CN/api-reference/peripherals/index.rst
+++ b/docs/zh_CN/api-reference/peripherals/index.rst
@@ -9,6 +9,7 @@
:SOC_ADC_SUPPORTED: adc/index
:SOC_ANA_CMPR_SUPPORTED: ana_cmpr
:SOC_GDMA_SUPPORT_CRC: async_crc
+ :SOC_DMA2D_SUPPORTED: async_color_convert
:SOC_ASYNC_MEMCPY_SUPPORTED: async_memcpy
:SOC_BITSCRAMBLER_SUPPORTED: bitscrambler
:SOC_MIPI_CSI_SUPPORTED: camera_driver