From 5f34fdc278ff0a75d35d9a95143619ed5823aa43 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 8 Dec 2025 15:32:09 +0800 Subject: [PATCH] fix(isp): Added subwindow configuration for AWB --- .../esp_driver_isp/include/driver/isp_awb.h | 8 +++- components/esp_driver_isp/src/isp_awb.c | 47 ++++++++++++++++++- components/hal/esp32p4/include/hal/isp_ll.h | 22 +++++++++ components/hal/include/hal/isp_hal.h | 13 ++++- components/hal/isp_hal.c | 20 +++++++- 5 files changed, 106 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_isp/include/driver/isp_awb.h b/components/esp_driver_isp/include/driver/isp_awb.h index 4cd508cd10..070c3390e5 100644 --- a/components/esp_driver_isp/include/driver/isp_awb.h +++ b/components/esp_driver_isp/include/driver/isp_awb.h @@ -27,12 +27,18 @@ typedef struct { * If your camera doesn't support the manual gain or don't want to change the camera configuration, * then you can choose to sample after CCM, and set the calculated gain to the CCM */ - isp_window_t window; /*!< Statistic window of AWB. + isp_window_t window; /*!< Statistic main window of AWB. * Suggest to set it at the middle of the image and a little smaller than the whole image. * It will be more reliable because the edges of image are easily to be overexposure, * the overexposure pixels are almost at maximum luminance, * which are not good references to calculate the gain for white balance. */ + isp_window_t subwindow; /*!< Statistic subwindow of AWB. + * Need to be set no greater than the main window. + * It will be evenly divided into a grid of ISP_AWB_WINDOW_X_NUM * ISP_AWB_WINDOW_Y_NUM blocks. + * The blocks share the same restrictions in R/G, B/G and luminance range as the main window. + * The statistics result of each block will be returned in the `isp_awb_stat_result_t::subwin_result` field. + */ struct { isp_u32_range_t luminance; /*!< Luminance range of the white patch. Range [0, 255 * 3] * Not suggest to set the max value to 255 * 3, diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index d4b201ba81..f9c3bb08c9 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -14,6 +14,7 @@ #include "esp_heap_caps.h" #include "driver/isp_awb.h" #include "esp_private/isp_private.h" +#include "hal/efuse_hal.h" typedef struct isp_awb_controller_t { _Atomic isp_fsm_t fsm; @@ -71,14 +72,58 @@ static esp_err_t s_esp_isp_awb_config_hardware(isp_proc_handle_t isp_proc, const { isp_ll_awb_set_sample_point(isp_proc->hal.hw, awb_cfg->sample_point); ESP_RETURN_ON_FALSE(isp_hal_awb_set_window_range(&isp_proc->hal, &awb_cfg->window), - ESP_ERR_INVALID_ARG, TAG, "invalid window"); + ESP_ERR_INVALID_ARG, TAG, "invalid window range"); + + // Subwindow feature is only supported on REV >= 3.0 + if (efuse_hal_chip_revision() < 300) { + bool subwindow_is_zero = awb_cfg->subwindow.top_left.x == 0 && + awb_cfg->subwindow.top_left.y == 0 && + awb_cfg->subwindow.btm_right.x == 0 && + awb_cfg->subwindow.btm_right.y == 0; + if (!subwindow_is_zero) { + ESP_LOGW(TAG, "Subwindow feature is not supported on REV < 3.0, subwindow will not be configured"); + } + } + + isp_window_t subwindow = awb_cfg->subwindow; + ESP_RETURN_ON_FALSE( + (subwindow.top_left.x >= awb_cfg->window.top_left.x) && + (subwindow.top_left.y >= awb_cfg->window.top_left.y) && + (subwindow.btm_right.x <= awb_cfg->window.btm_right.x) && + (subwindow.btm_right.y <= awb_cfg->window.btm_right.y), + ESP_ERR_INVALID_ARG, TAG, "subwindow exceeds window range" + ); + + if ((subwindow.btm_right.x - subwindow.top_left.x + 1) / ISP_AWB_WINDOW_X_NUM < 4 || + (subwindow.btm_right.y - subwindow.top_left.y + 1) / ISP_AWB_WINDOW_Y_NUM < 4) { + ESP_LOGE(TAG, "subwindow block size is too small: width and height must be at least 4 (got %d x %d)", + (subwindow.btm_right.x - subwindow.top_left.x + 1) / ISP_AWB_WINDOW_X_NUM, + (subwindow.btm_right.y - subwindow.top_left.y + 1) / ISP_AWB_WINDOW_Y_NUM); + return ESP_ERR_INVALID_ARG; + } + + int size_x = subwindow.btm_right.x - subwindow.top_left.x + 1; + int size_y = subwindow.btm_right.y - subwindow.top_left.y + 1; + if ((size_x % ISP_AWB_WINDOW_X_NUM != 0) || (size_y % ISP_AWB_WINDOW_Y_NUM != 0)) { + ESP_LOGW(TAG, "subwindow size (%d x %d) is not divisible by AWB subwindow blocks grid (%d x %d). \ + Resolution will be floored to the nearest divisible value.", + size_x, size_y, ISP_AWB_WINDOW_X_NUM, ISP_AWB_WINDOW_Y_NUM); + // floor to the nearest divisible value + subwindow.btm_right.x -= size_x % ISP_AWB_WINDOW_X_NUM; + subwindow.btm_right.y -= size_y % ISP_AWB_WINDOW_Y_NUM; + } + ESP_RETURN_ON_FALSE(isp_hal_awb_set_subwindow_range(&isp_proc->hal, &subwindow), + ESP_ERR_INVALID_ARG, TAG, "invalid subwindow range"); + isp_u32_range_t lum_range = awb_cfg->white_patch.luminance; ESP_RETURN_ON_FALSE(isp_hal_awb_set_luminance_range(&isp_proc->hal, lum_range.min, lum_range.max), ESP_ERR_INVALID_ARG, TAG, "invalid luminance range"); + isp_float_range_t rg_range = awb_cfg->white_patch.red_green_ratio; ESP_RETURN_ON_FALSE(rg_range.min < rg_range.max && rg_range.min >= 0 && isp_hal_awb_set_rg_ratio_range(&isp_proc->hal, rg_range.min, rg_range.max), ESP_ERR_INVALID_ARG, TAG, "invalid range of Red Green ratio"); + isp_float_range_t bg_range = awb_cfg->white_patch.blue_green_ratio; ESP_RETURN_ON_FALSE(bg_range.min < bg_range.max && bg_range.min >= 0 && isp_hal_awb_set_bg_ratio_range(&isp_proc->hal, bg_range.min, bg_range.max), diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index f98f6a2ceb..7657c470c7 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -2499,6 +2499,23 @@ static inline void isp_ll_hist_set_rgb_coefficient(isp_dev_t *hw, const isp_hist ---------------------------------------------------------------*/ #if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +/** + * @brief Set AWB subwindow range + * + * @param[in] hw Hardware instance address + * @param[in] top_left_x Top left pixel x axis value + * @param[in] top_left_y Top left pixel y axis value + * @param[in] sub_window_xsize Subwindow x size (minimum 4) + * @param[in] sub_window_ysize Subwindow y size (minimum 4) + */ +static inline void isp_ll_awb_set_subwindow_range(isp_dev_t *hw, uint32_t top_left_x, uint32_t top_left_y, uint32_t sub_window_xsize, uint32_t sub_window_ysize) +{ + hw->awb_bx.awb_x_start = top_left_x; + hw->awb_bx.awb_x_bsize = sub_window_xsize; + hw->awb_by.awb_y_start = top_left_y; + hw->awb_by.awb_y_bsize = sub_window_ysize; +} + /** * @brief Set crop clock control mode * @@ -2581,6 +2598,11 @@ static inline void isp_ll_crop_clear_error(isp_dev_t *hw) } #else +static inline void isp_ll_awb_set_subwindow_range(isp_dev_t *hw, uint32_t top_left_x, uint32_t top_left_y, uint32_t sub_window_xsize, uint32_t sub_window_ysize) +{ + // for compatibility +} + static inline void isp_ll_crop_set_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode) { // for compatibility diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index 104e5f71db..df5301ceda 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -132,6 +132,17 @@ void isp_hal_ae_window_config(isp_hal_context_t *hal, const isp_window_t *window */ bool isp_hal_awb_set_window_range(isp_hal_context_t *hal, const isp_window_t *win); +/** + * @brief Set the subwindow range of the AWB + * + * @param[in] hal Context of the HAL layer + * @param[in] win Pointer to the subwindow of the AWB + * @return + * - true Set success + * - false Invalid arg + */ +bool isp_hal_awb_set_subwindow_range(isp_hal_context_t *hal, const isp_window_t *win); + /** * @brief Set the luminance range of the white patch * diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index e4952ae610..a6d5cdf2c9 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -66,6 +66,24 @@ bool isp_hal_awb_set_window_range(isp_hal_context_t *hal, const isp_window_t *wi return true; } +bool isp_hal_awb_set_subwindow_range(isp_hal_context_t *hal, const isp_window_t *win) +{ + if (win->top_left.x > win->btm_right.x || + win->top_left.y > win->btm_right.y || + win->btm_right.x > ISP_LL_AWB_WINDOW_MAX_RANGE || + win->btm_right.y > ISP_LL_AWB_WINDOW_MAX_RANGE) { + return false; + } + isp_ll_awb_set_subwindow_range( + hal->hw, + win->top_left.x, + win->top_left.y, + (win->btm_right.x - win->top_left.x) / SOC_ISP_AWB_WINDOW_X_NUMS, + (win->btm_right.y - win->top_left.y) / SOC_ISP_AWB_WINDOW_Y_NUMS + ); + return true; +} + bool isp_hal_awb_set_luminance_range(isp_hal_context_t *hal, uint32_t lum_min, uint32_t lum_max) { if (lum_min > lum_max || lum_max > ISP_LL_AWB_LUM_MAX_RANGE) {