mirror of
https://github.com/espressif/esp-idf.git
synced 2026-01-19 17:55:43 +00:00
Merge branch 'feat/isp_crop_driver_v5.5' into 'release/v5.5'
feat(isp): support Crop driver on p4 rev3 (v5.5) See merge request espressif/esp-idf!43446
This commit is contained in:
@@ -46,6 +46,10 @@ if(CONFIG_SOC_ISP_WBG_SUPPORTED)
|
||||
list(APPEND srcs "src/isp_wbg.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ISP_CROP_SUPPORTED)
|
||||
list(APPEND srcs "src/isp_crop.c")
|
||||
endif()
|
||||
|
||||
if(NOT ${target} STREQUAL "linux")
|
||||
list(APPEND requires esp_mm)
|
||||
endif()
|
||||
|
||||
@@ -25,3 +25,4 @@
|
||||
#include "driver/isp_lsc.h"
|
||||
#include "driver/isp_sharpen.h"
|
||||
#include "driver/isp_wbg.h"
|
||||
#include "driver/isp_crop.h"
|
||||
|
||||
64
components/esp_driver_isp/include/driver/isp_crop.h
Normal file
64
components/esp_driver_isp/include/driver/isp_crop.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 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 ISP crop configurations
|
||||
*/
|
||||
typedef struct {
|
||||
isp_window_t window; /*!< Crop window coordinates */
|
||||
} esp_isp_crop_config_t;
|
||||
|
||||
/**
|
||||
* @brief ISP Crop configuration
|
||||
*
|
||||
* @note After calling this API, crop doesn't take into effect until `esp_isp_crop_enable` is called
|
||||
*
|
||||
* @param[in] isp_proc Processor handle
|
||||
* @param[in] config Crop configurations, set NULL to de-configure the ISP Crop
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||
*/
|
||||
esp_err_t esp_isp_crop_configure(isp_proc_handle_t isp_proc, const esp_isp_crop_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Enable ISP crop function
|
||||
*
|
||||
* @param[in] isp_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_crop_enable(isp_proc_handle_t isp_proc);
|
||||
|
||||
/**
|
||||
* @brief Disable ISP crop function
|
||||
*
|
||||
* @param[in] isp_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_crop_disable(isp_proc_handle_t isp_proc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -85,6 +85,7 @@ typedef struct isp_processor_t {
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) blc_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) ccm_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) color_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) crop_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) demosaic_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) gamma_fsm;
|
||||
ISP_ATOMIC_TYPE(isp_fsm_t) lsc_fsm;
|
||||
|
||||
80
components/esp_driver_isp/src/isp_crop.c
Normal file
80
components/esp_driver_isp/src/isp_crop.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/isp_core.h"
|
||||
#include "driver/isp_crop.h"
|
||||
#include "esp_private/isp_private.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "soc/chip_revision.h"
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Crop
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
#define IS_EVEN(x) ((x) % 2 == 0)
|
||||
#define IS_ODD(x) ((x) % 2 != 0)
|
||||
|
||||
static const char *TAG = "ISP_CROP";
|
||||
|
||||
esp_err_t esp_isp_crop_configure(isp_proc_handle_t isp_proc, const esp_isp_crop_config_t *config)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
unsigned chip_version = efuse_hal_chip_revision();
|
||||
if (!ESP_CHIP_REV_ABOVE(chip_version, 300)) {
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "Crop is not supported on ESP32P4 chips prior than v3.0");
|
||||
}
|
||||
#endif
|
||||
uint32_t x_start = config->window.top_left.x;
|
||||
uint32_t x_end = config->window.btm_right.x;
|
||||
uint32_t y_start = config->window.top_left.y;
|
||||
uint32_t y_end = config->window.btm_right.y;
|
||||
|
||||
ESP_RETURN_ON_FALSE(isp_proc && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(isp_proc->crop_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "crop is enabled already");
|
||||
ESP_RETURN_ON_FALSE(x_start < x_end, ESP_ERR_INVALID_ARG, TAG, "invalid window x coordinates");
|
||||
ESP_RETURN_ON_FALSE(y_start < y_end, ESP_ERR_INVALID_ARG, TAG, "invalid window y coordinates");
|
||||
ESP_RETURN_ON_FALSE(x_end <= isp_proc->h_res, ESP_ERR_INVALID_ARG, TAG, "window exceeds horizontal resolution");
|
||||
ESP_RETURN_ON_FALSE(y_end <= isp_proc->v_res, ESP_ERR_INVALID_ARG, TAG, "window exceeds vertical resolution");
|
||||
|
||||
// Check the validity of x/y coordinates
|
||||
ESP_RETURN_ON_FALSE(IS_EVEN(x_start), ESP_ERR_INVALID_ARG, TAG, "x_start must be even");
|
||||
ESP_RETURN_ON_FALSE(IS_ODD(x_end), ESP_ERR_INVALID_ARG, TAG, "x_end must be odd");
|
||||
ESP_RETURN_ON_FALSE(IS_EVEN(y_start), ESP_ERR_INVALID_ARG, TAG, "y_start must be even");
|
||||
ESP_RETURN_ON_FALSE(IS_ODD(y_end), ESP_ERR_INVALID_ARG, TAG, "y_end must be odd");
|
||||
|
||||
isp_ll_crop_set_clk_ctrl_mode(isp_proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO);
|
||||
isp_ll_crop_set_window(isp_proc->hal.hw, x_start, x_end, y_start, y_end);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_crop_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->crop_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "crop is enabled already");
|
||||
|
||||
isp_ll_crop_enable(isp_proc->hal.hw, true);
|
||||
isp_proc->crop_fsm = ISP_FSM_ENABLE;
|
||||
|
||||
ESP_LOGD(TAG, "Crop enabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_crop_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->crop_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "crop isn't enabled yet");
|
||||
|
||||
isp_ll_crop_enable(isp_proc->hal.hw, false);
|
||||
isp_proc->crop_fsm = ISP_FSM_INIT;
|
||||
|
||||
ESP_LOGD(TAG, "Crop disabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,11 @@ extern "C" {
|
||||
#define ISP_LL_EVENT_WBG_FRAME (1<<30)
|
||||
#define ISP_LL_EVENT_CROP_ERR (1<<31)
|
||||
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
#define ISP_LL_EVENT_ALL_MASK (0xFFFFFFFF)
|
||||
#else
|
||||
#define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF)
|
||||
#endif
|
||||
#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 | ISP_LL_EVENT_WBG_FRAME)
|
||||
@@ -199,6 +203,23 @@ typedef enum {
|
||||
ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC,
|
||||
} isp_ll_shadow_mode_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Crop
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief ISP crop error types
|
||||
*/
|
||||
typedef enum {
|
||||
ISP_LL_CROP_ERR_X_MISMATCH = (1 << 0), /*!< X end coordinate exceeds image size */
|
||||
ISP_LL_CROP_ERR_Y_MISMATCH = (1 << 1), /*!< Y end coordinate exceeds image size */
|
||||
ISP_LL_CROP_ERR_X_END_EVEN = (1 << 2), /*!< X end coordinate is even (should be odd) */
|
||||
ISP_LL_CROP_ERR_Y_END_EVEN = (1 << 3), /*!< Y end coordinate is even (should be odd) */
|
||||
ISP_LL_CROP_ERR_X_START_ODD = (1 << 4), /*!< X start coordinate is odd (should be even) */
|
||||
ISP_LL_CROP_ERR_Y_START_ODD = (1 << 5), /*!< Y start coordinate is odd (should be even) */
|
||||
} isp_ll_crop_error_t;
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Clock
|
||||
---------------------------------------------------------------*/
|
||||
@@ -2451,6 +2472,128 @@ static inline void isp_ll_hist_set_rgb_coefficient(isp_dev_t *hw, const isp_hist
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hist_coeff, hist_coeff_b, rgb_coeff->coeff_b.decimal);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
CROP
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
/**
|
||||
* @brief Set crop clock control mode
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] mode 'isp_ll_pipeline_clk_ctrl_t`
|
||||
*/
|
||||
static inline void isp_ll_crop_set_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode)
|
||||
{
|
||||
hw->clk_en.clk_crop_force_on = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable ISP crop
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] en enable / disable
|
||||
*/
|
||||
static inline void isp_ll_crop_enable(isp_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->cntl.crop_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ISP crop window coordinates
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] x_start Crop start x coordinate (0 to image_width-1)
|
||||
* @param[in] x_end Crop end x coordinate (x_start+1 to image_width-1)
|
||||
* @param[in] y_start Crop start y coordinate (0 to image_height-1)
|
||||
* @param[in] y_end Crop end y coordinate (y_start+1 to image_height-1)
|
||||
*/
|
||||
static inline void isp_ll_crop_set_window(isp_dev_t *hw,
|
||||
uint32_t x_start, uint32_t x_end,
|
||||
uint32_t y_start, uint32_t y_end)
|
||||
{
|
||||
hw->crop_x_capture.crop_x_start = x_start;
|
||||
hw->crop_x_capture.crop_x_end = x_end;
|
||||
hw->crop_y_capture.crop_y_start = y_start;
|
||||
hw->crop_y_capture.crop_y_end = y_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get crop window coordinates
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[out] x_start Crop start x coordinate (0 to image_width-1)
|
||||
* @param[out] x_end Crop end x coordinate (x_start+1 to image_width-1)
|
||||
* @param[out] y_start Crop start y coordinate (0 to image_height-1)
|
||||
* @param[out] y_end Crop end y coordinate (y_start+1 to image_height-1)
|
||||
*/
|
||||
static inline void isp_ll_crop_get_window(isp_dev_t *hw,
|
||||
uint32_t *x_start, uint32_t *x_end,
|
||||
uint32_t *y_start, uint32_t *y_end)
|
||||
{
|
||||
*x_start = hw->crop_x_capture.crop_x_start;
|
||||
*x_end = hw->crop_x_capture.crop_x_end;
|
||||
*y_start = hw->crop_y_capture.crop_y_start;
|
||||
*y_end = hw->crop_y_capture.crop_y_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get crop error status
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[out] error_bits Error status bits
|
||||
*/
|
||||
static inline void isp_ll_crop_get_error_status(isp_dev_t *hw, uint32_t *error_bits)
|
||||
{
|
||||
*error_bits = hw->crop_err_st.val & 0x3F; // Retrieve lower 6 bits
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear crop error
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
*/
|
||||
static inline void isp_ll_crop_clear_error(isp_dev_t *hw)
|
||||
{
|
||||
hw->crop_ctrl.crop_sft_rst = 1;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void isp_ll_crop_set_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
|
||||
static inline void isp_ll_crop_enable(isp_dev_t *hw, bool enable)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
|
||||
static inline void isp_ll_crop_set_window(isp_dev_t *hw,
|
||||
uint32_t x_start, uint32_t x_end,
|
||||
uint32_t y_start, uint32_t y_end)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
|
||||
static inline void isp_ll_crop_get_window(isp_dev_t *hw,
|
||||
uint32_t *x_start, uint32_t *x_end,
|
||||
uint32_t *y_start, uint32_t *y_end)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
|
||||
static inline void isp_ll_crop_get_error_status(isp_dev_t *hw, uint32_t *error_bits)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
|
||||
static inline void isp_ll_crop_clear_error(isp_dev_t *hw)
|
||||
{
|
||||
// for compatibility
|
||||
}
|
||||
#endif //#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -947,6 +947,10 @@ config SOC_ISP_COLOR_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ISP_CROP_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ISP_DEMOSAIC_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
@@ -357,6 +357,7 @@
|
||||
#define SOC_ISP_BLC_SUPPORTED 1
|
||||
#define SOC_ISP_CCM_SUPPORTED 1
|
||||
#define SOC_ISP_COLOR_SUPPORTED 1
|
||||
#define SOC_ISP_CROP_SUPPORTED 1
|
||||
#define SOC_ISP_DEMOSAIC_SUPPORTED 1
|
||||
#define SOC_ISP_DVP_SUPPORTED 1
|
||||
#define SOC_ISP_LSC_SUPPORTED 1
|
||||
|
||||
@@ -39,6 +39,7 @@ INPUT += \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_bf.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_blc.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_lsc.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_crop.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_demosaic.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_sharpen.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_core.h \
|
||||
|
||||
@@ -47,7 +47,7 @@ ISP Pipeline
|
||||
isp_chs [label = "Contrast &\n Hue & Saturation", width = 150, height = 70];
|
||||
isp_yuv [label = "YUV Limit\n YUB2RGB", width = 120, height = 70];
|
||||
|
||||
isp_header -> BLC -> BF -> LSC -> Demosaic -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> isp_tail;
|
||||
isp_header -> BLC -> BF -> LSC -> Demosaic -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> CROP -> isp_tail;
|
||||
|
||||
LSC -> HIST
|
||||
Demosaic -> AWB
|
||||
@@ -77,6 +77,7 @@ The ISP driver offers following services:
|
||||
- :ref:`isp-demosaic` - covers how to configure the Demosaic function.
|
||||
- :ref:`isp-gamma-correction` - covers how to enable and configure gamma correction.
|
||||
- :ref:`isp-sharpen` - covers how to configure the sharpening function.
|
||||
- :ref:`isp-crop` - covers how to enable and configure image cropping function.
|
||||
- :ref:`isp-callback` - covers how to hook user specific code to ISP driver event callback function.
|
||||
- :ref:`isp-thread-safety` - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
- :ref:`isp-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver.
|
||||
@@ -800,6 +801,51 @@ Calling :cpp:func:`esp_isp_sharpen_disable` does the opposite, that is, put the
|
||||
|
||||
:cpp:func:`esp_isp_sharpen_configure` is allowed to be called even if the driver is in **init** state, but the sharpen configurations will only be taken into effect when in **enable** state.
|
||||
|
||||
.. _isp-crop:
|
||||
|
||||
ISP Image Crop Controller
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ISP image crop function can extract a specified region from the original image, reducing the amount of data for subsequent processing and improving processing efficiency. The crop function is executed at the end of the ISP pipeline and can output a smaller region than the input image.
|
||||
|
||||
.. note::
|
||||
|
||||
The ISP image crop function is only available on ESP32-P4 revision 3.0 and above.
|
||||
|
||||
Calling :cpp:func:`esp_isp_crop_configure` to configure the image crop function, you can take the following code as reference:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_crop_config_t crop_config = {
|
||||
.window = {
|
||||
.top_left = {
|
||||
.x = 100, // Top-left X coordinate of crop region
|
||||
.y = 100, // Top-left Y coordinate of crop region
|
||||
},
|
||||
.btm_right = {
|
||||
.x = 699, // Bottom-right X coordinate of crop region
|
||||
.y = 499, // Bottom-right Y coordinate of crop region
|
||||
}
|
||||
}
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config));
|
||||
ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc));
|
||||
|
||||
After calling :cpp:func:`esp_isp_crop_configure`, you need to enable the ISP image crop controller by calling :cpp:func:`esp_isp_crop_enable`. This function:
|
||||
|
||||
* Switches the driver state from **init** to **enable**.
|
||||
|
||||
Calling :cpp:func:`esp_isp_crop_disable` does the opposite, that is, put the driver back to the **init** state.
|
||||
|
||||
:cpp:func:`esp_isp_crop_configure` is allowed to be called even if the driver is in **init** state, but the crop configurations will only be taken into effect when in **enable** state.
|
||||
|
||||
.. note::
|
||||
|
||||
- The top-left coordinates (top_left) of the crop region must be smaller than the bottom-right coordinates (btm_right)
|
||||
- The top-left coordinates (top_left) of the crop region must be even, and the bottom-right coordinates (btm_right) must be odd
|
||||
- The crop region cannot exceed the boundaries of the original image
|
||||
- Adjust the display medium (such as LCD) size according to the cropped resolution to ensure complete display and avoid black borders or stretching.
|
||||
|
||||
|
||||
.. _isp-callback:
|
||||
|
||||
@@ -927,6 +973,7 @@ API Reference
|
||||
.. include-build-file:: inc/isp_gamma.inc
|
||||
.. include-build-file:: inc/isp_hist.inc
|
||||
.. include-build-file:: inc/isp_color.inc
|
||||
.. include-build-file:: inc/isp_crop.inc
|
||||
.. include-build-file:: inc/isp_core.inc
|
||||
.. include-build-file:: inc/components/esp_driver_isp/include/driver/isp_types.inc
|
||||
.. include-build-file:: inc/components/hal/include/hal/isp_types.inc
|
||||
|
||||
@@ -47,7 +47,7 @@ ISP 流水线
|
||||
isp_chs [label = "对比度 &\n 色调 & 饱和度", width = 150, height = 70];
|
||||
isp_yuv [label = "YUV 限制\n YUB2RGB", width = 120, height = 70];
|
||||
|
||||
isp_header -> BLC -> BF -> LSC -> 去马赛克 -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> isp_tail;
|
||||
isp_header -> BLC -> BF -> LSC -> 去马赛克 -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> 裁剪 -> isp_tail;
|
||||
|
||||
LSC -> HIST
|
||||
去马赛克 -> AWB
|
||||
@@ -77,6 +77,7 @@ ISP 驱动程序提供以下服务:
|
||||
- :ref:`isp-demosaic` - 涵盖如何配置去马赛克功能。
|
||||
- :ref:`isp-gamma-correction` - 涵盖如何启用和配置 gamma 校正。
|
||||
- :ref:`isp-sharpen` - 涵盖如何配置锐化功能。
|
||||
- :ref:`isp-crop` - 涵盖如何启用和配置图像裁剪功能。
|
||||
- :ref:`isp-callback` - 涵盖如何将用户特定代码挂接到 ISP 驱动事件回调。
|
||||
- :ref:`isp-thread-safety` - 列出了驱动程序中线程安全的 API。
|
||||
- :ref:`isp-kconfig-options` - 列出了支持的 Kconfig 选项,这些选项可以对驱动程序产生不同影响。
|
||||
@@ -262,7 +263,7 @@ ISP AF 控制器
|
||||
|
||||
使用连续统计时,AF 环境检测器将失效。
|
||||
|
||||
.. code-block:: c
|
||||
.. code:: c
|
||||
|
||||
esp_isp_af_config_t af_config = {
|
||||
.edge_thresh = 128,
|
||||
@@ -399,7 +400,7 @@ ISP AE 控制器
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_ae_config_t ae_config = {
|
||||
esp_isp_ae_config_t ae_config = {
|
||||
.sample_point = ISP_AE_SAMPLE_POINT_AFTER_DEMOSAIC,
|
||||
};
|
||||
isp_ae_ctlr_t ae_ctlr = NULL;
|
||||
@@ -518,7 +519,6 @@ ISP BF 控制器
|
||||
|
||||
调用 :cpp:func:`esp_isp_bf_disable` 函数会执行相反的操作,即将驱动程序恢复到 **init** 状态。
|
||||
|
||||
|
||||
.. _isp-blc:
|
||||
|
||||
ISP BLC 控制器
|
||||
@@ -801,6 +801,50 @@ ISP 锐化控制器
|
||||
|
||||
即使驱动程序处于 **init** 状态,也可以调用 :cpp:func:`esp_isp_sharpen_configure`,但锐化配置只有在 **enable** 状态下才会生效。
|
||||
|
||||
.. _isp-crop:
|
||||
|
||||
ISP 图像裁剪控制器
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
ISP 图像裁剪功能可以从原始图像中提取指定区域,减少后续处理的数据量,提高处理效率。裁剪功能在 ISP 流水线的末端执行,可以输出比输入图像更小的区域。
|
||||
|
||||
.. note::
|
||||
|
||||
ISP 图像裁剪功能仅在 ESP32-P4 revision 3.0 及以上版本中可用。
|
||||
|
||||
可调用 :cpp:func:`esp_isp_crop_configure` 函数配置图像裁剪功能,请参考以下代码:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_crop_config_t crop_config = {
|
||||
.window = {
|
||||
.top_left = {
|
||||
.x = 100, // 裁剪区域左上角 X 坐标
|
||||
.y = 100, // 裁剪区域左上角 Y 坐标
|
||||
},
|
||||
.btm_right = {
|
||||
.x = 699, // 裁剪区域右下角 X 坐标
|
||||
.y = 499, // 裁剪区域右下角 Y 坐标
|
||||
}
|
||||
}
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config));
|
||||
ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc));
|
||||
|
||||
调用 :cpp:func:`esp_isp_crop_configure` 后,需要通过调用 :cpp:func:`esp_isp_crop_enable` 来启用 ISP 图像裁剪控制器。此函数:
|
||||
|
||||
* 将驱动程序状态从 **init** 切换到 **enable**。
|
||||
|
||||
调用 :cpp:func:`esp_isp_crop_disable` 函数会执行相反的操作,即将驱动程序恢复到 **init** 状态。
|
||||
|
||||
即使驱动程序处于 **init** 状态,也可以调用 :cpp:func:`esp_isp_crop_configure`,但裁剪配置只有在 **enable** 状态下才会生效。
|
||||
|
||||
.. note::
|
||||
|
||||
- 裁剪区域的左上角坐标 (top_left) 必须小于右下角坐标 (btm_right)
|
||||
- 裁剪区域的左上角坐标必须为偶数,右下角坐标必须为奇数
|
||||
- 裁剪区域不能超出原始图像的边界
|
||||
- 需根据裁剪后分辨率调整显示介质(如LCD)的尺寸,确保显示完整,避免出现黑边或拉伸现象。
|
||||
|
||||
.. _isp-callback:
|
||||
|
||||
@@ -850,7 +894,7 @@ ISP AE 环境检测器启动后,将动态生成特定事件。若想在事件
|
||||
注册 ISP HIST 统计完成事件回调函数
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
ISP HIST 控制器完成亮度统计后,将动态生成特定事件。若想在统计完成时收到通知,请通过调用 :cpp:func:`esp_isp_hist_register_event_callbacks` 将目标函数挂挂接到中断服务程序。所有支持的事件回调函数可参见 :cpp:type:`esp_isp_hist_cbs_t`:
|
||||
ISP HIST 控制器完成亮度统计后,将动态生成特定事件。若想在统计完成时收到通知,请通过调用 :cpp:func:`esp_isp_hist_register_event_callbacks` 将目标函数挂接到中断服务程序。所有支持的事件回调函数可参见 :cpp:type:`esp_isp_hist_cbs_t`:
|
||||
|
||||
- :cpp:member:`esp_isp_hist_cbs_t::on_statistics_done` 在完成亮度统计时设置回调函数。该函数原型在 :cpp:type:`esp_isp_hist_callback_t` 中声明。
|
||||
|
||||
@@ -928,6 +972,7 @@ API 参考
|
||||
.. include-build-file:: inc/isp_gamma.inc
|
||||
.. include-build-file:: inc/isp_hist.inc
|
||||
.. include-build-file:: inc/isp_color.inc
|
||||
.. include-build-file:: inc/isp_crop.inc
|
||||
.. include-build-file:: inc/isp_core.inc
|
||||
.. include-build-file:: inc/components/esp_driver_isp/include/driver/isp_types.inc
|
||||
.. include-build-file:: inc/components/hal/include/hal/isp_types.inc
|
||||
|
||||
@@ -15,7 +15,14 @@
|
||||
#include "example_dsi_init_config.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_panel_io_handle_t *mipi_dbi_io, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer)
|
||||
static const char *TAG = "example_dsi_init";
|
||||
|
||||
void example_dsi_resource_alloc(const example_dsi_alloc_config_t *config,
|
||||
esp_lcd_dsi_bus_handle_t *mipi_dsi_bus,
|
||||
esp_lcd_panel_io_handle_t *mipi_dbi_io,
|
||||
esp_lcd_panel_handle_t *mipi_dpi_panel,
|
||||
void** fb0,
|
||||
void** fb1)
|
||||
{
|
||||
//---------------DSI resource allocation------------------//
|
||||
esp_lcd_dsi_bus_config_t bus_config = {
|
||||
@@ -32,7 +39,22 @@ void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(*mipi_dsi_bus, &dbi_config, mipi_dbi_io));
|
||||
|
||||
// Use default config if not provided
|
||||
example_dsi_alloc_config_t default_config = EXAMPLE_DSI_ALLOC_CONFIG_DEFAULT();
|
||||
if (config == NULL) {
|
||||
config = &default_config;
|
||||
}
|
||||
|
||||
if (config->num_fbs < 1 || config->num_fbs > 2) {
|
||||
ESP_LOGE(TAG, "Invalid num_fbs: %d, must be 1 or 2", config->num_fbs);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t num_fbs = config->num_fbs;
|
||||
ESP_LOGI(TAG, "Allocating DSI resources with %d frame buffer(s)", num_fbs);
|
||||
|
||||
esp_lcd_dpi_panel_config_t dpi_config = {
|
||||
.num_fbs = num_fbs,
|
||||
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
|
||||
.dpi_clock_freq_mhz = EXAMPLE_MIPI_DSI_DPI_CLK_MHZ,
|
||||
.virtual_channel = 0,
|
||||
@@ -83,7 +105,23 @@ void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_ek79007(*mipi_dbi_io, &lcd_dev_config, mipi_dpi_panel));
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, frame_buffer));
|
||||
// Get frame buffer addresses
|
||||
if (fb0 != NULL) {
|
||||
if (num_fbs == 2) {
|
||||
if (fb1 != NULL) {
|
||||
ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 2, fb0, fb1));
|
||||
ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0);
|
||||
ESP_LOGD(TAG, "Frame buffer[1] allocated at: %p", *fb1);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "num_fbs is 2 but fb1 is NULL, only getting fb0");
|
||||
ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, fb0));
|
||||
ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0);
|
||||
}
|
||||
} else {
|
||||
ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, fb0));
|
||||
ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void example_dpi_panel_reset(esp_lcd_panel_handle_t mipi_dpi_panel)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -14,14 +14,37 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DSI init function
|
||||
*
|
||||
* @param[out] mipi_dsi_bus MIPI DSI bus handle
|
||||
* @param[out] mipi_dbi_io MIPI DBI io handle
|
||||
* @param[out] mipi_dpi_panel MIPI DPI panel handle
|
||||
* @param[out] frame_buffer frame buffer
|
||||
* @brief DSI allocation configuration
|
||||
*/
|
||||
void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_panel_io_handle_t *mipi_dbi_io, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer);
|
||||
typedef struct {
|
||||
uint8_t num_fbs; /*!< Number of frame buffers (1-2). */
|
||||
} example_dsi_alloc_config_t;
|
||||
|
||||
/**
|
||||
* @brief Default DSI allocation configuration
|
||||
*/
|
||||
#define EXAMPLE_DSI_ALLOC_CONFIG_DEFAULT() { \
|
||||
.num_fbs = 1, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DSI init function with configurable frame buffers
|
||||
*
|
||||
* @param[in] config DSI allocation configuration. If NULL, uses default (single buffer)
|
||||
* @param[out] mipi_dsi_bus MIPI DSI bus handle
|
||||
* @param[out] mipi_dbi_io MIPI DBI io handle
|
||||
* @param[out] mipi_dpi_panel MIPI DPI panel handle
|
||||
* @param[out] fb0 Pointer to receive the address of frame buffer 0 (first frame buffer)
|
||||
* @param[out] fb1 Pointer to receive the address of frame buffer 1 (second frame buffer). If NULL, single buffer mode is used.
|
||||
*
|
||||
* @note The number of frame buffers allocated is determined by config->num_fbs. If config is NULL, single buffer mode is used.
|
||||
*/
|
||||
void example_dsi_resource_alloc(const example_dsi_alloc_config_t *config,
|
||||
esp_lcd_dsi_bus_handle_t *mipi_dsi_bus,
|
||||
esp_lcd_panel_io_handle_t *mipi_dbi_io,
|
||||
esp_lcd_panel_handle_t *mipi_dpi_panel,
|
||||
void **fb0,
|
||||
void **fb1);
|
||||
|
||||
/**
|
||||
* @brief DPI panel reset function
|
||||
|
||||
@@ -57,10 +57,10 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy));
|
||||
|
||||
//---------------DSI Init------------------//
|
||||
example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer);
|
||||
example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL);
|
||||
|
||||
//---------------Necessary variable config------------------//
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
|
||||
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL);
|
||||
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
|
||||
@@ -108,7 +108,7 @@ void app_main(void)
|
||||
}
|
||||
|
||||
//--------Allocate Camera Buffer----------//
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM);
|
||||
if (!cam_buffer) {
|
||||
ESP_LOGE(TAG, "no mem for cam_buffer");
|
||||
|
||||
@@ -13,6 +13,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_RGB565_BITS_PER_PIXEL (16)
|
||||
#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
|
||||
#define EXAMPLE_DVP_CAM_XCLK_FREQ_HZ (20000000)
|
||||
#define EXAMPLE_DVP_CAM_DATA_WIDTH (8)
|
||||
|
||||
@@ -36,6 +38,7 @@ extern "C" {
|
||||
#define EXAMPLE_DVP_CAM_HSYNC_IO (-1)
|
||||
|
||||
#else
|
||||
|
||||
#define EXAMPLE_DVP_CAM_SCCB_SCL_IO (33)
|
||||
#define EXAMPLE_DVP_CAM_SCCB_SDA_IO (32)
|
||||
|
||||
|
||||
@@ -89,10 +89,10 @@ void app_main(void)
|
||||
* ISP convert to RGB565
|
||||
*/
|
||||
//---------------DSI Init------------------//
|
||||
example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer);
|
||||
example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL);
|
||||
|
||||
//---------------Necessary variable config------------------//
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
|
||||
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL);
|
||||
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
|
||||
@@ -157,7 +157,7 @@ void app_main(void)
|
||||
}
|
||||
|
||||
//--------Allocate Camera Buffer----------//
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM);
|
||||
if (!cam_buffer) {
|
||||
ESP_LOGE(TAG, "no mem for cam_buffer");
|
||||
|
||||
@@ -13,6 +13,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
|
||||
#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
|
||||
#define EXAMPLE_ISP_DVP_CAM_SCCB_SCL_IO (33)
|
||||
#define EXAMPLE_ISP_DVP_CAM_SCCB_SDA_IO (32)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
static const char *TAG = "dvp_spi_lcd";
|
||||
|
||||
#define BUFFER_SIZE (CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
#define BUFFER_SIZE (CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL)
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_handle_t panel_hdl;
|
||||
@@ -164,7 +164,7 @@ void app_main(void)
|
||||
}
|
||||
|
||||
//--------Allocate Camera Buffer----------//
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
void *cam_buffer = NULL;
|
||||
|
||||
cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, EXAMPLE_DVP_CAM_BUF_ALLOC_CAPS);
|
||||
|
||||
@@ -14,6 +14,7 @@ extern "C" {
|
||||
|
||||
//----------CAM Config------------//
|
||||
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
|
||||
#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
|
||||
#define EXAMPLE_DVP_CAM_SCCB_SCL_IO (5)
|
||||
#define EXAMPLE_DVP_CAM_SCCB_SDA_IO (4)
|
||||
|
||||
@@ -13,6 +13,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
|
||||
#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000)
|
||||
#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4
|
||||
|
||||
|
||||
@@ -51,10 +51,10 @@ void app_main(void)
|
||||
* ISP convert to RGB565
|
||||
*/
|
||||
//---------------DSI Init------------------//
|
||||
example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer);
|
||||
example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL);
|
||||
|
||||
//---------------Necessary variable config------------------//
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
|
||||
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL);
|
||||
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
|
||||
|
||||
@@ -16,6 +16,9 @@ This example demonstrates how to use the ISP (image signal processor) to work wi
|
||||
- ISP GAMMA feature
|
||||
- ISP Color feature
|
||||
- ISP LSC feature
|
||||
- ISP Crop feature (need to enable in `idf.py menuconfig`)
|
||||
|
||||
Additionally, this example also implements **Dual Frame Buffer (Ping-Pong Buffering)**, which eliminates screen tearing for smooth video display
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -121,6 +124,21 @@ Remember to select the LCD screen model and set corresponding correct horizontal
|
||||
|
||||
Available options for the camera sensor output horizontal/vertical resolution can be seen in ``menuconfig`` > ``Example Configuration``. Note that the horizontal resolution for the camera should be the same as the LCD screen horizontal resolution.
|
||||
|
||||
#### Optional: Image Cropping Configuration
|
||||
|
||||
This example supports optional image cropping, which allows you to capture and display a specific region of the camera output. To enable this feature:
|
||||
|
||||
1. Navigate to `menuconfig` > `Example Configuration`
|
||||
2. Enable `Enable ISP Image Cropping`
|
||||
3. Configure the crop region:
|
||||
- `ISP Crop Top-Left Horizontal`: X coordinate of top-left corner
|
||||
- `ISP Crop Top-Left Vertical`: Y coordinate of top-left corner
|
||||
- `ISP Crop Bottom-Right Horizontal`: X coordinate of bottom-right corner
|
||||
- `ISP Crop Bottom-Right Vertical`: Y coordinate of bottom-right corner
|
||||
|
||||
**Note**: When cropping is enabled:
|
||||
- The cropped image maintains its relative position on the screen
|
||||
- A dedicated frame processing task handles the image transformation
|
||||
|
||||
### Build and Flash
|
||||
|
||||
@@ -142,15 +160,23 @@ To exit the serial monitor, use `Ctrl` + `]`.
|
||||
If you see the following console output, your example should be running correctly:
|
||||
|
||||
```
|
||||
I (1085) main_task: Calling app_main()
|
||||
I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c
|
||||
I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0
|
||||
I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps
|
||||
I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps
|
||||
I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps
|
||||
I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps
|
||||
I (1425) main_task: Calling app_main()
|
||||
I (1425) example_dsi_init: Allocating DSI resources with 2 frame buffer(s)
|
||||
I (1485) example_dsi_init: Frame buffer[0] allocated at: 0x48000a40
|
||||
I (1485) example_dsi_init: Frame buffer[1] allocated at: 0x481f4a80
|
||||
I (1485) isp_dsi: Original CSI resolution: 800x640
|
||||
I (1485) isp_dsi: Display resolution: 800x640, bits per pixel: 16
|
||||
I (1495) isp_dsi: frame_buffer_size: 2048000
|
||||
I (1495) isp_dsi: Frame buffers: fb0=0x48000a40, fb1=0x481f4a80
|
||||
I (1515) ov5647: Detected Camera sensor PID=0x5647
|
||||
I (1535) sensor_init: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps
|
||||
I (1535) sensor_init: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps
|
||||
I (1535) sensor_init: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps
|
||||
I (1535) sensor_init: fmt[3].name:MIPI_2lane_24Minput_RAW10_1920x1080_30fps
|
||||
I (1545) sensor_init: fmt[4].name:MIPI_2lane_24Minput_RAW10_1280x960_binning_45fps
|
||||
I (2025) sensor_init: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps
|
||||
I (2045) isp_dsi: ISP Crop not configured
|
||||
I (2105) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c
|
||||
```
|
||||
|
||||
Below picture is from the video stream of OV5647 and ILI9881C. The camera module is auto-focused and calibrated by ESP on-chip ISP hardware. The edge is over-sharpened as example code configured.
|
||||
|
||||
@@ -44,4 +44,57 @@ menu "Example Configuration"
|
||||
default 600 if EXAMPLE_MIPI_CSI_VRES_600
|
||||
default 640 if EXAMPLE_MIPI_CSI_VRES_640
|
||||
default 1280 if EXAMPLE_MIPI_CSI_VRES_1280
|
||||
|
||||
config EXAMPLE_ISP_CROP_ENABLE
|
||||
depends on (ESP32P4_REV_MIN_FULL >= 300)
|
||||
bool "Enable ISP crop functionality"
|
||||
default n
|
||||
help
|
||||
Enable ISP crop functionality. When enabled, you can configure
|
||||
the crop area for the ISP pipeline.
|
||||
|
||||
menu "ISP Crop Configuration"
|
||||
visible if EXAMPLE_ISP_CROP_ENABLE
|
||||
|
||||
config EXAMPLE_ISP_CROP_TOP_LEFT_H
|
||||
int "ISP crop top-left horizontal coordinate"
|
||||
default 0
|
||||
range 0 799 if EXAMPLE_MIPI_CSI_HRES_800
|
||||
range 0 1023 if EXAMPLE_MIPI_CSI_HRES_1024
|
||||
help
|
||||
Horizontal coordinate of the top-left corner for ISP crop.
|
||||
Must be an even number and less than bottom-right horizontal coordinate.
|
||||
|
||||
config EXAMPLE_ISP_CROP_TOP_LEFT_V
|
||||
int "ISP crop top-left vertical coordinate"
|
||||
default 0
|
||||
range 0 599 if EXAMPLE_MIPI_CSI_VRES_600
|
||||
range 0 639 if EXAMPLE_MIPI_CSI_VRES_640
|
||||
range 0 1279 if EXAMPLE_MIPI_CSI_VRES_1280
|
||||
help
|
||||
Vertical coordinate of the top-left corner for ISP crop.
|
||||
Must be an even number and less than bottom-right vertical coordinate.
|
||||
|
||||
config EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H
|
||||
int "ISP crop bottom-right horizontal coordinate"
|
||||
default 799 if EXAMPLE_MIPI_CSI_HRES_800
|
||||
default 1023 if EXAMPLE_MIPI_CSI_HRES_1024
|
||||
range 1 799 if EXAMPLE_MIPI_CSI_HRES_800
|
||||
range 1 1023 if EXAMPLE_MIPI_CSI_HRES_1024
|
||||
help
|
||||
Horizontal coordinate of the bottom-right corner for ISP crop.
|
||||
Must be an odd number, greater than top-left horizontal coordinate, and not exceed display width.
|
||||
|
||||
config EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V
|
||||
int "ISP crop bottom-right vertical coordinate"
|
||||
default 599 if EXAMPLE_MIPI_CSI_VRES_600
|
||||
default 639 if EXAMPLE_MIPI_CSI_VRES_640
|
||||
default 1279 if EXAMPLE_MIPI_CSI_VRES_1280
|
||||
range 1 599 if EXAMPLE_MIPI_CSI_VRES_600
|
||||
range 1 639 if EXAMPLE_MIPI_CSI_VRES_640
|
||||
range 1 1279 if EXAMPLE_MIPI_CSI_VRES_1280
|
||||
help
|
||||
Vertical coordinate of the bottom-right corner for ISP crop.
|
||||
Must be an odd number, greater than top-left vertical coordinate, and not exceed display height.
|
||||
endmenu
|
||||
endmenu
|
||||
|
||||
@@ -11,6 +11,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_RGB565_BITS_PER_PIXEL 16
|
||||
#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8)
|
||||
#define EXAMPLE_MIPI_SCCB_FREQ (100000)
|
||||
#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4
|
||||
|
||||
|
||||
@@ -33,6 +33,103 @@ static const char *TAG = "isp_dsi";
|
||||
static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
|
||||
static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Ping-Pong Buffer Management
|
||||
---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
void *fb0; // Frame buffer 0
|
||||
void *fb1; // Frame buffer 1
|
||||
void *csi_buffer; // Current buffer for CSI to write
|
||||
void *dsi_buffer; // Current buffer for DSI to display
|
||||
esp_lcd_panel_handle_t panel;// DPI panel handle
|
||||
int h_res; // Horizontal resolution
|
||||
int v_res; // Vertical resolution (full screen)
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
int crop_h_res; // Cropped horizontal resolution
|
||||
int crop_v_res; // Cropped vertical resolution
|
||||
void *pending_buffer; // Buffer pending to be displayed
|
||||
SemaphoreHandle_t frame_ready_sem; // Semaphore to signal frame ready
|
||||
#endif
|
||||
} pingpong_buffer_ctx_t;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
/**
|
||||
* @brief Process frame: Add blank areas to fill full screen resolution
|
||||
*
|
||||
* Algorithm: Fill from bottom to top to avoid overwriting crop data
|
||||
* - Cropped image is placed at original position (relative to full frame)
|
||||
* - Other areas are filled with white (0xFFFF for RGB565)
|
||||
*
|
||||
* Example: Original 100x100, crop (50,50) to (100,100) → shows at bottom-right
|
||||
*
|
||||
* @param buffer Frame buffer to process (contains cropped image at start)
|
||||
* @param ctx Ping-pong buffer context
|
||||
*/
|
||||
static void process_frame_with_blanks(void *buffer, pingpong_buffer_ctx_t *ctx)
|
||||
{
|
||||
if (ctx->crop_v_res == ctx->v_res) {
|
||||
// No cropping, no need to process
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t *fb = (uint16_t *)buffer;
|
||||
|
||||
const int crop_left = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H;
|
||||
const int crop_top = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V;
|
||||
const int crop_right = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H;
|
||||
const int crop_bottom = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V;
|
||||
const int crop_width = crop_right - crop_left + 1;
|
||||
|
||||
const int full_width = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES;
|
||||
const int full_height = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES;
|
||||
|
||||
// Helper macros for pixel indexing
|
||||
#define SRC_PIXEL(x, y) fb[(y) * crop_width + (x)]
|
||||
#define DST_PIXEL(x, y) fb[(y) * full_width + (x)]
|
||||
|
||||
// ========== Step 1: Fill bottom blank region [crop_bottom+1, full_height) ==========
|
||||
if (crop_bottom + 1 < full_height) {
|
||||
memset(&DST_PIXEL(0, crop_bottom + 1),
|
||||
0xFF,
|
||||
full_width * (full_height - crop_bottom - 1) * EXAMPLE_RGB565_BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
// ========== Step 2: Process crop region [crop_top, crop_bottom] ==========
|
||||
for (int y = crop_bottom; y >= crop_top; y--) {
|
||||
int src_y = y - crop_top; // Corresponding row in cropped data (0-based)
|
||||
|
||||
// Fill right blank region first (crop_right+1, full_width)
|
||||
if (crop_right + 1 < full_width) {
|
||||
memset(&DST_PIXEL(crop_right + 1, y),
|
||||
0xFF,
|
||||
(full_width - crop_right - 1) * EXAMPLE_RGB565_BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
// Copy crop data from source to destination
|
||||
memcpy(&DST_PIXEL(crop_left, y),
|
||||
&SRC_PIXEL(0, src_y),
|
||||
crop_width * EXAMPLE_RGB565_BYTES_PER_PIXEL);
|
||||
|
||||
// Fill left blank region [0, crop_left)
|
||||
if (crop_left > 0) {
|
||||
memset(&DST_PIXEL(0, y),
|
||||
0xFF,
|
||||
crop_left * EXAMPLE_RGB565_BYTES_PER_PIXEL);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Step 3: Fill top blank region [0, crop_top) ==========
|
||||
if (crop_top > 0) {
|
||||
memset(&DST_PIXEL(0, 0),
|
||||
0xFF,
|
||||
full_width * crop_top * EXAMPLE_RGB565_BYTES_PER_PIXEL);
|
||||
}
|
||||
|
||||
#undef SRC_PIXEL
|
||||
#undef DST_PIXEL
|
||||
}
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AF
|
||||
---------------------------------------------------------------*/
|
||||
@@ -185,13 +282,47 @@ static uint32_t s_gamma_correction_curve(uint32_t x)
|
||||
return pow((double)x / 256, 0.7) * 256;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
/*---------------------------------------------------------------
|
||||
Frame Processing Task
|
||||
---------------------------------------------------------------*/
|
||||
static void frame_processing_task(void *arg)
|
||||
{
|
||||
pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)arg;
|
||||
|
||||
while (1) {
|
||||
// Wait for frame ready signal from ISR
|
||||
if (xSemaphoreTake(ctx->frame_ready_sem, portMAX_DELAY) == pdTRUE) {
|
||||
// Process the frame: add blank areas if needed
|
||||
process_frame_with_blanks(ctx->pending_buffer, ctx);
|
||||
|
||||
// Ping-Pong switch: swap CSI write buffer and DSI display buffer
|
||||
void *temp = ctx->csi_buffer;
|
||||
ctx->csi_buffer = ctx->dsi_buffer;
|
||||
ctx->dsi_buffer = temp;
|
||||
|
||||
// Trigger buffer switch by calling draw_bitmap
|
||||
// DPI driver will detect which buffer we're using and switch to it
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(ctx->panel,
|
||||
0, 0,
|
||||
ctx->h_res,
|
||||
ctx->crop_v_res,
|
||||
ctx->pending_buffer));
|
||||
|
||||
ESP_LOGD(TAG, "Frame displayed: %p", ctx->pending_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL;
|
||||
esp_lcd_panel_io_handle_t mipi_dbi_io = NULL;
|
||||
esp_lcd_panel_handle_t mipi_dpi_panel = NULL;
|
||||
void *frame_buffer = NULL;
|
||||
void *fb0 = NULL;
|
||||
void *fb1 = NULL;
|
||||
size_t frame_buffer_size = 0;
|
||||
|
||||
//mipi ldo
|
||||
@@ -207,18 +338,54 @@ void app_main(void)
|
||||
* Sensor use RAW8
|
||||
* ISP convert to RGB565
|
||||
*/
|
||||
//---------------DSI Init------------------//
|
||||
example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer);
|
||||
//---------------DSI Init with Dual Frame Buffers------------------//
|
||||
example_dsi_alloc_config_t dsi_alloc_config = {
|
||||
.num_fbs = 2, // Enable dual frame buffers
|
||||
};
|
||||
example_dsi_resource_alloc(&dsi_alloc_config, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &fb0, &fb1);
|
||||
|
||||
//---------------Necessary variable config------------------//
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8;
|
||||
int display_h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES;
|
||||
int display_v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES;
|
||||
|
||||
ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8);
|
||||
ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size);
|
||||
ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer);
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
// Use cropped resolution for frame buffer
|
||||
display_h_res = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H - CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H + 1;
|
||||
display_v_res = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V - CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V + 1;
|
||||
#endif
|
||||
|
||||
frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
|
||||
ESP_LOGI(TAG, "Original CSI resolution: %dx%d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES);
|
||||
ESP_LOGI(TAG, "Display resolution: %dx%d, bits per pixel: %d", display_h_res, display_v_res, EXAMPLE_RGB565_BITS_PER_PIXEL);
|
||||
ESP_LOGI(TAG, "Frame buffers: fb0=%p, fb1=%p", fb0, fb1);
|
||||
|
||||
//---------------Ping-Pong Buffer Context------------------//
|
||||
pingpong_buffer_ctx_t pp_ctx = {
|
||||
.fb0 = fb0,
|
||||
.fb1 = fb1,
|
||||
.csi_buffer = fb0, // CSI starts writing to fb0
|
||||
.dsi_buffer = fb1, // DSI starts displaying fb1
|
||||
.panel = mipi_dpi_panel,
|
||||
.h_res = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES,
|
||||
.v_res = CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES,
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
.crop_h_res = display_h_res,
|
||||
.crop_v_res = display_v_res,
|
||||
.pending_buffer = NULL,
|
||||
.frame_ready_sem = xSemaphoreCreateBinary(),
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
if (pp_ctx.frame_ready_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create frame ready semaphore");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_cam_ctlr_trans_t new_trans = {
|
||||
.buffer = frame_buffer,
|
||||
.buffer = pp_ctx.csi_buffer,
|
||||
.buflen = frame_buffer_size,
|
||||
};
|
||||
|
||||
@@ -248,8 +415,8 @@ void app_main(void)
|
||||
//---------------CSI Init------------------//
|
||||
esp_cam_ctlr_csi_config_t csi_config = {
|
||||
.ctlr_id = 0,
|
||||
.h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES,
|
||||
.v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES,
|
||||
.h_res = display_h_res,
|
||||
.v_res = display_v_res,
|
||||
.lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS,
|
||||
.input_data_color_type = CAM_CTLR_COLOR_RAW8,
|
||||
.output_data_color_type = CAM_CTLR_COLOR_RGB565,
|
||||
@@ -268,7 +435,7 @@ void app_main(void)
|
||||
.on_get_new_trans = s_camera_get_new_vb,
|
||||
.on_trans_finished = s_camera_get_finished_trans,
|
||||
};
|
||||
if (esp_cam_ctlr_register_event_callbacks(handle, &cbs, &new_trans) != ESP_OK) {
|
||||
if (esp_cam_ctlr_register_event_callbacks(handle, &cbs, &pp_ctx) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ops register fail");
|
||||
return;
|
||||
}
|
||||
@@ -422,6 +589,29 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_isp_lsc_enable(isp_proc));
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
/*---------------------------------------------------------------
|
||||
CROP
|
||||
---------------------------------------------------------------*/
|
||||
esp_isp_crop_config_t crop_config = {
|
||||
.window = {
|
||||
.top_left = {
|
||||
.x = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H,
|
||||
.y = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V
|
||||
},
|
||||
.btm_right = {
|
||||
.x = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H,
|
||||
.y = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V
|
||||
}
|
||||
}
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config));
|
||||
ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc));
|
||||
ESP_LOGI(TAG, "ISP Crop enabled: (%d,%d) to (%d,%d)",
|
||||
CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H, CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V,
|
||||
CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H, CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V);
|
||||
#endif
|
||||
|
||||
typedef struct af_task_param_t {
|
||||
isp_proc_handle_t isp_proc;
|
||||
esp_sccb_io_handle_t dw9714_io_handle;
|
||||
@@ -433,12 +623,20 @@ void app_main(void)
|
||||
};
|
||||
xTaskCreatePinnedToCore(af_task, "af_task", 8192, &af_task_param, 5, NULL, 0);
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
//---------------Frame Processing Task------------------//
|
||||
xTaskCreatePinnedToCore(frame_processing_task, "frame_proc", 4096, &pp_ctx, 6, NULL, 0);
|
||||
ESP_LOGI(TAG, "Frame processing task created");
|
||||
#endif
|
||||
|
||||
//---------------DPI Reset------------------//
|
||||
example_dpi_panel_reset(mipi_dpi_panel);
|
||||
|
||||
//init to all white
|
||||
memset(frame_buffer, 0xFF, frame_buffer_size);
|
||||
esp_cache_msync((void *)frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
//init both frame buffers to white
|
||||
memset(fb0, 0xFF, frame_buffer_size);
|
||||
memset(fb1, 0xFF, frame_buffer_size);
|
||||
esp_cache_msync((void *)fb0, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
esp_cache_msync((void *)fb1, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
|
||||
if (esp_cam_ctlr_start(handle) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Driver start fail");
|
||||
@@ -454,14 +652,30 @@ void app_main(void)
|
||||
|
||||
static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
|
||||
{
|
||||
esp_cam_ctlr_trans_t new_trans = *(esp_cam_ctlr_trans_t *)user_data;
|
||||
trans->buffer = new_trans.buffer;
|
||||
trans->buflen = new_trans.buflen;
|
||||
pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)user_data;
|
||||
|
||||
// Provide the current CSI buffer for the next frame
|
||||
trans->buffer = ctx->csi_buffer;
|
||||
trans->buflen = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)
|
||||
{
|
||||
pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)user_data;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
ctx->pending_buffer = trans->buffer;
|
||||
xSemaphoreGiveFromISR(ctx->frame_ready_sem, &high_task_wakeup);
|
||||
return (high_task_wakeup == pdTRUE);
|
||||
#else
|
||||
void *temp = ctx->csi_buffer;
|
||||
ctx->csi_buffer = ctx->dsi_buffer;
|
||||
ctx->dsi_buffer = temp;
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(ctx->panel, 0, 0, ctx->h_res, ctx->v_res, trans->buffer));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy));
|
||||
|
||||
//---------------DSI Init------------------//
|
||||
example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, NULL);
|
||||
example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, NULL, NULL);
|
||||
example_dpi_panel_reset(mipi_dpi_panel);
|
||||
example_dpi_panel_init(mipi_dpi_panel);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user