Merge branch 'fix/awb_subwindow_v6.0' into 'release/v6.0'

fix(isp): Added subwindow configuration for AWB (v6.0)

See merge request espressif/esp-idf!44218
This commit is contained in:
morris
2025-12-17 09:46:42 +08:00
5 changed files with 106 additions and 4 deletions

View File

@@ -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,

View File

@@ -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),

View File

@@ -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

View File

@@ -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
*

View File

@@ -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) {