From 294868362f6236695214bdb7a9a3fa9eeaf5cd0f Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 24 Sep 2025 10:23:42 +0800 Subject: [PATCH] feat(isp_color): support ISP color on P4 --- .../esp_driver_isp/include/driver/isp_ccm.h | 2 +- components/esp_driver_isp/src/isp_ccm.c | 13 ++++- components/hal/esp32p4/include/hal/isp_ll.h | 6 +++ .../isp/multi_pipelines/main/isp_dsi_main.c | 54 ++++++++++++++++++- 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_isp/include/driver/isp_ccm.h b/components/esp_driver_isp/include/driver/isp_ccm.h index 1560782894..6f9531bf92 100644 --- a/components/esp_driver_isp/include/driver/isp_ccm.h +++ b/components/esp_driver_isp/include/driver/isp_ccm.h @@ -20,7 +20,7 @@ extern "C" { * */ typedef struct { - float matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]; /*!< The color correction matrix in float, range (-4.0, 4.0) */ + float matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]; /*!< The color correction matrix in float*/ bool saturation; /*!< Whether to use saturation when the float data in the matrix is out of the range, * For example, if one of the matrix data is 5.0, * When saturation is true, and final value will be limited to 4.0, and won't rise error diff --git a/components/esp_driver_isp/src/isp_ccm.c b/components/esp_driver_isp/src/isp_ccm.c index fd04c70cfb..e47af37025 100644 --- a/components/esp_driver_isp/src/isp_ccm.c +++ b/components/esp_driver_isp/src/isp_ccm.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 */ @@ -21,6 +21,17 @@ esp_err_t esp_isp_ccm_configure(isp_proc_handle_t proc, const esp_isp_ccm_config { ESP_RETURN_ON_FALSE(proc && ccm_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + // Check matrix values are within valid range + float max_range = (1 << ISP_LL_CCM_MATRIX_INT_BITS); + float min_range = -(1 << ISP_LL_CCM_MATRIX_INT_BITS); + for (int i = 0; i < ISP_CCM_DIMENSION; i++) { + for (int j = 0; j < ISP_CCM_DIMENSION; j++) { + float value = ccm_cfg->matrix[i][j]; + ESP_RETURN_ON_FALSE(value >= min_range && value <= max_range, ESP_ERR_INVALID_ARG, TAG, + "Matrix[%d][%d] value %f is out of range [%f, %f]", i, j, value, min_range, max_range); + } + } + bool ret = true; portENTER_CRITICAL(&proc->spinlock); isp_ll_ccm_set_clk_ctrl_mode(proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO); diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index 250537ca68..a79a9d3b4f 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -12,6 +12,7 @@ #include "hal/assert.h" #include "hal/config.h" #include "hal/hal_utils.h" +#include "hal/config.h" #include "hal/isp_types.h" #include "hal/color_types.h" #include "soc/isp_struct.h" @@ -123,8 +124,13 @@ extern "C" { /*--------------------------------------------------------------- CCM ---------------------------------------------------------------*/ +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +#define ISP_LL_CCM_MATRIX_INT_BITS (4) +#define ISP_LL_CCM_MATRIX_FRAC_BITS (8) +#else #define ISP_LL_CCM_MATRIX_INT_BITS (2) #define ISP_LL_CCM_MATRIX_FRAC_BITS (10) +#endif #define ISP_LL_CCM_MATRIX_TOT_BITS (ISP_LL_CCM_MATRIX_INT_BITS + ISP_LL_CCM_MATRIX_FRAC_BITS + 1) // including one sign bit typedef union { diff --git a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c index 79ac257074..852690f3ea 100644 --- a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c +++ b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c @@ -274,7 +274,9 @@ void app_main(void) } ESP_ERROR_CHECK(esp_cam_ctlr_enable(handle)); - //---------------ISP Init------------------// + /*--------------------------------------------------------------- + ISP Init + ---------------------------------------------------------------*/ isp_proc_handle_t isp_proc = NULL; esp_isp_processor_cfg_t isp_config = { .clk_hz = 80 * 1000 * 1000, @@ -289,6 +291,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); + /*--------------------------------------------------------------- + BF + ---------------------------------------------------------------*/ esp_isp_bf_config_t bf_config = { .denoising_level = 5, .padding_mode = ISP_BF_EDGE_PADDING_MODE_SRND_DATA, @@ -303,6 +308,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_bf_configure(isp_proc, &bf_config)); ESP_ERROR_CHECK(esp_isp_bf_enable(isp_proc)); + /*--------------------------------------------------------------- + BLC + ---------------------------------------------------------------*/ #if CONFIG_ESP32P4_REV_MIN_FULL >= 300 /** * This piece of BLC code is to show how to use the BLC related APIs. @@ -346,6 +354,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_blc_set_correction_offset(isp_proc, &blc_offset)); #endif + /*--------------------------------------------------------------- + DEMOSAIC + ---------------------------------------------------------------*/ esp_isp_demosaic_config_t demosaic_config = { .grad_ratio = { .integer = 2, @@ -355,6 +366,38 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_demosaic_configure(isp_proc, &demosaic_config)); ESP_ERROR_CHECK(esp_isp_demosaic_enable(isp_proc)); + /*--------------------------------------------------------------- + CCM + ---------------------------------------------------------------*/ + /** + * CCM is used for color correction and white balance adjustment. + * It should be configured after demosaic and before gamma correction. + * + * The matrix format is: + * [R_out] [RR RG RB] [R_in] + * [G_out] = [GR GG GB] [G_in] + * [B_out] [BR BG BB] [B_in] + * + * For ESP32P4 ECO5: + * - Matrix coefficients range: ±15.996 (4-bit integer + 8-bit fraction) + * - For earlier versions: ±3.999 (2-bit integer + 10-bit fraction) + */ + esp_isp_ccm_config_t ccm_config = { + .matrix = { + // Default identity matrix (no color correction) + {1.0, 0.0, 0.0}, // R channel: R = 1.0*R + 0.0*G + 0.0*B + {0.0, 1.0, 0.0}, // G channel: G = 0.0*R + 1.0*G + 0.0*B + {0.0, 0.0, 1.0} // B channel: B = 0.0*R + 0.0*G + 1.0*B + }, + .saturation = false // Don't use saturation for out-of-range values + }; + + ESP_ERROR_CHECK(esp_isp_ccm_configure(isp_proc, &ccm_config)); + ESP_ERROR_CHECK(esp_isp_ccm_enable(isp_proc)); + + /*--------------------------------------------------------------- + GAMMA + ---------------------------------------------------------------*/ isp_gamma_curve_points_t pts = {}; ESP_ERROR_CHECK(esp_isp_gamma_fill_curve_points(s_gamma_correction_curve, &pts)); ESP_ERROR_CHECK(esp_isp_gamma_configure(isp_proc, COLOR_COMPONENT_R, &pts)); @@ -362,6 +405,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_gamma_configure(isp_proc, COLOR_COMPONENT_B, &pts)); ESP_ERROR_CHECK(esp_isp_gamma_enable(isp_proc)); + /*--------------------------------------------------------------- + SHARPEN + ---------------------------------------------------------------*/ esp_isp_sharpen_config_t sharpen_config = { .h_freq_coeff = { .integer = 2, @@ -385,6 +431,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_sharpen_configure(isp_proc, &sharpen_config)); ESP_ERROR_CHECK(esp_isp_sharpen_enable(isp_proc)); + /*--------------------------------------------------------------- + COLOR + ---------------------------------------------------------------*/ esp_isp_color_config_t color_config = { .color_contrast = { .integer = 1, @@ -401,6 +450,9 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_color_enable(isp_proc)); #if CONFIG_ESP32P4_REV_MIN_FULL >= 100 + /*--------------------------------------------------------------- + LSC + ---------------------------------------------------------------*/ esp_isp_lsc_gain_array_t gain_array = {}; esp_isp_lsc_config_t lsc_config = { .gain_array = &gain_array,