Skip to content

Commit

Permalink
Merge branch 'feature/isp_gamma_correction_support' into 'master'
Browse files Browse the repository at this point in the history
feat(isp): add gamma correction driver to ISP

Closes IDF-9988

See merge request espressif/esp-idf!32274
  • Loading branch information
songruo committed Aug 22, 2024
2 parents fab0658 + f2d131a commit c607544
Show file tree
Hide file tree
Showing 12 changed files with 473 additions and 539 deletions.
3 changes: 2 additions & 1 deletion components/esp_driver_isp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ if(CONFIG_SOC_ISP_SUPPORTED)
"src/isp_af.c"
"src/isp_ccm.c"
"src/isp_awb.c"
"src/isp_ae.c")
"src/isp_ae.c"
"src/isp_gamma.c")
endif()

if(CONFIG_SOC_ISP_BF_SUPPORTED)
Expand Down
2 changes: 1 addition & 1 deletion components/esp_driver_isp/include/driver/isp_ccm.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ typedef struct {
* but it only takes effect until `esp_isp_ccm_enable` is called
*
* @param[in] proc Processor handle
* @param[in] ccm_cfg CCM configurations, set NULL to de-configure the ISP CCM
* @param[in] ccm_cfg CCM configurations
*
* @return
* - ESP_OK On success
Expand Down
76 changes: 76 additions & 0 deletions components/esp_driver_isp/include/driver/isp_gamma.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

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

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief ISP gamma Correction configuration
*
* @note This function is allowed to be called before or after esp_isp_gamma_enable(),
* but it only takes effect until esp_isp_gamma_enable() is called
*
* @param[in] proc Processor handle
* @param[in] component One of the R/G/B components, color_component_t
* @param[in] pts Group of points that describe the desired gamma correction curve;<br>
* Passing in NULL to reset to default parameters (no correction)
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
*/
esp_err_t esp_isp_gamma_configure(isp_proc_handle_t proc, color_component_t component, const isp_gamma_curve_points_t *pts);

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

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

/**
* @brief Helper function to fill the isp_gamma_curve_points_t structure, giving the mathematical function of the desired gamma correction curve
*
* @note The raw values are sampled with equal spacing
*
* @param[in] gamma_correction_operator The desired gamma correction curve y = f(x).<br>
* x is the raw value, in [0, 256]; y is the gamma-corrected value, in [0, 256];<br>
* y can be equal to 256 only if x = 256. For any other x value, y should be always less than 256.
* @param[out] pts Pointer to the to-be-filled isp_gamma_curve_points_t structure
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
*/
esp_err_t esp_isp_gamma_fill_curve_points(uint32_t (* gamma_correction_operator)(uint32_t), isp_gamma_curve_points_t *pts);

#ifdef __cplusplus
}
#endif
2 changes: 2 additions & 0 deletions components/esp_driver_isp/linker.lf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ archive: libesp_driver_isp.a
entries:
if ISP_CTRL_FUNC_IN_IRAM = y:
isp_sharpen: esp_isp_sharpen_configure (noflash)
isp_gamma: esp_isp_gamma_configure (noflash)
isp_gamma: esp_isp_gamma_fill_curve_points (noflash)

[mapping:isp_hal]
archive: libhal.a
Expand Down
99 changes: 99 additions & 0 deletions components/esp_driver_isp/src/isp_gamma.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <esp_types.h>
#include <sys/param.h>
#include "esp_log.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "driver/isp_core.h"
#include "driver/isp_gamma.h"
#include "esp_private/isp_private.h"
#include "hal/isp_types.h"

static const char *TAG = "ISP_GAMMA";

/*---------------------------------------------------------------
Gamma Correction
---------------------------------------------------------------*/
// A curve of y = x indicates no gamma curve correction involved
static inline uint32_t s_gamma_linear_curve(uint32_t x)
{
return x;
}

