diff --git a/components/esp_driver_isp/include/driver/isp_awb.h b/components/esp_driver_isp/include/driver/isp_awb.h index 8fc03709fb..10883e2c66 100644 --- a/components/esp_driver_isp/include/driver/isp_awb.h +++ b/components/esp_driver_isp/include/driver/isp_awb.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -164,6 +164,18 @@ esp_err_t esp_isp_awb_controller_start_continuous_statistics(isp_awb_ctlr_t awb_ */ esp_err_t esp_isp_awb_controller_stop_continuous_statistics(isp_awb_ctlr_t awb_ctlr); +/** + * @brief Set AWB white balance gain + * + * @param[in] awb_ctlr AWB controller handle + * @param[in] gain AWB white balance gain + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Null pointer + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_set_wb_gain(isp_awb_ctlr_t awb_ctlr, isp_awb_gain_t gain); + /** * @brief Event data of callbacks */ diff --git a/components/esp_driver_isp/include/driver/isp_types.h b/components/esp_driver_isp/include/driver/isp_types.h index a1ff944014..3b3131d0f3 100644 --- a/components/esp_driver_isp/include/driver/isp_types.h +++ b/components/esp_driver_isp/include/driver/isp_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,14 +39,25 @@ typedef struct { int luminance[ISP_AF_WINDOW_NUM]; ///< Luminance, it refers how luminant an image is } isp_af_result_t; +/** + * @brief ISP AWB subwindow result + */ +typedef struct { + uint32_t white_patch_num[ISP_AWB_WINDOW_X_NUM][ISP_AWB_WINDOW_Y_NUM]; ///< white patch number that counted by AWB in the subwindow + uint32_t sum_r[ISP_AWB_WINDOW_X_NUM][ISP_AWB_WINDOW_Y_NUM]; ///< The sum of R channel of these white patches + uint32_t sum_g[ISP_AWB_WINDOW_X_NUM][ISP_AWB_WINDOW_Y_NUM]; ///< The sum of G channel of these white patches + uint32_t sum_b[ISP_AWB_WINDOW_X_NUM][ISP_AWB_WINDOW_Y_NUM]; ///< The sum of B channel of these white patches +} isp_awb_subwin_stat_result_t; + /** * @brief ISP AWB result */ typedef struct { - uint32_t white_patch_num; ///< white patch number that counted by AWB in the window - uint32_t sum_r; ///< The sum of R channel of these white patches - uint32_t sum_g; ///< The sum of G channel of these white patches - uint32_t sum_b; ///< The sum of B channel of these white patches + uint32_t white_patch_num; ///< white patch number that counted by AWB in the window + uint32_t sum_r; ///< The sum of R channel of these white patches + uint32_t sum_g; ///< The sum of G channel of these white patches + uint32_t sum_b; ///< The sum of B channel of these white patches + isp_awb_subwin_stat_result_t subwin_result; ///< The AWB subwindow statistics result } isp_awb_stat_result_t; /** diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index 46ce95bab2..e734985bcd 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -111,6 +111,10 @@ esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_a isp_ll_awb_enable(isp_proc->hal.hw, false); isp_ll_awb_set_clk_ctrl_mode(isp_proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO); isp_ll_awb_enable_algorithm_mode(isp_proc->hal.hw, true); +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + isp_ll_awb_set_wb_gain_clk_ctrl_mode(isp_proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO); + isp_ll_awb_enable_wb_gain(isp_proc->hal.hw, true); +#endif ESP_GOTO_ON_ERROR(s_esp_isp_awb_config_hardware(isp_proc, awb_cfg), err2, TAG, "configure awb hardware failed"); *ret_hdl = awb_ctlr; @@ -135,6 +139,9 @@ esp_err_t esp_isp_del_awb_controller(isp_awb_ctlr_t awb_ctlr) s_isp_declaim_awb_controller(awb_ctlr); isp_ll_awb_enable_algorithm_mode(awb_ctlr->isp_proc->hal.hw, false); +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + isp_ll_awb_enable_wb_gain(awb_ctlr->isp_proc->hal.hw, false); +#endif s_isp_awb_free_controller(awb_ctlr); return ESP_OK; @@ -221,6 +228,17 @@ esp_err_t esp_isp_awb_controller_stop_continuous_statistics(isp_awb_ctlr_t awb_c return ESP_OK; } +#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 +esp_err_t esp_isp_awb_controller_set_wb_gain(isp_awb_ctlr_t awb_ctlr, isp_awb_gain_t gain) +{ + ESP_RETURN_ON_FALSE(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(atomic_load(&awb_ctlr->fsm) != ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller not in init state"); + isp_ll_awb_set_wb_gain(awb_ctlr->isp_proc->hal.hw, gain); + + return ESP_OK; +} +#endif //#if !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ @@ -239,6 +257,26 @@ bool IRAM_ATTR esp_isp_awb_isr(isp_proc_handle_t proc, uint32_t awb_events) .sum_b = isp_ll_awb_get_accumulated_b_value(proc->hal.hw), }, }; + + // Get subwindow statistics + for (int x = 0; x < ISP_AWB_WINDOW_X_NUM; x++) { + for (int y = 0; y < ISP_AWB_WINDOW_Y_NUM; y++) { + int subwindow_id = x * ISP_AWB_WINDOW_Y_NUM + y; + + isp_ll_lut_awb_set_cmd(proc->hal.hw, ISP_LL_LUT_AWB_WHITE_PATCH_CNT, subwindow_id, ISP_LL_LUT_AWB); + edata.awb_result.subwin_result.white_patch_num[x][y] = isp_ll_lut_awb_get_subwindow_white_patch_cnt(proc->hal.hw); + + isp_ll_lut_awb_set_cmd(proc->hal.hw, ISP_LL_LUT_AWB_ACCUMULATED_R, subwindow_id, ISP_LL_LUT_AWB); + edata.awb_result.subwin_result.sum_r[x][y] = isp_ll_lut_awb_get_subwindow_accumulated_r(proc->hal.hw); + + isp_ll_lut_awb_set_cmd(proc->hal.hw, ISP_LL_LUT_AWB_ACCUMULATED_G, subwindow_id, ISP_LL_LUT_AWB); + edata.awb_result.subwin_result.sum_g[x][y] = isp_ll_lut_awb_get_subwindow_accumulated_g(proc->hal.hw); + + isp_ll_lut_awb_set_cmd(proc->hal.hw, ISP_LL_LUT_AWB_ACCUMULATED_B, subwindow_id, ISP_LL_LUT_AWB); + edata.awb_result.subwin_result.sum_b[x][y] = isp_ll_lut_awb_get_subwindow_accumulated_b(proc->hal.hw); + } + } + // Invoke the callback if the callback is registered if (awb_ctlr->cbs.on_statistics_done) { need_yield |= awb_ctlr->cbs.on_statistics_done(awb_ctlr, &edata, awb_ctlr->user_data); diff --git a/components/esp_driver_isp/src/isp_lsc.c b/components/esp_driver_isp/src/isp_lsc.c index 0d11a963d9..758d780758 100644 --- a/components/esp_driver_isp/src/isp_lsc.c +++ b/components/esp_driver_isp/src/isp_lsc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -76,10 +76,10 @@ esp_err_t esp_isp_lsc_configure(isp_proc_handle_t isp_proc, const esp_isp_lsc_co for (int y = 0; y < num_grids_y; y++) { for (int x = 0; x < num_grids_x; x++) { int i = y * num_grids_x + x; - isp_ll_lut_set_wdata_r_gr(isp_proc->hal.hw, config->gain_array->gain_r[i], config->gain_array->gain_gr[i]); - isp_ll_lut_set_cmd(isp_proc->hal.hw, true, false, i, ISP_LL_LUT_LSC); - isp_ll_lut_set_wdata_gb_b(isp_proc->hal.hw, config->gain_array->gain_gb[i], config->gain_array->gain_b[i]); - isp_ll_lut_set_cmd(isp_proc->hal.hw, true, true, i, ISP_LL_LUT_LSC); + isp_ll_lut_lsc_set_wdata_r_gr(isp_proc->hal.hw, config->gain_array->gain_r[i], config->gain_array->gain_gr[i]); + isp_ll_lut_lsc_set_cmd(isp_proc->hal.hw, true, false, i, ISP_LL_LUT_LSC); + isp_ll_lut_lsc_set_wdata_gb_b(isp_proc->hal.hw, config->gain_array->gain_gb[i], config->gain_array->gain_b[i]); + isp_ll_lut_lsc_set_cmd(isp_proc->hal.hw, true, true, i, ISP_LL_LUT_LSC); } } diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index a79a9d3b4f..288cb3ab90 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -15,6 +15,7 @@ #include "hal/config.h" #include "hal/isp_types.h" #include "hal/color_types.h" +#include "hal/config.h" #include "soc/isp_struct.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/clk_tree_defs.h" @@ -67,11 +68,14 @@ extern "C" { #define ISP_LL_EVENT_YUV2RGB_FRAME (1<<26) #define ISP_LL_EVENT_TAIL_IDI_FRAME (1<<27) #define ISP_LL_EVENT_HEADER_IDI_FRAME (1<<28) +#define ISP_LL_EVENT_CROP_FRAME (1<<29) +#define ISP_LL_EVENT_WBG_FRAME (1<<30) +#define ISP_LL_EVENT_CROP_ERR (1<<31) #define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF) #define ISP_LL_EVENT_AF_MASK (ISP_LL_EVENT_AF_FDONE | ISP_LL_EVENT_AF_ENV) #define ISP_LL_EVENT_AE_MASK (ISP_LL_EVENT_AE_FDONE | ISP_LL_EVENT_AE_ENV) -#define ISP_LL_EVENT_AWB_MASK (ISP_LL_EVENT_AWB_FDONE) +#define ISP_LL_EVENT_AWB_MASK (ISP_LL_EVENT_AWB_FDONE | ISP_LL_EVENT_WBG_FRAME) #define ISP_LL_EVENT_SHARP_MASK (ISP_LL_EVENT_SHARP_FRAME) #define ISP_LL_EVENT_HIST_MASK (ISP_LL_EVENT_HIST_FDONE) #define ISP_LL_EVENT_COLOR_MASK (ISP_LL_EVENT_COLOR_FRAME) @@ -172,8 +176,19 @@ typedef union { typedef enum { ISP_LL_LUT_LSC, ///< LUT for LSC ISP_LL_LUT_DPC, ///< LUT for DPC + ISP_LL_LUT_AWB, ///< LUT for AWB } isp_ll_lut_t; +/** + * @brief ISP LUT AWB type + */ +typedef enum { + ISP_LL_LUT_AWB_WHITE_PATCH_CNT, ///< White patch count + ISP_LL_LUT_AWB_ACCUMULATED_R, ///< Accumulated R + ISP_LL_LUT_AWB_ACCUMULATED_G, ///< Accumulated G + ISP_LL_LUT_AWB_ACCUMULATED_B, ///< Accumulated B +} isp_ll_lut_awb_t; + /** * @brief ISP pipeline clock control mode */ @@ -1366,7 +1381,7 @@ static inline void isp_ll_lsc_set_xtablesize(isp_dev_t *hw, uint8_t xtablesize) LUT ---------------------------------------------------------------*/ /** - * @brief Select ISP LUT + * @brief Select ISP LUT for LSC usage * * @param[in] hw Hardware instance address * @param[in] is_write Is write or not @@ -1374,7 +1389,7 @@ static inline void isp_ll_lsc_set_xtablesize(isp_dev_t *hw, uint8_t xtablesize) * @param[in] addr LUT addr * @param[in] lut ISP LUT */ -static inline void isp_ll_lut_set_cmd(isp_dev_t *hw, bool is_write, bool is_gb_b, uint32_t addr, isp_ll_lut_t lut) +static inline void isp_ll_lut_lsc_set_cmd(isp_dev_t *hw, bool is_write, bool is_gb_b, uint32_t addr, isp_ll_lut_t lut) { uint32_t val = 0; val |= is_write ? (1 << 16) : 0; @@ -1391,7 +1406,7 @@ static inline void isp_ll_lut_set_cmd(isp_dev_t *hw, bool is_write, bool is_gb_b * @param[in] gb_gain gb gain * @param[in] b_gain b gain */ -static inline void isp_ll_lut_set_wdata_gb_b(isp_dev_t *hw, isp_lsc_gain_t gb_gain, isp_lsc_gain_t b_gain) +static inline void isp_ll_lut_lsc_set_wdata_gb_b(isp_dev_t *hw, isp_lsc_gain_t gb_gain, isp_lsc_gain_t b_gain) { hw->lut_wdata.lut_wdata = (gb_gain.val & 0x3ff) << 10 | (b_gain.val & 0x3ff); } @@ -1403,11 +1418,75 @@ static inline void isp_ll_lut_set_wdata_gb_b(isp_dev_t *hw, isp_lsc_gain_t gb_ga * @param[in] r_gain r gain * @param[in] gr_gain gr gain */ -static inline void isp_ll_lut_set_wdata_r_gr(isp_dev_t *hw, isp_lsc_gain_t r_gain, isp_lsc_gain_t gr_gain) +static inline void isp_ll_lut_lsc_set_wdata_r_gr(isp_dev_t *hw, isp_lsc_gain_t r_gain, isp_lsc_gain_t gr_gain) { hw->lut_wdata.lut_wdata = (r_gain.val & 0x3ff) << 10 | (gr_gain.val & 0x3ff); } +/** + * @brief Set AWB LUT command + * + * @param[in] hw Hardware instance address + * @param[in] type ISP LUT AWB type + * @param[in] addr AWB sub window ID + */ +static inline void isp_ll_lut_awb_set_cmd(isp_dev_t *hw, isp_ll_lut_awb_t type, uint32_t sub_window_id, isp_ll_lut_t lut) +{ + HAL_ASSERT(sub_window_id <= 25); + uint32_t val = 0; + val |= 0x2000 + 4 * sub_window_id + type; + val |= lut << 12; + hw->lut_cmd.val = val; +} + +/** + * @brief Get AWB statistics of subwindow white patch count + * + * @param[in] hw Hardware instance address + * + * @return White patch number + */ +static inline uint32_t isp_ll_lut_awb_get_subwindow_white_patch_cnt(isp_dev_t *hw) +{ + return hw->lut_rdata.lut_rdata; +} + +/** + * @brief Get AWB statistics of subwindow accumulated R + * + * @param[in] hw Hardware instance address + * + * @return Accumulated R + */ +static inline uint32_t isp_ll_lut_awb_get_subwindow_accumulated_r(isp_dev_t *hw) +{ + return hw->lut_rdata.lut_rdata; +} + +/** + * @brief Get AWB statistics of subwindow accumulated G + * + * @param[in] hw Hardware instance address + * + * @return Accumulated G + */ +static inline uint32_t isp_ll_lut_awb_get_subwindow_accumulated_g(isp_dev_t *hw) +{ + return hw->lut_rdata.lut_rdata; +} + +/** + * @brief Get AWB statistics of subwindow accumulated B + * + * @param[in] hw Hardware instance address + * + * @return Accumulated B + */ +static inline uint32_t isp_ll_lut_awb_get_subwindow_accumulated_b(isp_dev_t *hw) +{ + return hw->lut_rdata.lut_rdata; +} + /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ @@ -1636,6 +1715,43 @@ static inline uint32_t isp_ll_awb_get_accumulated_b_value(isp_dev_t *hw) return hw->awb0_acc_b.awb0_acc_b; } +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +/** + * @brief Enable AWB white balance gain + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_awb_enable_wb_gain(isp_dev_t *hw, bool enable) +{ + hw->cntl.wbg_en = enable; +} + +/** + * @brief Set AWB white balance gain clock control mode + * + * @param[in] hw Hardware instance address + * @param[in] mode 'isp_ll_pipeline_clk_ctrl_t` + */ +static inline void isp_ll_awb_set_wb_gain_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode) +{ + hw->clk_en.clk_wbg_force_on = mode; +} + +/** + * @brief Set AWB white balance gain + * + * @param[in] hw Hardware instance address + * @param[in] gain AWB white balance gain + */ +static inline void isp_ll_awb_set_wb_gain(isp_dev_t *hw, isp_awb_gain_t gain) +{ + hw->wbg_coef_r.wbg_r = gain.gain_r; + hw->wbg_coef_g.wbg_g = gain.gain_g; + hw->wbg_coef_b.wbg_b = gain.gain_b; +} +#endif //#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 + /*--------------------------------------------------------------- Demosaic ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 974c5a3d35..29ecffe1b0 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.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 */ @@ -125,6 +125,14 @@ typedef enum { AWB ---------------------------------------------------------------*/ +#if SOC_ISP_AWB_WINDOW_X_NUMS +#define ISP_AWB_WINDOW_X_NUM SOC_ISP_AWB_WINDOW_X_NUMS // The AWB window number for sampling +#define ISP_AWB_WINDOW_Y_NUM SOC_ISP_AWB_WINDOW_Y_NUMS // The AWB window number for sampling +#else +#define ISP_AWB_WINDOW_X_NUM 0 +#define ISP_AWB_WINDOW_Y_NUM 0 +#endif + /** * @brief ISP AWB sample point in the ISP pipeline */ @@ -133,12 +141,21 @@ typedef enum { ISP_AWB_SAMPLE_POINT_AFTER_CCM, ///< Sample AWB data after CCM (Color Correction Matrix) } isp_awb_sample_point_t; +/** + * @brief ISP AWB gain + */ +typedef struct { + uint32_t gain_r; ///< White balance gain for R channel + uint32_t gain_g; ///< White balance gain for G channel + uint32_t gain_b; ///< White balance gain for B channel +} isp_awb_gain_t; + /*--------------------------------------------------------------- BF ---------------------------------------------------------------*/ #if SOC_ISP_BF_SUPPORTED -#define ISP_BF_TEMPLATE_X_NUMS SOC_ISP_BF_TEMPLATE_X_NUMS // BF template x field nums -#define ISP_BF_TEMPLATE_Y_NUMS SOC_ISP_BF_TEMPLATE_Y_NUMS // BF template y field nums +#define ISP_BF_TEMPLATE_X_NUMS SOC_ISP_BF_TEMPLATE_X_NUMS ///< BF template x field nums +#define ISP_BF_TEMPLATE_Y_NUMS SOC_ISP_BF_TEMPLATE_Y_NUMS ///< BF template y field nums #else #define ISP_BF_TEMPLATE_X_NUMS 0 #define ISP_BF_TEMPLATE_Y_NUMS 0 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index adbec0f47b..a5af548ca4 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -979,6 +979,14 @@ config SOC_ISP_AF_WINDOW_NUMS int default 3 +config SOC_ISP_AWB_WINDOW_X_NUMS + int + default 5 + +config SOC_ISP_AWB_WINDOW_Y_NUMS + int + default 5 + config SOC_ISP_BF_TEMPLATE_X_NUMS int default 3 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 31b6b173c5..dd17b2718c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -370,6 +370,8 @@ #define SOC_ISP_AE_BLOCK_Y_NUMS 5 #define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_WINDOW_NUMS 3 +#define SOC_ISP_AWB_WINDOW_X_NUMS 5 +#define SOC_ISP_AWB_WINDOW_Y_NUMS 5 #define SOC_ISP_BF_TEMPLATE_X_NUMS 3 #define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 #define SOC_ISP_CCM_DIMENSION 3