forked from espressif/esp-idf
feat(isp): supported bypass isp to use csi
This commit is contained in:
committed by
Armando (Dou Yiwen)
parent
71e4d9ec50
commit
4abe226cf3
@@ -33,6 +33,9 @@ typedef struct {
|
|||||||
uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame
|
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
|
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)
|
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)
|
||||||
|
struct {
|
||||||
|
uint32_t bypass_isp: 1; ///< Bypass ISP pipelines
|
||||||
|
} flags; ///< Flags
|
||||||
} esp_isp_processor_cfg_t;
|
} esp_isp_processor_cfg_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -65,6 +65,7 @@ typedef struct isp_processor_t {
|
|||||||
uint32_t h_res;
|
uint32_t h_res;
|
||||||
uint32_t v_res;
|
uint32_t v_res;
|
||||||
color_raw_element_order_t bayer_order;
|
color_raw_element_order_t bayer_order;
|
||||||
|
bool bypass_isp;
|
||||||
/* sub module contexts */
|
/* sub module contexts */
|
||||||
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
|
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
|
||||||
isp_awb_ctlr_t awb_ctlr;
|
isp_awb_ctlr_t awb_ctlr;
|
||||||
|
@@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -17,12 +17,15 @@
|
|||||||
#include "esp_private/periph_ctrl.h"
|
#include "esp_private/periph_ctrl.h"
|
||||||
#include "esp_private/mipi_csi_share_hw_ctrl.h"
|
#include "esp_private/mipi_csi_share_hw_ctrl.h"
|
||||||
#include "hal/hal_utils.h"
|
#include "hal/hal_utils.h"
|
||||||
|
#include "hal/color_hal.h"
|
||||||
#include "soc/mipi_csi_bridge_struct.h"
|
#include "soc/mipi_csi_bridge_struct.h"
|
||||||
#include "soc/isp_periph.h"
|
#include "soc/isp_periph.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "esp_private/esp_clk_tree_common.h"
|
#include "esp_private/esp_clk_tree_common.h"
|
||||||
#include "esp_private/isp_private.h"
|
#include "esp_private/isp_private.h"
|
||||||
|
|
||||||
|
#define ISP_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
|
||||||
|
|
||||||
typedef struct isp_platform_t {
|
typedef struct isp_platform_t {
|
||||||
_lock_t mutex;
|
_lock_t mutex;
|
||||||
isp_processor_t *processors[SOC_ISP_NUMS];
|
isp_processor_t *processors[SOC_ISP_NUMS];
|
||||||
@@ -76,6 +79,9 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
|
|||||||
esp_err_t ret = ESP_FAIL;
|
esp_err_t ret = ESP_FAIL;
|
||||||
ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet");
|
ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet");
|
||||||
|
if (proc_config->flags.bypass_isp) {
|
||||||
|
ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == proc_config->output_data_color_type, ESP_ERR_INVALID_ARG, TAG, "isp is bypassed, input and output data color type should be same");
|
||||||
|
}
|
||||||
|
|
||||||
isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS);
|
isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS);
|
||||||
ESP_RETURN_ON_FALSE(proc, ESP_ERR_NO_MEM, TAG, "no mem");
|
ESP_RETURN_ON_FALSE(proc, ESP_ERR_NO_MEM, TAG, "no mem");
|
||||||
@@ -117,27 +123,39 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
|
|||||||
proc->isp_fsm = ISP_FSM_INIT;
|
proc->isp_fsm = ISP_FSM_INIT;
|
||||||
proc->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
proc->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
//Input color format
|
//Input & Output color format
|
||||||
bool valid_format = false;
|
|
||||||
color_space_pixel_format_t in_color_format = {
|
color_space_pixel_format_t in_color_format = {
|
||||||
.color_type_id = proc_config->input_data_color_type,
|
.color_type_id = proc_config->input_data_color_type,
|
||||||
};
|
};
|
||||||
valid_format = isp_ll_set_input_data_color_format(proc->hal.hw, in_color_format);
|
|
||||||
ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid input color space config");
|
|
||||||
|
|
||||||
//Output color format
|
|
||||||
valid_format = false;
|
|
||||||
color_space_pixel_format_t out_color_format = {
|
color_space_pixel_format_t out_color_format = {
|
||||||
.color_type_id = proc_config->output_data_color_type,
|
.color_type_id = proc_config->output_data_color_type,
|
||||||
};
|
};
|
||||||
valid_format = isp_ll_set_output_data_color_format(proc->hal.hw, out_color_format);
|
int in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(in_color_format);
|
||||||
ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid output color space config");
|
|
||||||
|
if (!proc_config->flags.bypass_isp) {
|
||||||
|
bool valid_format = false;
|
||||||
|
valid_format = isp_ll_set_input_data_color_format(proc->hal.hw, in_color_format);
|
||||||
|
ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid input color space config");
|
||||||
|
|
||||||
|
valid_format = false;
|
||||||
|
valid_format = isp_ll_set_output_data_color_format(proc->hal.hw, out_color_format);
|
||||||
|
ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid output color space config");
|
||||||
|
}
|
||||||
|
|
||||||
isp_ll_clk_enable(proc->hal.hw, true);
|
isp_ll_clk_enable(proc->hal.hw, true);
|
||||||
isp_ll_set_input_data_source(proc->hal.hw, proc_config->input_data_source);
|
isp_ll_set_input_data_source(proc->hal.hw, proc_config->input_data_source);
|
||||||
isp_ll_enable_line_start_packet_exist(proc->hal.hw, proc_config->has_line_start_packet);
|
isp_ll_enable_line_start_packet_exist(proc->hal.hw, proc_config->has_line_start_packet);
|
||||||
isp_ll_enable_line_end_packet_exist(proc->hal.hw, proc_config->has_line_end_packet);
|
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);
|
if (proc_config->flags.bypass_isp) {
|
||||||
|
/**
|
||||||
|
* When ISP bypass, input module is still working, input Hsize needs to be re-calculated
|
||||||
|
* according to input bits per pixel and IDI32.
|
||||||
|
* Hsize now stands for the number of 32-bit in one line.
|
||||||
|
*/
|
||||||
|
isp_ll_set_intput_data_h_pixel_num(proc->hal.hw, ISP_DIV_ROUND_UP(proc_config->h_res * in_bits_per_pixel, 32));
|
||||||
|
} else {
|
||||||
|
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_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_set_bayer_mode(proc->hal.hw, proc_config->bayer_order);
|
||||||
isp_ll_yuv_set_std(proc->hal.hw, proc_config->yuv_std);
|
isp_ll_yuv_set_std(proc->hal.hw, proc_config->yuv_std);
|
||||||
@@ -154,6 +172,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_
|
|||||||
proc->h_res = proc_config->h_res;
|
proc->h_res = proc_config->h_res;
|
||||||
proc->v_res = proc_config->v_res;
|
proc->v_res = proc_config->v_res;
|
||||||
proc->bayer_order = proc_config->bayer_order;
|
proc->bayer_order = proc_config->bayer_order;
|
||||||
|
proc->bypass_isp = proc_config->flags.bypass_isp;
|
||||||
|
|
||||||
*ret_proc = proc;
|
*ret_proc = proc;
|
||||||
|
|
||||||
@@ -209,6 +228,7 @@ esp_err_t esp_isp_enable(isp_proc_handle_t proc)
|
|||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(proc->isp_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
|
ESP_RETURN_ON_FALSE(proc->isp_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
|
||||||
|
ESP_RETURN_ON_FALSE(proc->bypass_isp == false, ESP_ERR_INVALID_STATE, TAG, "processor is configured to be bypassed");
|
||||||
|
|
||||||
isp_ll_enable(proc->hal.hw, true);
|
isp_ll_enable(proc->hal.hw, true);
|
||||||
proc->isp_fsm = ISP_FSM_ENABLE;
|
proc->isp_fsm = ISP_FSM_ENABLE;
|
||||||
|
@@ -104,6 +104,11 @@ If the configurations in :cpp:type:`esp_isp_processor_cfg_t` is specified, users
|
|||||||
|
|
||||||
You can use the created handle to enable/disable the ISP driver and do other ISP module installation.
|
You can use the created handle to enable/disable the ISP driver and do other ISP module installation.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
ISP peripheral is necessary if MIPI CSI or ISP_DVP is used as camera controller. This means even if ISP functions are not needed, you still need to install the ISP driver by calling :cpp:func:`esp_isp_new_processor`.
|
||||||
|
|
||||||
|
If ISP functions are not needed, ISP driver supports bypassing ISP pipelines and only necessary functions will be enabled. This can be done by setting :cpp:member:`esp_isp_processor_cfg_t::bypass_isp`.
|
||||||
|
|
||||||
Install ISP Auto Focus (AF) Driver
|
Install ISP Auto Focus (AF) Driver
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Reference in New Issue
Block a user