esp_err_t esp_isp_gamma_configure(isp_proc_handle_t proc, color_component_t component, const isp_gamma_curve_points_t *pts)
{
ESP_RETURN_ON_FALSE_ISR(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE_ISR(component < COLOR_COMPONENT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid argument: component");

if (!pts) {
isp_gamma_curve_points_t linear_pts = {};
esp_isp_gamma_fill_curve_points(s_gamma_linear_curve, &linear_pts);
isp_ll_gamma_set_correction_curve(proc->hal.hw, component, &linear_pts);
return ESP_OK;
}

// Check the validation of x values
uint32_t x_prev = 0;
for (int i = 0; i < ISP_GAMMA_CURVE_POINTS_NUM; i++) {
uint32_t x_i = pts->pt[i].x;
if (i == ISP_GAMMA_CURVE_POINTS_NUM - 1) {
ESP_RETURN_ON_FALSE_ISR(x_i == 255, ESP_ERR_INVALID_ARG, TAG, "invalid argument: pts->pt[ISP_GAMMA_CURVE_POINTS_NUM - 1].x != 255");
x_i = 256;
}
uint32_t x_delta = x_i - x_prev;
ESP_RETURN_ON_FALSE_ISR((x_i > x_prev) && ((x_delta & (x_delta - 1)) == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: pts->pt[%d].x", i);
x_prev = x_i;
}

isp_ll_gamma_set_correction_curve(proc->hal.hw, component, pts);

return ESP_OK;
}

esp_err_t esp_isp_gamma_enable(isp_proc_handle_t proc)
{
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

portENTER_CRITICAL(&proc->spinlock);
isp_ll_gamma_enable(proc->hal.hw, true);
portEXIT_CRITICAL(&proc->spinlock);

return ESP_OK;
}

esp_err_t esp_isp_gamma_disable(isp_proc_handle_t proc)
{
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

portENTER_CRITICAL(&proc->spinlock);
isp_ll_gamma_enable(proc->hal.hw, false);
portEXIT_CRITICAL(&proc->spinlock);

return ESP_OK;
}

esp_err_t esp_isp_gamma_fill_curve_points(uint32_t (* gamma_correction_operator)(uint32_t), isp_gamma_curve_points_t *pts)
{
ESP_RETURN_ON_FALSE_ISR(gamma_correction_operator && pts, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

uint32_t x_i = 0;
uint32_t y_i = 0;
const uint32_t x_delta = 256 / ISP_GAMMA_CURVE_POINTS_NUM;
for (int i = 0; i < ISP_GAMMA_CURVE_POINTS_NUM; i++) {
x_i += x_delta;
x_i = MIN(x_i, 255);
y_i = gamma_correction_operator(x_i);
#if !CONFIG_ISP_CTRL_FUNC_IN_IRAM
ESP_LOGD(TAG, "x[%d] = %"PRIu32", y[%d] = %"PRIu32"", i, x_i, i, y_i);
#endif
ESP_RETURN_ON_FALSE_ISR(y_i < 256, ESP_ERR_INVALID_ARG, TAG, "invalid argument: gamma_correction_operator");
pts->pt[i].x = x_i;
pts->pt[i].y = y_i;
}
return ESP_OK;
}
71 changes: 71 additions & 0 deletions components/hal/esp32p4/include/hal/isp_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,77 @@ static inline void isp_ll_yuv_set_std(isp_dev_t *hw, isp_yuv_conv_std_t std)
hw->yuv_format.yuv_mode = std;
}

/*---------------------------------------------------------------
Gamma Correction
---------------------------------------------------------------*/
/**
* @brief Enable / Disable gamma
*
* @param[in] hw Hardware instance address
* @param[in] enable Enable / Disable
*/
static inline void isp_ll_gamma_enable(isp_dev_t *hw, bool enable)
{
hw->cntl.gamma_en = enable;
}

/**
* @brief Set gamma correction curve for one of the R/G/B components
*
* @param[in] hw Hardware instance address
* @param[in] channel One of the R/G/B components, color_component_t
* @param[in] pts Pointer to the structure that contains the information of the gamma curve
*/
__attribute__((always_inline))
static inline void isp_ll_gamma_set_correction_curve(isp_dev_t *hw, color_component_t channel, const isp_gamma_curve_points_t *pts)
{
int ch_index = -1;
switch (channel) {
case COLOR_COMPONENT_R:
ch_index = 0;
break;
case COLOR_COMPONENT_G:
ch_index = 1;
break;
case COLOR_COMPONENT_B:
ch_index = 2;
break;
default:
abort();
}

uint32_t x_prev = 0;
uint32_t gamma_x1 = 0, gamma_x2 = 0, gamma_y1 = 0, gamma_y2 = 0, gamma_y3 = 0, gamma_y4 = 0;
for (int i = 0; i < ISP_GAMMA_CURVE_POINTS_NUM; i++) {
uint32_t x_delta = (i == (ISP_GAMMA_CURVE_POINTS_NUM - 1) ? 256 : pts->pt[i].x) - x_prev;
uint32_t power = __builtin_ctz(x_delta);
HAL_ASSERT((x_delta & (x_delta - 1)) == 0 && power < 8);
if (i < 4) {
gamma_x1 |= (power << (21 - i * 3));
gamma_y1 |= (pts->pt[i].y << (24 - i * 8));
} else if (i < 8) {
gamma_x1 |= (power << (21 - i * 3));
gamma_y2 |= (pts->pt[i].y << (24 - (i - 4) * 8));
} else if (i < 12) {
gamma_x2 |= (power << (21 - (i - 8) * 3));
gamma_y3 |= (pts->pt[i].y << (24 - (i - 8) * 8));
} else {
gamma_x2 |= (power << (21 - (i - 8) * 3));
gamma_y4 |= (pts->pt[i].y << (24 - (i - 12) * 8));
}
x_prev = pts->pt[i].x;
}
hw->gamma_rgb_x[ch_index].gamma_x1.val = gamma_x1;
hw->gamma_rgb_x[ch_index].gamma_x2.val = gamma_x2;
hw->gamma_rgb_y[ch_index].gamma_y1.val = gamma_y1;
hw->gamma_rgb_y[ch_index].gamma_y2.val = gamma_y2;
hw->gamma_rgb_y[ch_index].gamma_y3.val = gamma_y3;
hw->gamma_rgb_y[ch_index].gamma_y4.val = gamma_y4;

hw->gamma_ctrl.gamma_update = 1;
while (hw->gamma_ctrl.gamma_update);
}

#ifdef __cplusplus
}
#endif
14 changes: 14 additions & 0 deletions components/hal/include/hal/color_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,20 @@ typedef union {
uint16_t val; /*!< 16-bit RGB565 value */
} color_pixel_rgb565_data_t;

/*---------------------------------------------------------------
Color Components
---------------------------------------------------------------*/

/**
* @brief Color component
*/
typedef enum {
COLOR_COMPONENT_R, /*!< R component */
COLOR_COMPONENT_G, /*!< G component */
COLOR_COMPONENT_B, /*!< B component */
COLOR_COMPONENT_INVALID, /*!< Invalid color component */
} color_component_t;

#ifdef __cplusplus
}
#endif
26 changes: 23 additions & 3 deletions components/hal/include/hal/isp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ typedef enum {

/**
* @brief ISP AWB sample point in the ISP pipeline
*
*/
typedef enum {
ISP_AWB_SAMPLE_POINT_BEFORE_CCM, ///< Sample AWB data before CCM (Color Correction Matrix)
Expand Down Expand Up @@ -192,7 +191,7 @@ typedef union {
uint32_t integer:ISP_SHARPEN_H_FREQ_COEF_INT_BITS; ///< Decimal part
uint32_t reserved:ISP_SHARPEN_H_FREQ_COEF_RES_BITS; ///< Reserved
};
uint32_t val;
uint32_t val; ///< 32-bit high freq pixel sharpeness coeff register value
} isp_sharpen_h_freq_coeff;

/**
Expand All @@ -204,7 +203,7 @@ typedef union {
uint32_t integer:ISP_SHARPEN_M_FREQ_COEF_INT_BITS; ///< Decimal part
uint32_t reserved:ISP_SHARPEN_M_FREQ_COEF_RES_BITS; ///< Reserved
};
uint32_t val;
uint32_t val; ///< 32-bit medium freq pixel sharpeness coeff register value
} isp_sharpen_m_freq_coeff;

/**
Expand All @@ -215,6 +214,27 @@ typedef enum {
ISP_SHARPEN_EDGE_PADDING_MODE_CUSTOM_DATA, ///< Fill Sharpen edge padding data with custom pixel data
} isp_sharpen_edge_padding_mode_t;

/*---------------------------------------------------------------
Gamma Correction
---------------------------------------------------------------*/
#define ISP_GAMMA_CURVE_POINTS_NUM 16 ///< Number of points to define a gamma correction curve

/**
* @brief Structure that declares the points on an ISP gamma curve
*
* Constraint on pt[n].x:
* When n = 0, pt[n].x = 2 ^ a[n]
* When 0 < n < ISP_GAMMA_CURVE_POINTS_NUM-1, pt[n].x - pt[n-1].x = 2 ^ a[n]
* When n = ISP_GAMMA_CURVE_POINTS_NUM-1, pt[n].x = 255, (pt[n].x + 1) - pt[n-1].x = 2 ^ a[n]
* a[n] within [0, 7]
*/
typedef struct {
struct {
uint8_t x; ///< Raw value (0, 255]
uint8_t y; ///< gamma-corrected value (0, 255]
} pt[ISP_GAMMA_CURVE_POINTS_NUM]; ///< Point (x, y)
} isp_gamma_curve_points_t;

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit c607544

Please sign in to comment.