From ca3ff9aced2b4e58ce69718d014228e01069c196 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 17 Oct 2025 19:10:48 +0800 Subject: [PATCH 1/4] docs(ppa): add a note about bilinear scaling algorithm in PPA SRM Closes https://github.com/espressif/esp-idf/issues/17531 --- docs/en/api-reference/peripherals/ppa.rst | 4 ++++ docs/zh_CN/api-reference/peripherals/ppa.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst index 74998a03b2..3a6f64fe55 100644 --- a/docs/en/api-reference/peripherals/ppa.rst +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -93,6 +93,10 @@ Some notes to avoid confusion in configuring :cpp:type:`ppa_srm_oper_config_t`: - Output block's width/height is totally determined by the input block's width/height, scaling factor, and rotation angle, so output block's width/height does not need to be configured. However, please make sure the output block can fit at the offset location in the output picture. - If the color mode of the input or output picture is ``PPA_SRM_COLOR_MODE_YUV420``, then its ``pic_w``, ``pic_h``, ``block_w``, ``block_h``, ``block_offset_x``, ``block_offset_y`` fields must be even. +.. note:: + + The PPA SRM internally uses bilinear scaling algorithm to process. Therefore, it may cause chromatic aberration and loss of contrast at the edges in a scaled picture. + Blend ~~~~~ diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst index 053908b71a..c9b4841413 100644 --- a/docs/zh_CN/api-reference/peripherals/ppa.rst +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -93,6 +93,10 @@ PPA 操作包括: - 输出块的宽度/高度完全由输入块的宽度/高度、缩放因子和旋转角度决定,因此无需配置输出块的宽度/高度。但请确保输出块可以适应输出图片中的偏移位置。 - 如果输入或输出图片的色彩模式为 ``PPA_SRM_COLOR_MODE_YUV420``,那么其 ``pic_w``、``pic_h``、``block_w``、``block_h``、``block_offset_x`` 以及 ``block_offset_y`` 字段必须为偶数。 +.. note:: + + PPA SRM 内部使用双线性缩放算法进行处理。因此,缩放后的图片边缘可能会出现色差和对比度损失。 + 叠加 ~~~~ From 507bea72e7b1b188885e3ba752d1546cccc74a7b Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 20 Oct 2025 16:58:21 +0800 Subject: [PATCH 2/4] fix(ppa): YUV444 cannot be a PPA SRM output color mode --- components/esp_driver_ppa/src/ppa_srm.c | 14 +++----------- components/hal/esp32p4/include/hal/ppa_ll.h | 2 +- components/hal/include/hal/ppa_types.h | 5 ++--- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index fd30be80e7..2b6c834e98 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -114,13 +114,6 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel } ppa_srm_color_mode_t ppa_out_color_mode = srm_trans_desc->out.srm_cm; - if (ppa_out_color_mode == PPA_SRM_COLOR_MODE_YUV444) { - ppa_out_color_mode = PPA_SRM_COLOR_MODE_YUV420; - dma2d_csc_config_t dma_rx_csc = { - .rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444, - }; - dma2d_configure_color_space_conversion(dma2d_rx_chan, &dma_rx_csc); - } // Configure the block size to be received by the SRM engine, which is passed from the 2D-DMA TX channel (i.e. 2D-DMA dscr-port mode) uint32_t block_h = 0, block_v = 0; @@ -179,7 +172,9 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); - ESP_RETURN_ON_FALSE(ppa_ll_srm_is_color_mode_supported(config->in.srm_cm) && ppa_ll_srm_is_color_mode_supported(config->out.srm_cm), ESP_ERR_INVALID_ARG, TAG, "unsupported color mode"); + ESP_RETURN_ON_FALSE(ppa_ll_srm_is_color_mode_supported(config->in.srm_cm) && + (ppa_ll_srm_is_color_mode_supported(config->out.srm_cm) && config->out.srm_cm != PPA_SRM_COLOR_MODE_YUV444), + ESP_ERR_INVALID_ARG, TAG, "unsupported color mode"); // For YUV420 input/output: in desc, ha/hb/va/vb/x/y must be even number // For YUV422 input/output: in desc, ha/hb/x must be even number if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV420) { @@ -290,9 +285,6 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC; } - if (config->out.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { - dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_RX_CSC; - } dma_trans_desc->specified_tx_channel_mask = 0; dma_trans_desc->specified_rx_channel_mask = 0; diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index a0e7323397..60159b65c7 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -244,7 +244,7 @@ static inline bool ppa_ll_srm_is_color_mode_supported(ppa_srm_color_mode_t color case PPA_SRM_COLOR_MODE_RGB888: case PPA_SRM_COLOR_MODE_RGB565: case PPA_SRM_COLOR_MODE_YUV420: - case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before/after PPA + case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before PPA, and not supported as output color mode #if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: diff --git a/components/hal/include/hal/ppa_types.h b/components/hal/include/hal/ppa_types.h index 6f99322255..0120556ce3 100644 --- a/components/hal/include/hal/ppa_types.h +++ b/components/hal/include/hal/ppa_types.h @@ -40,10 +40,9 @@ typedef enum { PPA_SRM_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA SRM color mode: RGB888 */ PPA_SRM_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA SRM color mode: RGB565 */ PPA_SRM_COLOR_MODE_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), /*!< PPA SRM color mode: YUV420 */ - PPA_SRM_COLOR_MODE_YUV444 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV444), /*!< PPA SRM color mode: YUV444 (limited range only)*/ - // YUV444 not supported by PPA hardware, but we can use 2D-DMA to do conversion before sending into and after coming out from the PPA module + PPA_SRM_COLOR_MODE_YUV444 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV444), /*!< PPA SRM color mode: YUV444 (limited range only and can only be the input color mode)*/ + // YUV444 not supported by PPA hardware, but we can use 2D-DMA to do conversion before sending into the PPA module // If in_pic is YUV444, then TX DMA channel could do DMA2D_CSC_TX_YUV444_TO_RGB888_601/709, so PPA in_color_mode is RGB888 - // If out_pic is YUV444, then RX DMA channel could do DMA2D_CSC_RX_YUV420_TO_YUV444, so PPA out_color_mode is YUV420 PPA_SRM_COLOR_MODE_YUV422_UYVY = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_UYVY422), /*!< PPA SRM color mode: YUV422 */ PPA_SRM_COLOR_MODE_YUV422_VYUY = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_VYUY422), /*!< PPA SRM color mode: YUV422, only available on input */ PPA_SRM_COLOR_MODE_YUV422_YUYV = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUYV422), /*!< PPA SRM color mode: YUV422, only available on input */ From 1b13ef0498328d02cde60c8e69c1bf1b6736ca36 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 20 Oct 2025 17:39:17 +0800 Subject: [PATCH 3/4] fix(ppa): fix potential SRM operation stuck on DMA issue Apply a workaound to bypass macro block order function in PPA SRM when specific conditions are met to avoid SRM operation getting stuck --- components/esp_driver_ppa/src/ppa_srm.c | 22 +++++ .../esp_driver_ppa/test_apps/main/test_ppa.c | 84 +++++++++++++++++++ components/hal/esp32p4/include/hal/ppa_ll.h | 11 +++ 3 files changed, 117 insertions(+) diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 2b6c834e98..c35a736bf3 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -156,6 +156,28 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel ppa_ll_srm_enable_mirror_x(platform->hal.dev, srm_trans_desc->mirror_x); ppa_ll_srm_enable_mirror_y(platform->hal.dev, srm_trans_desc->mirror_y); + // Hardware bug workaround (DIG-734) + uint32_t w_out = srm_trans_desc->in.block_w * srm_trans_desc->scale_x_int + srm_trans_desc->in.block_w * srm_trans_desc->scale_x_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + uint32_t w_divisor = (ppa_out_color_mode == PPA_SRM_COLOR_MODE_ARGB8888 || ppa_out_color_mode == PPA_SRM_COLOR_MODE_RGB888) ? 32 : 64; + uint32_t w_left = w_out % w_divisor; + w_left = (w_left == 0) ? w_divisor : w_left; + uint32_t h_mb = (ppa_ll_srm_get_mb_size(platform->hal.dev) == PPA_LL_SRM_MB_SIZE_16_16) ? 16 : 32; + uint32_t h_in_left = srm_trans_desc->in.block_h % h_mb; + h_in_left = (h_in_left == 0) ? h_mb : h_in_left; + uint32_t h_left = h_in_left * srm_trans_desc->scale_y_int + h_in_left * srm_trans_desc->scale_y_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + const uint32_t dma2d_fifo_depth_bits = 12 * 128; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = ppa_out_color_mode, + }; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); + bool bypass_mb_order = false; + if (((w_out > w_divisor) || (srm_trans_desc->in.block_h > h_mb)) && // will be cut into more than one trans unit + ((w_left * h_left * out_pixel_depth) < dma2d_fifo_depth_bits) + ) { + bypass_mb_order = true; + } + ppa_ll_srm_bypass_mb_order(platform->hal.dev, bypass_mb_order); + ppa_ll_srm_start(platform->hal.dev); // No need to yield diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c index 011add8c2e..8684e6ee15 100644 --- a/components/esp_driver_ppa/test_apps/main/test_ppa.c +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -18,6 +18,7 @@ #include "hal/color_hal.h" #include "esp_cache.h" #include "ppa_performance.h" +#include "esp_random.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -837,3 +838,86 @@ TEST_CASE("ppa_fill_performance", "[PPA]") free(out_buf); } + +TEST_CASE("ppa_srm_stress_test", "[PPA]") +{ + // Configurable parameters + const uint32_t w = 200; + const uint32_t h = 200; + const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0; + const float scale_x = 1.0; + const float scale_y = 1.0; + + color_space_pixel_format_t in_pixel_format = { + .color_type_id = in_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8; + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(out_buf); + uint8_t *in_buf = heap_caps_aligned_calloc(4, in_buf_size, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(in_buf); + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + // Test on different sizes of the block + int test_iterations = 50; + while (test_iterations-- > 0) { + uint32_t block_w_initial = esp_random() % (w - 100); + uint32_t block_h_initial = esp_random() % (h - 100); + block_w_initial = (block_w_initial == 0) ? 1 : block_w_initial; + block_h_initial = (block_h_initial == 0) ? 1 : block_h_initial; + uint32_t block_w = 0; + uint32_t block_h = 0; + for (int i = 0; i < 100; i++) { + block_w = block_w_initial + i; + block_h = block_h_initial + i; + // printf("block_w = %ld, block_h = %ld\n", block_w, block_h); + ppa_srm_oper_config_t oper_config = { + .in.buffer = in_buf, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = block_w, + .in.block_h = block_h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = in_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = block_w, + .out.pic_h = block_h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = out_cm, + + .rotation_angle = rotation, + .scale_x = scale_x, + .scale_y = scale_y, + + .rgb_swap = 0, + .byte_swap = 0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); + } + } + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(in_buf); + free(out_buf); +} diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index 60159b65c7..cf4e5786d5 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -600,6 +600,17 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, } } +/** + * @brief Whether to bypass the macro block order function in PPA SRM + * + * @param dev Peripheral instance address + * @param enable True to bypass; False to not bypass + */ +static inline void ppa_ll_srm_bypass_mb_order(ppa_dev_t *dev, bool enable) +{ + dev->sr_byte_order.sr_macro_bk_ro_bypass = enable; +} + //////////////////////////////////// Blending //////////////////////////////////////// /* * Alpha Blending Calculation: From d6fbe418c6886bc4c7f0c25aaad85793c5081d03 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 17 Dec 2025 21:31:05 +0800 Subject: [PATCH 4/4] fix(ppa): fix SRM YUV422/420 incorrect DMA descriptor port mode block size --- components/hal/esp32p4/include/hal/ppa_ll.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index cf4e5786d5..a299531151 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -550,14 +550,14 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, break; case PPA_SRM_COLOR_MODE_YUV420: *block_h = 20; - *block_v = 18; + *block_v = 20; break; case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: case PPA_SRM_COLOR_MODE_YUV422_YUYV: case PPA_SRM_COLOR_MODE_YUV422_YVYU: *block_h = 20; - *block_v = 20; + *block_v = 18; break; default: // Unsupported SRM input color mode @@ -577,14 +577,14 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, break; case PPA_SRM_COLOR_MODE_YUV420: *block_h = 36; - *block_v = 34; + *block_v = 36; break; case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: case PPA_SRM_COLOR_MODE_YUV422_YUYV: case PPA_SRM_COLOR_MODE_YUV422_YVYU: *block_h = 36; - *block_v = 36; + *block_v = 34; break; default: // Unsupported SRM input color mode