Skip to content

Commit

Permalink
Merge branch 'feat/isp_lsc_feature' into 'master'
Browse files Browse the repository at this point in the history
isp: lsc feature

Closes IDF-11228

See merge request espressif/esp-idf!31193
  • Loading branch information
Icarus113 committed Oct 18, 2024
2 parents bae513e + 7e02f87 commit df9d722
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 17 deletions.
4 changes: 4 additions & 0 deletions components/esp_driver_isp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ if(CONFIG_SOC_ISP_COLOR_SUPPORTED)
list(APPEND srcs "src/isp_color.c")
endif()

if(CONFIG_SOC_ISP_LSC_SUPPORTED)
list(APPEND srcs "src/isp_lsc.c")
endif()

if(NOT ${target} STREQUAL "linux")
list(APPEND requires esp_mm)
endif()
Expand Down
1 change: 1 addition & 0 deletions components/esp_driver_isp/include/driver/isp.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
#include "driver/isp_hist.h"
#include "driver/isp_sharpen.h"
#include "driver/isp_color.h"
#include "driver/isp_lsc.h"
2 changes: 2 additions & 0 deletions components/esp_driver_isp/include/driver/isp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdbool.h>
#include "esp_err.h"
#include "driver/isp_types.h"
#include "hal/color_types.h"

