Merge branch 'fix/fix_awb_subwindow_config_v5.4' into 'release/v5.4'

isp: fixed awb subwindow config always need to be set issue (v5.4)

See merge request espressif/esp-idf!44858
This commit is contained in:
morris
2026-01-08 16:02:20 +08:00
12 changed files with 147 additions and 95 deletions

View File

@@ -24,6 +24,9 @@ typedef struct {
uint8_t denoising_level; ///< BF denoising level, from 2 to 20, the bigger the better denoising performance, but the worse detailed
uint8_t padding_line_tail_valid_start_pixel; ///< BF edge padding line tail valid start pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid
uint8_t padding_line_tail_valid_end_pixel; ///< BF edge padding line tail valid end pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid
struct {
uint32_t update_once_configured : 1; ///< If set, apply configuration to hardware immediately; otherwise defer to frame boundary
} flags; ///< Driver behaviour flags
} esp_isp_bf_config_t;
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -43,10 +43,13 @@ typedef struct {
* @brief ISP BLC configurations
*/
typedef struct {
isp_window_t window; ///< The sampling windows of BLC, only pixels within the window will be sampled
esp_isp_blc_thresh_t filter_threshold; ///< Black level threshold for each channel of the raw Bayer image
bool filter_enable; ///< Enable filter for BLC, if enabled, only pixels within the threshold will be sampled
esp_isp_blc_stretch_t stretch; ///< Stretch configurations for each channel of the raw Bayer image
isp_window_t window; ///< The sampling windows of BLC, only pixels within the window will be sampled
esp_isp_blc_thresh_t filter_threshold; ///< Black level threshold for each channel of the raw Bayer image
bool filter_enable; ///< Enable filter for BLC, if enabled, only pixels within the threshold will be sampled
esp_isp_blc_stretch_t stretch; ///< Stretch configurations for each channel of the raw Bayer image
struct {
uint32_t update_once_configured : 1; ///< If set, apply configuration to hardware immediately; otherwise defer to frame boundary
} flags; ///< Driver behaviour flags
} esp_isp_blc_config_t;
/**

View File

@@ -36,6 +36,9 @@ typedef struct {
* Zero (0): Maintains the original brightness, without adjusting the image's brightness.
* Positive range (1 to 127): Increases brightness, the larger the value, the brighter the image.
*/
struct {
uint32_t update_once_configured : 1; ///< If set, apply configuration to hardware immediately; otherwise defer to frame boundary
} flags; ///< Driver behaviour flags
} esp_isp_color_config_t;
/**

View File

@@ -27,6 +27,9 @@ typedef struct {
uint8_t sharpen_template[ISP_SHARPEN_TEMPLATE_X_NUMS][ISP_SHARPEN_TEMPLATE_Y_NUMS]; ///< Sharpen template data
uint8_t padding_line_tail_valid_start_pixel; ///< Sharpen edge padding line tail valid start pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid
uint8_t padding_line_tail_valid_end_pixel; ///< Sharpen edge padding line tail valid end pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid
struct {
uint32_t update_once_configured : 1; ///< If set, apply configuration to hardware immediately; otherwise defer to frame boundary
} flags; ///< Driver behaviour flags
} esp_isp_sharpen_config_t;
/**

View File

@@ -21,7 +21,9 @@ extern "C" {
* @brief ISP BLC configurations
*/
typedef struct {
//for future proof
struct {
uint32_t update_once_configured : 1; ///< If set, apply configuration to hardware immediately; otherwise defer to frame boundary
} flags; ///< Driver behaviour flags
} esp_isp_wbg_config_t;
/**

View File

@@ -75,47 +75,49 @@ static esp_err_t s_esp_isp_awb_config_hardware(isp_proc_handle_t isp_proc, const
ESP_RETURN_ON_FALSE(isp_hal_awb_set_window_range(&isp_proc->hal, &awb_cfg->window),
ESP_ERR_INVALID_ARG, TAG, "invalid window range");
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;
// 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");
}
} else {
// Subwindow is just checked and configured on REV >= 3.0
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_is_zero) {
// Subwindow is just checked and configured on REV >= 3.0
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) {
int block_width = (int)((subwindow.btm_right.x - subwindow.top_left.x + 1) / ISP_AWB_WINDOW_X_NUM);
int block_height = (int)((subwindow.btm_right.y - subwindow.top_left.y + 1) / ISP_AWB_WINDOW_Y_NUM);
ESP_LOGE(TAG, "subwindow block size is too small: width and height must be at least 4 (got %d x %d)",
block_width, block_height);
return ESP_ERR_INVALID_ARG;
}
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) {
int block_width = (int)((subwindow.btm_right.x - subwindow.top_left.x + 1) / ISP_AWB_WINDOW_X_NUM);
int block_height = (int)((subwindow.btm_right.y - subwindow.top_left.y + 1) / ISP_AWB_WINDOW_Y_NUM);
ESP_LOGE(TAG, "subwindow block size is too small: width and height must be at least 4 (got %d x %d)",
block_width, block_height);
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;
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");
}
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;

View File

@@ -43,7 +43,7 @@ esp_err_t esp_isp_bf_configure(isp_proc_handle_t proc, const esp_isp_bf_config_t
isp_hal_bf_config(&(proc->hal), NULL);
}
bool valid = isp_ll_shadow_update_bf(proc->hal.hw);
bool valid = isp_ll_shadow_update_bf(proc->hal.hw, config->flags.update_once_configured);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update bf shadow register");
return ESP_OK;

View File

@@ -58,7 +58,7 @@ esp_err_t esp_isp_blc_configure(isp_proc_handle_t isp_proc, const esp_isp_blc_co
// Configure stretch enable for each channel
isp_ll_blc_enable_stretch(isp_proc->hal.hw, config->stretch.top_left_chan_stretch_en, config->stretch.top_right_chan_stretch_en, config->stretch.bottom_left_chan_stretch_en, config->stretch.bottom_right_chan_stretch_en);
bool valid = isp_ll_shadow_update_blc(isp_proc->hal.hw);
bool valid = isp_ll_shadow_update_blc(isp_proc->hal.hw, config->flags.update_once_configured);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update blc shadow register");
return ESP_OK;

View File

@@ -43,7 +43,7 @@ esp_err_t esp_isp_color_configure(isp_proc_handle_t proc, const esp_isp_color_co
isp_hal_color_config(&(proc->hal), NULL);
}
bool valid = isp_ll_shadow_update_color(proc->hal.hw);
bool valid = isp_ll_shadow_update_color(proc->hal.hw, config->flags.update_once_configured);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update color shadow register");
return ESP_OK;

View File

@@ -45,7 +45,7 @@ esp_err_t esp_isp_sharpen_configure(isp_proc_handle_t proc, const esp_isp_sharpe
isp_hal_sharpen_config(&(proc->hal), NULL);
}
bool valid = isp_ll_shadow_update_sharpen(proc->hal.hw);
bool valid = isp_ll_shadow_update_sharpen(proc->hal.hw, config->flags.update_once_configured);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update sharp shadow register");
return ESP_OK;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -32,11 +32,14 @@ esp_err_t esp_isp_wbg_configure(isp_proc_handle_t isp_proc, const esp_isp_wbg_co
}
#endif
ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(isp_proc && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
// Configure clock control mode
isp_ll_awb_set_wb_gain_clk_ctrl_mode(isp_proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO);
bool valid = isp_ll_shadow_update_wbg(isp_proc->hal.hw, config->flags.update_once_configured);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update wbg shadow register");
return ESP_OK;
}
@@ -61,9 +64,6 @@ esp_err_t esp_isp_wbg_set_wb_gain(isp_proc_handle_t isp_proc, isp_wbg_gain_t gai
// Set WBG gain
isp_ll_awb_set_wb_gain(isp_proc->hal.hw, gain);
bool valid = isp_ll_shadow_update_wbg(isp_proc->hal.hw);
ESP_RETURN_ON_FALSE_ISR(valid, ESP_ERR_INVALID_STATE, TAG, "failed to update wbg shadow register");
return ESP_OK;
}

View File

@@ -1867,21 +1867,27 @@ static inline void isp_ll_shadow_set_mode(isp_dev_t *hw, isp_ll_shadow_mode_t mo
/**
* @brief Update BLC shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_blc(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_blc(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.blc_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.blc_update = 1;
} else {
if (hw->shadow_reg_ctrl.blc_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.blc_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.blc_update = 1;
}
return true;
}
@@ -1889,21 +1895,27 @@ static inline bool isp_ll_shadow_update_blc(isp_dev_t *hw)
/**
* @brief Update DPC shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_dpc(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_dpc(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.dpc_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.dpc_update = 1;
} else {
if (hw->shadow_reg_ctrl.dpc_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.dpc_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.dpc_update = 1;
}
return true;
}
@@ -1911,21 +1923,27 @@ static inline bool isp_ll_shadow_update_dpc(isp_dev_t *hw)
/**
* @brief Update BF shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_bf(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_bf(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.bf_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.bf_update = 1;
} else {
if (hw->shadow_reg_ctrl.bf_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.bf_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.bf_update = 1;
}
return true;
}
@@ -1933,21 +1951,27 @@ static inline bool isp_ll_shadow_update_bf(isp_dev_t *hw)
/**
* @brief Update WBG shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_wbg(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_wbg(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.wbg_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.wbg_update = 1;
} else {
if (hw->shadow_reg_ctrl.wbg_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.wbg_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.wbg_update = 1;
}
return true;
}
@@ -1983,21 +2007,27 @@ static inline bool isp_ll_shadow_update_ccm(isp_dev_t *hw, bool force_update)
/**
* @brief Update Sharpen shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_sharpen(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_sharpen(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.sharp_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.sharp_update = 1;
} else {
if (hw->shadow_reg_ctrl.sharp_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.sharp_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.sharp_update = 1;
}
return true;
}
@@ -2005,21 +2035,27 @@ static inline bool isp_ll_shadow_update_sharpen(isp_dev_t *hw)
/**
* @brief Update Color shadow register
*
* @param[in] hw Hardware instance address
* @param[in] hw Hardware instance address
* @param[in] force_update Force update
* @return
* - True if update is successful, False otherwise
*/
static inline bool isp_ll_shadow_update_color(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_color(isp_dev_t *hw, bool force_update)
{
//only valid when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
HAL_ASSERT(hw->shadow_reg_ctrl.shadow_update_sel == ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC);
if (hw->shadow_reg_ctrl.color_update == 1) {
return false;
}
if (force_update) {
//don't care shadow register
hw->shadow_reg_ctrl.color_update = 1;
} else {
if (hw->shadow_reg_ctrl.color_update == 1) {
return false;
}
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.color_update = 1;
//self clear when ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC
hw->shadow_reg_ctrl.color_update = 1;
}
return true;
}
@@ -2030,25 +2066,25 @@ static inline void isp_ll_shadow_set_mode(isp_dev_t *hw, isp_ll_shadow_mode_t mo
//for compatibility
}
static inline bool isp_ll_shadow_update_blc(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_blc(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;
}
static inline bool isp_ll_shadow_update_dpc(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_dpc(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;
}
static inline bool isp_ll_shadow_update_bf(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_bf(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;
}
static inline bool isp_ll_shadow_update_wbg(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_wbg(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;
@@ -2060,13 +2096,13 @@ static inline bool isp_ll_shadow_update_ccm(isp_dev_t *hw, bool force_update)
return true;
}
static inline bool isp_ll_shadow_update_sharpen(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_sharpen(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;
}
static inline bool isp_ll_shadow_update_color(isp_dev_t *hw)
static inline bool isp_ll_shadow_update_color(isp_dev_t *hw, bool force_update)
{
//for compatibility
return true;