#ifdef __cplusplus
extern "C" {
Expand All @@ -30,6 +31,7 @@ typedef struct {
bool has_line_end_packet; ///< Enable line end packet
uint32_t h_res; ///< Input horizontal resolution, i.e. the number of pixels in a line
uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame
color_raw_element_order_t bayer_order; ///< Bayer order
int intr_priority; ///< The interrupt priority, range 0~3, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
} esp_isp_processor_cfg_t;

Expand Down
91 changes: 91 additions & 0 deletions components/esp_driver_isp/include/driver/isp_lsc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <stdint.h>
#include "esp_err.h"
#include "driver/isp_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief LSC Gain array
*/
typedef struct {
isp_lsc_gain_t *gain_r; ///< Gain for R channel
isp_lsc_gain_t *gain_gr; ///< Gain for GR channel
isp_lsc_gain_t *gain_gb; ///< Gain for GB channel
isp_lsc_gain_t *gain_b; ///< Gain for B channel
} esp_isp_lsc_gain_array_t;

/**
* @brief ISP LSC configurations
*/
typedef struct {
esp_isp_lsc_gain_array_t *gain_array; ///< Gain array
} esp_isp_lsc_config_t;

/**
* @brief Helper function to allocate gain array for LSC
*
* @param[in] proc Processor handle
* @param[in] gain_array Gain array to be allocated
* @param[out] out_array_size_per_channel Array size
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE Not allowed to be called under current state
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t esp_isp_lsc_allocate_gain_array(isp_proc_handle_t isp_proc, esp_isp_lsc_gain_array_t *gain_array, size_t *out_array_size_per_channel);

/**
* @brief ISP LSC configuration
*
* @note After calling this API, LSC doesn't take into effect until `esp_isp_lsc_enable` is called
*
* @param[in] proc Processor handle
* @param[in] config LSC configurations
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE Not allowed to be called under current state
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
* - ESP_ERR_NOT_SUPPORTED Not supported
*/
esp_err_t esp_isp_lsc_configure(isp_proc_handle_t isp_proc, const esp_isp_lsc_config_t *config);

/**
* @brief Enable ISP LSC function
*
* @param[in] proc Processor handle
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state is invalid.
*/
esp_err_t esp_isp_lsc_enable(isp_proc_handle_t isp_proc);

/**
* @brief Disable ISP LSC function
*
* @param[in] proc Processor handle
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_ERR_INVALID_STATE Driver state is invalid.
*/
esp_err_t esp_isp_lsc_disable(isp_proc_handle_t isp_proc);

#ifdef __cplusplus
}
#endif
4 changes: 3 additions & 1 deletion components/esp_driver_isp/include/esp_private/isp_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ typedef struct isp_processor_t {
color_space_pixel_format_t out_color_format;
uint32_t h_res;
uint32_t v_res;
color_raw_element_order_t bayer_order;
/* sub module contexts */
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
isp_awb_ctlr_t awb_ctlr;
Expand All @@ -73,6 +74,7 @@ typedef struct isp_processor_t {
isp_fsm_t demosaic_fsm;
isp_fsm_t sharpen_fsm;
isp_fsm_t color_fsm;
isp_fsm_t lsc_fsm;
esp_isp_evt_cbs_t cbs;
void *user_data;

Expand All @@ -85,7 +87,7 @@ typedef struct isp_processor_t {
uint32_t ae_isr_added: 1;
uint32_t awb_isr_added: 1;
uint32_t sharp_isr_added: 1;
uint32_t hist_isr_added: 1;
uint32_t hist_isr_added: 1;
} isr_users;

} isp_processor_t;
Expand Down
2 changes: 2 additions & 0 deletions components/esp_driver_isp/src/isp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
isp_ll_enable_line_end_packet_exist(proc->hal.hw, proc_config->has_line_end_packet);
isp_ll_set_intput_data_h_pixel_num(proc->hal.hw, proc_config->h_res);
isp_ll_set_intput_data_v_row_num(proc->hal.hw, proc_config->v_res);
isp_ll_set_bayer_mode(proc->hal.hw, proc_config->bayer_order);
isp_ll_yuv_set_std(proc->hal.hw, proc_config->yuv_std);
if (out_color_format.color_space == COLOR_SPACE_YUV) {
isp_ll_yuv_set_range(proc->hal.hw, proc_config->yuv_range);
Expand All @@ -148,6 +149,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
proc->out_color_format = out_color_format;
proc->h_res = proc_config->h_res;
proc->v_res = proc_config->v_res;
proc->bayer_order = proc_config->bayer_order;

*ret_proc = proc;

Expand Down
110 changes: 110 additions & 0 deletions components/esp_driver_isp/src/isp_lsc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdatomic.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "driver/isp_core.h"
#include "driver/isp_bf.h"
#include "driver/isp_lsc.h"
#include "esp_private/isp_private.h"
#include "hal/efuse_hal.h"
#include "soc/chip_revision.h"

/*---------------------------------------------------------------
LSC
---------------------------------------------------------------*/
#define ISP_LSC_GET_GRIDS(res) (((res) - 1) / 2 / ISP_LL_LSC_GRID_HEIGHT + 2)

static const char *TAG = "ISP_LSC";

esp_err_t esp_isp_lsc_allocate_gain_array(isp_proc_handle_t isp_proc, esp_isp_lsc_gain_array_t *gain_array, size_t *out_array_size_per_channel)
{
ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(isp_proc->lsc_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "lsc is enabled already");

int num_grids_x_max = ISP_LSC_GET_GRIDS(ISP_LL_HSIZE_MAX);
int num_grids_y_max = ISP_LSC_GET_GRIDS(ISP_LL_VSIZE_MAX);
int num_grids_x = ISP_LSC_GET_GRIDS(isp_proc->h_res);
int num_grids_y = ISP_LSC_GET_GRIDS(isp_proc->v_res);
ESP_LOGD(TAG, "num_grids_x_max: %d, num_grids_x: %d, num_grids_y_max: %d, num_grids_y: %d", num_grids_x_max, num_grids_y_max, num_grids_x, num_grids_y);
ESP_RETURN_ON_FALSE(num_grids_x <= num_grids_x_max && num_grids_y <= num_grids_y_max, ESP_ERR_INVALID_ARG, TAG, "invalid h_res or v_res");

gain_array->gain_r = (isp_lsc_gain_t *)heap_caps_calloc(1, num_grids_x * num_grids_y * sizeof(isp_lsc_gain_t), ISP_MEM_ALLOC_CAPS);
gain_array->gain_gr = (isp_lsc_gain_t *)heap_caps_calloc(1, num_grids_x * num_grids_y * sizeof(isp_lsc_gain_t), ISP_MEM_ALLOC_CAPS);
gain_array->gain_gb = (isp_lsc_gain_t *)heap_caps_calloc(1, num_grids_x * num_grids_y * sizeof(isp_lsc_gain_t), ISP_MEM_ALLOC_CAPS);
gain_array->gain_b = (isp_lsc_gain_t *)heap_caps_calloc(1, num_grids_x * num_grids_y * sizeof(isp_lsc_gain_t), ISP_MEM_ALLOC_CAPS);

if (!gain_array->gain_r || !gain_array->gain_gr || !gain_array->gain_gb || !gain_array->gain_b) {
ESP_LOGE(TAG, "no enough mem for gain arrays");
return ESP_ERR_NO_MEM;
}
ESP_LOGD(TAG, "gain_array->gain_r: %p, gain_array->gain_gr: %p, gain_array->gain_gb: %p, gain_array->gain_b: %p", gain_array->gain_r, gain_array->gain_gr, gain_array->gain_gb, gain_array->gain_b);
*out_array_size_per_channel = num_grids_x * num_grids_y;
return ESP_OK;
}

esp_err_t esp_isp_lsc_configure(isp_proc_handle_t isp_proc, const esp_isp_lsc_config_t *config)
{
#if CONFIG_IDF_TARGET_ESP32P4
unsigned chip_version = efuse_hal_chip_revision();
if (!ESP_CHIP_REV_ABOVE(chip_version, 100)) {
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "LSC is not supported on ESP32P4 chips prior than ECO2");
}
#endif

ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

int num_grids_x_max = ISP_LSC_GET_GRIDS(ISP_LL_HSIZE_MAX);
int num_grids_y_max = ISP_LSC_GET_GRIDS(ISP_LL_VSIZE_MAX);
int num_grids_x = ISP_LSC_GET_GRIDS(isp_proc->h_res);
int num_grids_y = ISP_LSC_GET_GRIDS(isp_proc->v_res);
ESP_LOGD(TAG, "num_grids_x_max: %d, num_grids_x: %d, num_grids_y_max: %d, num_grids_y: %d", num_grids_x_max, num_grids_y_max, num_grids_x, num_grids_y);
ESP_RETURN_ON_FALSE(num_grids_x <= num_grids_x_max && num_grids_y <= num_grids_y_max, ESP_ERR_INVALID_ARG, TAG, "invalid h_res or v_res");
ESP_RETURN_ON_FALSE(config->gain_array->gain_r && config->gain_array->gain_gr && config->gain_array->gain_gb && config->gain_array->gain_b, ESP_ERR_INVALID_ARG, TAG, "null pointer to gain arrays");

isp_ll_lsc_set_xtablesize(isp_proc->hal.hw, num_grids_x);

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);
}
}

return ESP_OK;
}

esp_err_t esp_isp_lsc_enable(isp_proc_handle_t isp_proc)
{
ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(isp_proc->lsc_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "lsc is enabled already");

isp_ll_lsc_clk_enable(isp_proc->hal.hw, true);
isp_ll_lsc_enable(isp_proc->hal.hw, true);
isp_proc->lsc_fsm = ISP_FSM_ENABLE;

return ESP_OK;
}

esp_err_t esp_isp_lsc_disable(isp_proc_handle_t isp_proc)
{
ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(isp_proc->lsc_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "lsc isn't enabled yet");

isp_ll_lsc_enable(isp_proc->hal.hw, false);
isp_ll_lsc_clk_enable(isp_proc->hal.hw, false);
isp_proc->lsc_fsm = ISP_FSM_INIT;

return ESP_OK;
}
Loading

0 comments on commit df9d722

Please sign in to comment.