mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(isp): added isp driver framework and isp af driver
This commit is contained in:
parent
1ed64afddd
commit
bf1275d700
12
components/esp_driver_isp/CMakeLists.txt
Normal file
12
components/esp_driver_isp/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
set(srcs)
|
||||||
|
|
||||||
|
set(public_include "include")
|
||||||
|
|
||||||
|
if(CONFIG_SOC_ISP_SUPPORTED)
|
||||||
|
list(APPEND srcs "src/isp.c"
|
||||||
|
"src/isp_af.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
idf_component_register(SRCS ${srcs}
|
||||||
|
INCLUDE_DIRS ${public_include}
|
||||||
|
)
|
11
components/esp_driver_isp/Kconfig
Normal file
11
components/esp_driver_isp/Kconfig
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
menu "ESP-Driver:ISP Configurations"
|
||||||
|
depends on SOC_ISP_SUPPORTED
|
||||||
|
|
||||||
|
config ISP_ISR_IRAM_SAFE
|
||||||
|
bool "ISP driver ISR IRAM-Safe"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Ensure the ISP driver ISR is IRAM-Safe. When enabled, the ISR handler
|
||||||
|
will be available when the cache is disabled.
|
||||||
|
|
||||||
|
endmenu # ISP Configuration
|
87
components/esp_driver_isp/include/driver/isp.h
Normal file
87
components/esp_driver_isp/include/driver/isp.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* 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 "driver/isp_af.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ISP configurations
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
isp_clk_src_t clk_src; ///< Clock source
|
||||||
|
uint32_t clk_hz; ///< Clock frequency in Hz, suggest twice higher than cam sensor speed
|
||||||
|
isp_input_data_source_t input_data_source; ///< Input data source
|
||||||
|
isp_color_t input_data_color_type; ///< Input color type
|
||||||
|
isp_color_t output_data_color_type; ///< Output color type
|
||||||
|
bool has_line_start_packet; ///< Enable line start packet
|
||||||
|
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
|
||||||
|
} esp_isp_processor_cfg_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief New an ISP processor
|
||||||
|
*
|
||||||
|
* @param[in] proc_config Pointer to ISP config. Refer to ``esp_isp_processor_cfg_t``.
|
||||||
|
* @param[out] ret_proc Processor handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||||
|
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
|
||||||
|
* - ESP_ERR_NOT_SUPPORTED Not supported mode
|
||||||
|
* - ESP_ERR_NO_MEM If out of memory
|
||||||
|
*/
|
||||||
|
esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_proc_handle_t *ret_proc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an ISP processor
|
||||||
|
*
|
||||||
|
* @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_del_processor(isp_proc_handle_t proc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable an ISP processor
|
||||||
|
*
|
||||||
|
* @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_enable(isp_proc_handle_t proc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable an ISP processor
|
||||||
|
*
|
||||||
|
* @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_disable(isp_proc_handle_t proc);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
220
components/esp_driver_isp/include/driver/isp_af.h
Normal file
220
components/esp_driver_isp/include/driver/isp_af.h
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* 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 "driver/isp.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AF controller config
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
#if SOC_ISP_AF_WINDOW_NUMS
|
||||||
|
isp_af_window_t window[SOC_ISP_AF_WINDOW_NUMS]; ///< AF window settings
|
||||||
|
#endif
|
||||||
|
int edge_thresh; ///< Edge threshold, definition higher than this value will be counted as a valid pixel for calculating AF result
|
||||||
|
} esp_isp_af_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief New an ISP AF controller
|
||||||
|
*
|
||||||
|
* @param[in] isp_proc ISP Processor handle
|
||||||
|
* @param[in] af_config Pointer to AF config. Refer to ``esp_isp_af_config_t``.
|
||||||
|
* @param[out] ret_hdl AF controller handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||||
|
* - ESP_ERR_INVALID_STATE Invalid state
|
||||||
|
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
|
||||||
|
* - ESP_ERR_NO_MEM If out of memory
|
||||||
|
*/
|
||||||
|
esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an ISP AF controller
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller 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_del_af_controller(isp_af_ctrlr_t af_ctrlr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable an ISP AF controller
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller 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_af_controller_enable(isp_af_ctrlr_t af_ctrlr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable an ISP AF controller
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller 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_af_controller_disable(isp_af_ctrlr_t af_ctrlr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get AF result
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller handle
|
||||||
|
* @param[out] out_res AF result
|
||||||
|
*
|
||||||
|
* @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_af_controller_get_oneshot_result(isp_af_ctrlr_t af_ctrlr, isp_af_result_t *out_res);
|
||||||
|
|
||||||
|
/*---------------------------------------------
|
||||||
|
AF Env Monitor
|
||||||
|
----------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* @brief AF environment detector config
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int interval; ///< Interval between environment detection, in frames
|
||||||
|
} esp_isp_af_env_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event data structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
//empty for future proof
|
||||||
|
} esp_isp_af_env_detector_evt_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prototype of ISP AF Env detector event callback
|
||||||
|
*
|
||||||
|
* @param[in] handle ISP Env detector handle
|
||||||
|
* @param[in] edata ISP AF Env detector event data
|
||||||
|
* @param[in] user_data User registered context, registered when in `esp_isp_af_env_detector_register_event_callbacks()`
|
||||||
|
*
|
||||||
|
* @return Whether a high priority task is woken up by this function
|
||||||
|
*/
|
||||||
|
typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_env_detr_t detector, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Group of ISP AF Env detector callbacks
|
||||||
|
*
|
||||||
|
* @note These callbacks are all running in an ISR environment.
|
||||||
|
* @note When CONFIG_ISP_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||||
|
* Involved variables should be in internal RAM as well.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
esp_isp_af_env_detector_callback_t on_env_change; ///< Event callback, invoked when environment change happens.
|
||||||
|
} esp_isp_af_env_detector_evt_cbs_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief New an ISP AF environment detector
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller handle
|
||||||
|
* @param[in] config Pointer to AF env detector config. Refer to ``esp_isp_af_env_config_t``.
|
||||||
|
* @param[out] ret_hdl AF env detector handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||||
|
* - ESP_ERR_INVALID_STATE Invalid state
|
||||||
|
* - ESP_ERR_NO_MEM If out of memory
|
||||||
|
*/
|
||||||
|
esp_err_t esp_isp_new_af_env_detector(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_config_t *config, isp_af_env_detr_t *ret_hdl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an ISP AF environment detector
|
||||||
|
*
|
||||||
|
* @param[in] af_env_detector AF env detector 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_del_af_env_detector(isp_af_env_detr_t af_env_detector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable an ISP AF environment detector
|
||||||
|
*
|
||||||
|
* @param[in] af_env_detector AF env detector 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_af_env_detector_enable(isp_af_env_detr_t af_env_detector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable an ISP AF environment detector
|
||||||
|
*
|
||||||
|
* @param[in] af_env_detector AF env detector 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_af_env_detector_disable(isp_af_env_detr_t af_env_detector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set ISP AF environment detector detecting threshold
|
||||||
|
*
|
||||||
|
* @param[in] af_env_detector AF env detector handle
|
||||||
|
* @param[in] definition_thresh Threshold for definition
|
||||||
|
* @param[in] luminance_thresh Threshold for luminance
|
||||||
|
*
|
||||||
|
* @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_af_env_detector_set_threshold(isp_af_env_detr_t af_env_detector, int definition_thresh, int luminance_thresh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register AF environment detector event callbacks
|
||||||
|
*
|
||||||
|
* @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member in
|
||||||
|
* the `cbs` structure to NULL.
|
||||||
|
* @note When CONFIG_ISP_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||||
|
* Involved variables (including `user_data`) should be in internal RAM as well.
|
||||||
|
*
|
||||||
|
* @param[in] af_env_detector AF env detector handle
|
||||||
|
* @param[in] cbs Group of callback functions
|
||||||
|
* @param[in] user_data User data, which will be delivered to the callback functions directly
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK: On success
|
||||||
|
* - ESP_ERR_INVALID_ARG: Invalid arguments
|
||||||
|
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
|
||||||
|
*/
|
||||||
|
esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_env_detr_t af_env_detector, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
32
components/esp_driver_isp/include/driver/isp_types.h
Normal file
32
components/esp_driver_isp/include/driver/isp_types.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal/isp_types.h"
|
||||||
|
#include "hal/color_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of ISP processor handle
|
||||||
|
*/
|
||||||
|
typedef struct isp_processor_t *isp_proc_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of ISP AF controller handle
|
||||||
|
*/
|
||||||
|
typedef struct isp_af_controller_t *isp_af_ctrlr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of ISP AF Env detector handle
|
||||||
|
*/
|
||||||
|
typedef struct isp_af_env_detector_t *isp_af_env_detr_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
301
components/esp_driver_isp/src/isp.c
Normal file
301
components/esp_driver_isp/src/isp.c
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "esp_clk_tree.h"
|
||||||
|
#include "driver/isp.h"
|
||||||
|
#include "esp_private/periph_ctrl.h"
|
||||||
|
#include "esp_private/mipi_csi_share_hw_ctrl.h"
|
||||||
|
#include "hal/hal_utils.h"
|
||||||
|
#include "hal/isp_types.h"
|
||||||
|
#include "hal/isp_hal.h"
|
||||||
|
#include "hal/isp_ll.h"
|
||||||
|
#include "soc/mipi_csi_bridge_struct.h"
|
||||||
|
#include "soc/isp_periph.h"
|
||||||
|
#include "isp_internal.h"
|
||||||
|
|
||||||
|
#if CONFIG_ISP_ISR_IRAM_SAFE
|
||||||
|
#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM)
|
||||||
|
#else
|
||||||
|
#define ISP_INTR_ALLOC_FLAGS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_ISP_ISR_IRAM_SAFE
|
||||||
|
#define ISP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||||
|
#else
|
||||||
|
#define ISP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct isp_platform_t {
|
||||||
|
_lock_t mutex;
|
||||||
|
isp_processor_t *processors[SOC_ISP_NUMS];
|
||||||
|
} isp_platform_t;
|
||||||
|
|
||||||
|
static const char *TAG = "ISP";
|
||||||
|
static isp_platform_t s_platform;
|
||||||
|
|
||||||
|
static esp_err_t s_isp_claim_processor(isp_processor_t *proc)
|
||||||
|
{
|
||||||
|
assert(proc);
|
||||||
|
|
||||||
|
_lock_acquire(&s_platform.mutex);
|
||||||
|
bool found = false;
|
||||||
|
for (int i = 0; i < SOC_ISP_NUMS; i ++) {
|
||||||
|
found = !s_platform.processors[i];
|
||||||
|
if (found) {
|
||||||
|
s_platform.processors[i] = proc;
|
||||||
|
proc->proc_id = i;
|
||||||
|
PERIPH_RCC_ATOMIC() {
|
||||||
|
isp_ll_enable_module_clock(proc->hal.hw, true);
|
||||||
|
isp_ll_reset_module_clock(proc->hal.hw);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_lock_release(&s_platform.mutex);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t s_isp_declaim_processor(isp_processor_t *proc)
|
||||||
|
{
|
||||||
|
assert(proc);
|
||||||
|
|
||||||
|
_lock_acquire(&s_platform.mutex);
|
||||||
|
s_platform.processors[proc->proc_id] = NULL;
|
||||||
|
PERIPH_RCC_ATOMIC() {
|
||||||
|
isp_ll_enable_module_clock(proc->hal.hw, false);
|
||||||
|
}
|
||||||
|
_lock_release(&s_platform.mutex);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_proc_handle_t *ret_proc)
|
||||||
|
{
|
||||||
|
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->input_data_source == ISP_INPUT_DATA_SOURCE_CSI, ESP_ERR_NOT_SUPPORTED, TAG, "only support CSI as input source at this moment");
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
//claim a processor, then do assignment
|
||||||
|
ESP_GOTO_ON_ERROR(s_isp_claim_processor(proc), err, TAG, "no available isp processor");
|
||||||
|
#if SOC_ISP_SHARE_CSI_BRG
|
||||||
|
ESP_GOTO_ON_ERROR(mipi_csi_brg_claim(MIPI_CSI_BRG_USER_SHARE, &proc->csi_brg_id), err, TAG, "csi bridge is in use already");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
isp_clk_src_t clk_src = !proc_config->clk_src ? ISP_CLK_SRC_DEFAULT : proc_config->clk_src;
|
||||||
|
uint32_t clk_src_freq_hz = 0;
|
||||||
|
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz), err, TAG, "clock source setting fail");
|
||||||
|
ESP_GOTO_ON_FALSE((proc_config->clk_hz > 0 && proc_config->clk_hz <= clk_src_freq_hz), ESP_ERR_INVALID_ARG, err, TAG, "clk hz not supported");
|
||||||
|
|
||||||
|
uint32_t out_clk_freq_hz = 0;
|
||||||
|
hal_utils_clk_div_t clk_div = {};
|
||||||
|
hal_utils_clk_info_t clk_info = {
|
||||||
|
.src_freq_hz = clk_src_freq_hz,
|
||||||
|
.exp_freq_hz = proc_config->clk_hz,
|
||||||
|
.max_integ = ISP_LL_TX_MAX_CLK_INT_DIV,
|
||||||
|
.min_integ = 1,
|
||||||
|
.round_opt = HAL_DIV_ROUND,
|
||||||
|
};
|
||||||
|
out_clk_freq_hz = hal_utils_calc_clk_div_integer(&clk_info, &clk_div.integer);
|
||||||
|
if (out_clk_freq_hz != proc_config->clk_hz) {
|
||||||
|
ESP_LOGW(TAG, "precision loss, real output frequency: %"PRIu32"Hz", out_clk_freq_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
isp_hal_init(&proc->hal, proc->proc_id);
|
||||||
|
//necessary ISP submodules that needs basic initialisation
|
||||||
|
isp_ll_bf_clk_enable(proc->hal.hw, true);
|
||||||
|
isp_ll_bf_enable(proc->hal.hw, true);
|
||||||
|
isp_ll_ccm_clk_enable(proc->hal.hw, true);
|
||||||
|
isp_ll_ccm_enable(proc->hal.hw, true);
|
||||||
|
isp_ll_color_clk_enable(proc->hal.hw, true);
|
||||||
|
isp_ll_color_enable(proc->hal.hw, true);
|
||||||
|
PERIPH_RCC_ATOMIC() {
|
||||||
|
isp_ll_select_clk_source(proc->hal.hw, clk_src);
|
||||||
|
isp_ll_set_clock_div(proc->hal.hw, &clk_div);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc->isp_fsm = ISP_FSM_INIT;
|
||||||
|
proc->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
|
//Input color format
|
||||||
|
bool valid_format = false;
|
||||||
|
color_space_pixel_format_t in_color_format = {
|
||||||
|
.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_type_id = proc_config->output_data_color_type,
|
||||||
|
};
|
||||||
|
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_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_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);
|
||||||
|
|
||||||
|
*ret_proc = proc;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(proc);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_del_processor(isp_proc_handle_t proc)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
//declaim first, then do free
|
||||||
|
ESP_RETURN_ON_ERROR(s_isp_declaim_processor(proc), TAG, "declaim processor fail");
|
||||||
|
#if SOC_ISP_SHARE_CSI_BRG
|
||||||
|
ESP_RETURN_ON_ERROR(mipi_csi_brg_declaim(proc->csi_brg_id), TAG, "declaim csi bridge fail");
|
||||||
|
#endif
|
||||||
|
free(proc);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->isp_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state");
|
||||||
|
|
||||||
|
isp_ll_enable(proc->hal.hw, true);
|
||||||
|
proc->isp_fsm = ISP_FSM_ENABLE;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_disable(isp_proc_handle_t proc)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(proc->isp_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "processor isn't in enable state");
|
||||||
|
|
||||||
|
isp_ll_enable(proc->hal.hw, false);
|
||||||
|
proc->isp_fsm = ISP_FSM_INIT;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
INTR
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
static void IRAM_ATTR s_isp_isr_dispatcher(void *arg)
|
||||||
|
{
|
||||||
|
isp_processor_t *proc = (isp_processor_t *)arg;
|
||||||
|
bool need_yield = false;
|
||||||
|
|
||||||
|
//Check and clear hw events
|
||||||
|
uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK);
|
||||||
|
|
||||||
|
bool do_dispatch = false;
|
||||||
|
//Deal with hw events
|
||||||
|
if (af_events) {
|
||||||
|
portENTER_CRITICAL_ISR(&proc->spinlock);
|
||||||
|
do_dispatch = proc->af_isr_added;
|
||||||
|
portEXIT_CRITICAL_ISR(&proc->spinlock);
|
||||||
|
|
||||||
|
if (do_dispatch) {
|
||||||
|
need_yield |= esp_isp_af_isr(proc, af_events);
|
||||||
|
}
|
||||||
|
do_dispatch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_yield) {
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
|
||||||
|
bool do_alloc = false;
|
||||||
|
portENTER_CRITICAL(&proc->spinlock);
|
||||||
|
proc->isr_ref_counts++;
|
||||||
|
if (proc->isr_ref_counts == 1) {
|
||||||
|
assert(!proc->intr_hdl);
|
||||||
|
do_alloc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (submodule) {
|
||||||
|
case ISP_SUBMODULE_AF:
|
||||||
|
proc->af_isr_added = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&proc->spinlock);
|
||||||
|
|
||||||
|
if (do_alloc) {
|
||||||
|
ret = esp_intr_alloc(isp_hw_info.instances[proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS, s_isp_isr_dispatcher, (void *)proc, &proc->intr_hdl);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "no intr source");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
esp_intr_enable(proc->intr_hdl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_deregister_isr(isp_proc_handle_t proc, isp_submodule_t submodule)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
|
||||||
|
bool do_free = false;
|
||||||
|
portENTER_CRITICAL(&proc->spinlock);
|
||||||
|
proc->isr_ref_counts--;
|
||||||
|
assert(proc->isr_ref_counts >= 0);
|
||||||
|
if (proc->isr_ref_counts == 0) {
|
||||||
|
assert(proc->intr_hdl);
|
||||||
|
do_free = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (submodule) {
|
||||||
|
case ISP_SUBMODULE_AF:
|
||||||
|
proc->af_isr_added = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&proc->spinlock);
|
||||||
|
|
||||||
|
if (do_free) {
|
||||||
|
esp_intr_disable(proc->intr_hdl);
|
||||||
|
ret = esp_intr_free(proc->intr_hdl);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
330
components/esp_driver_isp/src/isp_af.c
Normal file
330
components/esp_driver_isp/src/isp_af.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "driver/isp.h"
|
||||||
|
#include "hal/isp_hal.h"
|
||||||
|
#include "hal/isp_ll.h"
|
||||||
|
#include "isp_internal.h"
|
||||||
|
|
||||||
|
#if CONFIG_ISP_ISR_IRAM_SAFE
|
||||||
|
#define ISP_AF_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||||
|
#else
|
||||||
|
#define ISP_AF_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *TAG = "ISP_AF";
|
||||||
|
|
||||||
|
/*---------------------------------------------
|
||||||
|
AF
|
||||||
|
----------------------------------------------*/
|
||||||
|
static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_controller_t *af_ctlr)
|
||||||
|
{
|
||||||
|
assert(isp_proc && af_ctlr);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
portENTER_CRITICAL(&isp_proc->spinlock);
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) {
|
||||||
|
found = !isp_proc->af_ctlr[i];
|
||||||
|
if (found) {
|
||||||
|
isp_proc->af_ctlr[i] = af_ctlr;
|
||||||
|
af_ctlr->id = i;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&isp_proc->spinlock);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t s_isp_declaim_af_controller(isp_af_controller_t *af_ctlr)
|
||||||
|
{
|
||||||
|
assert(af_ctlr && af_ctlr->isp_proc);
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&af_ctlr->isp_proc->spinlock);
|
||||||
|
af_ctlr->isp_proc->af_ctlr[af_ctlr->id] = NULL;
|
||||||
|
portEXIT_CRITICAL(&af_ctlr->isp_proc->spinlock);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
ESP_RETURN_ON_FALSE(isp_proc && af_config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
|
||||||
|
bool rgb2yuv_en = isp_ll_is_rgb2yuv_enabled(isp_proc->hal.hw);
|
||||||
|
bool demosaic_en = isp_ll_is_demosaic_enabled(isp_proc->hal.hw);
|
||||||
|
ESP_RETURN_ON_FALSE(demosaic_en && rgb2yuv_en, ESP_ERR_INVALID_STATE, TAG, "RGB2YUV not enabled, please update the output_data_color_type");
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_WINDOW_NUMS; i++) {
|
||||||
|
ESP_LOGV(TAG, "af_config->window[%d].top_left_x: %"PRId32, i, af_config->window[i].top_left_x);
|
||||||
|
ESP_LOGV(TAG, "af_config->window[%d].bottom_right_x: %"PRId32, i, af_config->window[i].bottom_right_x);
|
||||||
|
ESP_LOGV(TAG, "af_config->window[%d].bottom_right_y: %"PRId32, i, af_config->window[i].bottom_right_y);
|
||||||
|
ESP_LOGV(TAG, "af_config->window[%d].top_left_y: %"PRId32, i, af_config->window[i].top_left_y);
|
||||||
|
|
||||||
|
ESP_RETURN_ON_FALSE(((af_config->window[i].top_left_x < ISP_LL_AF_WINDOW_MAX_RANGE) &&
|
||||||
|
(af_config->window[i].bottom_right_x >= af_config->window[i].top_left_x) &&
|
||||||
|
(af_config->window[i].bottom_right_x < ISP_LL_AF_WINDOW_MAX_RANGE) &&
|
||||||
|
(af_config->window[i].top_left_y < ISP_LL_AF_WINDOW_MAX_RANGE) &&
|
||||||
|
(af_config->window[i].bottom_right_y >= af_config->window[i].top_left_y) &&
|
||||||
|
(af_config->window[i].bottom_right_y < ISP_LL_AF_WINDOW_MAX_RANGE)), ESP_ERR_INVALID_ARG, TAG, "invalid window");
|
||||||
|
}
|
||||||
|
ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0");
|
||||||
|
|
||||||
|
isp_af_controller_t *af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_AF_MEM_ALLOC_CAPS);
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem");
|
||||||
|
|
||||||
|
//claim an AF controller
|
||||||
|
ESP_GOTO_ON_ERROR(s_isp_claim_af_controller(isp_proc, af_ctlr), err, TAG, "no available controller");
|
||||||
|
|
||||||
|
af_ctlr->fsm = ISP_FSM_INIT;
|
||||||
|
af_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
af_ctlr->isp_proc = isp_proc;
|
||||||
|
|
||||||
|
isp_ll_af_enable_auto_update(isp_proc->hal.hw, false);
|
||||||
|
isp_ll_af_enable(isp_proc->hal.hw, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_WINDOW_NUMS; i++) {
|
||||||
|
isp_hal_af_window_config(&isp_proc->hal, i, &af_config->window[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
isp_ll_af_set_edge_thresh_mode(isp_proc->hal.hw, ISP_LL_AF_EDGE_MONITOR_MODE_MANUAL);
|
||||||
|
isp_ll_af_set_edge_thresh(isp_proc->hal.hw, af_config->edge_thresh);
|
||||||
|
isp_ll_clear_intr(isp_proc->hal.hw, ISP_LL_EVENT_AF_MASK);
|
||||||
|
|
||||||
|
*ret_hdl = af_ctlr;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(af_ctlr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_ERROR(s_isp_declaim_af_controller(af_ctlr), TAG, "controller isn't in use");
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state");
|
||||||
|
|
||||||
|
free(af_ctlr);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state");
|
||||||
|
|
||||||
|
isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, true);
|
||||||
|
isp_ll_af_enable(af_ctlr->isp_proc->hal.hw, true);
|
||||||
|
af_ctlr->fsm = ISP_FSM_ENABLE;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state");
|
||||||
|
|
||||||
|
isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, false);
|
||||||
|
isp_ll_af_enable(af_ctlr->isp_proc->hal.hw, false);
|
||||||
|
af_ctlr->fsm = ISP_FSM_INIT;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_controller_get_oneshot_result(isp_af_ctrlr_t af_ctlr, isp_af_result_t *out_res)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE_ISR(af_ctlr && out_res, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE_ISR(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state");
|
||||||
|
|
||||||
|
isp_hal_af_get_oneshot_result(&af_ctlr->isp_proc->hal, out_res);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------
|
||||||
|
AF Env Monitor
|
||||||
|
----------------------------------------------*/
|
||||||
|
static esp_err_t s_isp_claim_af_env_detector(isp_af_ctrlr_t af_ctlr, isp_af_env_detector_t *af_env_detector)
|
||||||
|
{
|
||||||
|
assert(af_ctlr && af_env_detector);
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
portENTER_CRITICAL(&af_ctlr->spinlock);
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_ENV_DETECTOR_NUMS; i++) {
|
||||||
|
found = !af_ctlr->af_env_detector[i];
|
||||||
|
if (found) {
|
||||||
|
af_ctlr->af_env_detector[i] = af_env_detector;
|
||||||
|
af_env_detector->id = i;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&af_ctlr->spinlock);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t s_isp_declaim_af_env_detector(isp_af_env_detector_t *af_env_detector)
|
||||||
|
{
|
||||||
|
assert(af_env_detector && af_env_detector->af_ctlr);
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&af_env_detector->af_ctlr->spinlock);
|
||||||
|
af_env_detector->af_ctlr->af_env_detector[af_env_detector->id] = NULL;
|
||||||
|
portEXIT_CRITICAL(&af_env_detector->af_ctlr->spinlock);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_new_af_env_detector(isp_af_ctrlr_t af_ctlr, const esp_isp_af_env_config_t *config, isp_af_env_detr_t *ret_hdl)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr && config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
|
||||||
|
isp_af_env_detector_t *af_env_detector = heap_caps_calloc(1, sizeof(isp_af_env_detector_t), ISP_AF_MEM_ALLOC_CAPS);
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector, ESP_ERR_NO_MEM, TAG, "no mem");
|
||||||
|
|
||||||
|
//claim an AF Env detector
|
||||||
|
ESP_GOTO_ON_ERROR(s_isp_claim_af_env_detector(af_ctlr, af_env_detector), err, TAG, "no available env detector");
|
||||||
|
|
||||||
|
af_env_detector->fsm = ISP_FSM_INIT;
|
||||||
|
af_env_detector->config.interval = config->interval;
|
||||||
|
af_env_detector->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
af_env_detector->af_ctlr = af_ctlr;
|
||||||
|
|
||||||
|
isp_ll_af_env_monitor_set_period(af_ctlr->isp_proc->hal.hw, 0);
|
||||||
|
isp_ll_clear_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV);
|
||||||
|
|
||||||
|
*ret_hdl = af_env_detector;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(af_env_detector);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_del_af_env_detector(isp_af_env_detr_t af_env_detector)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector && af_env_detector->af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_ERROR(s_isp_declaim_af_env_detector(af_env_detector), TAG, "detector isn't in use");
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in init state");
|
||||||
|
|
||||||
|
free(af_env_detector);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_env_detector_enable(isp_af_env_detr_t af_env_detector)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector && af_env_detector->af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in init state");
|
||||||
|
|
||||||
|
//try use ratio mode
|
||||||
|
isp_ll_af_env_monitor_set_mode(af_env_detector->af_ctlr->isp_proc->hal.hw, ISP_LL_AF_ENV_MONITOR_MODE_ABS);
|
||||||
|
isp_ll_af_env_monitor_set_period(af_env_detector->af_ctlr->isp_proc->hal.hw, af_env_detector->config.interval);
|
||||||
|
isp_ll_enable_intr(af_env_detector->af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV, true);
|
||||||
|
af_env_detector->fsm = ISP_FSM_ENABLE;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_env_detector_disable(isp_af_env_detr_t af_env_detector)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector && af_env_detector->af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state");
|
||||||
|
|
||||||
|
isp_ll_af_env_monitor_set_period(af_env_detector->af_ctlr->isp_proc->hal.hw, 0);
|
||||||
|
af_env_detector->fsm = ISP_FSM_INIT;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_env_detr_t af_env_detector, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
|
ESP_RETURN_ON_FALSE(af_env_detector->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state");
|
||||||
|
|
||||||
|
#if CONFIG_ISP_ISR_IRAM_SAFE
|
||||||
|
if (cbs->on_env_change) {
|
||||||
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_env_change), ESP_ERR_INVALID_ARG, TAG, "on_env_change callback not in IRAM");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ESP_RETURN_ON_ERROR(esp_isp_register_isr(af_env_detector->af_ctlr->isp_proc, ISP_SUBMODULE_AF), TAG, "fail to register ISR");
|
||||||
|
|
||||||
|
af_env_detector->cbs.on_env_change = cbs->on_env_change;
|
||||||
|
af_env_detector->user_data = user_data;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_isp_af_env_detector_set_threshold(isp_af_env_detr_t af_env_detector, int definition_thresh, int luminance_thresh)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE_ISR(af_env_detector, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
|
ESP_RETURN_ON_FALSE_ISR(af_env_detector->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state");
|
||||||
|
|
||||||
|
isp_ll_af_env_monitor_set_thresh(af_env_detector->af_ctlr->isp_proc->hal.hw, definition_thresh, luminance_thresh);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
INTR
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
static bool IRAM_ATTR s_af_env_isr(isp_af_env_detector_t *detector)
|
||||||
|
{
|
||||||
|
bool need_yield = false;
|
||||||
|
|
||||||
|
esp_isp_af_env_detector_evt_data_t edata = {};
|
||||||
|
if (detector->cbs.on_env_change(detector, &edata, detector->user_data)) {
|
||||||
|
need_yield |= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return need_yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRAM_ATTR esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* HW events are cleared in the ISP ISR dispatcher.
|
||||||
|
* We only deal with HW events
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool need_yield = false;
|
||||||
|
|
||||||
|
if (af_events & ISP_LL_EVENT_AF_ENV) {
|
||||||
|
/**
|
||||||
|
* Now only one detector.
|
||||||
|
* Should decide a detector instance according to the hw event.
|
||||||
|
*/
|
||||||
|
isp_af_env_detector_t *detector = proc->af_ctlr[0]->af_env_detector[0];
|
||||||
|
|
||||||
|
need_yield |= s_af_env_isr(detector);
|
||||||
|
}
|
||||||
|
|
||||||
|
return need_yield;
|
||||||
|
}
|
90
components/esp_driver_isp/src/isp_internal.h
Normal file
90
components/esp_driver_isp/src/isp_internal.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_intr_alloc.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "hal/isp_hal.h"
|
||||||
|
#include "hal/isp_types.h"
|
||||||
|
#include "soc/isp_periph.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ISP_FSM_INIT,
|
||||||
|
ISP_FSM_ENABLE,
|
||||||
|
} isp_fsm_t;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
Driver Context
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
typedef enum {
|
||||||
|
ISP_SUBMODULE_AF,
|
||||||
|
} isp_submodule_t;
|
||||||
|
|
||||||
|
typedef struct isp_af_env_detector_t isp_af_env_detector_t;
|
||||||
|
typedef struct isp_af_controller_t isp_af_controller_t;
|
||||||
|
typedef struct isp_processor_t isp_processor_t;
|
||||||
|
|
||||||
|
struct isp_af_env_detector_t {
|
||||||
|
int id;
|
||||||
|
isp_fsm_t fsm;
|
||||||
|
esp_isp_af_env_config_t config;
|
||||||
|
portMUX_TYPE spinlock;
|
||||||
|
esp_isp_af_env_detector_evt_cbs_t cbs;
|
||||||
|
void *user_data;
|
||||||
|
isp_af_controller_t *af_ctlr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct isp_af_controller_t {
|
||||||
|
int id;
|
||||||
|
isp_fsm_t fsm;
|
||||||
|
portMUX_TYPE spinlock;
|
||||||
|
isp_processor_t *isp_proc;
|
||||||
|
isp_af_env_detector_t *af_env_detector[SOC_ISP_AF_ENV_DETECTOR_NUMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct isp_processor_t {
|
||||||
|
int proc_id;
|
||||||
|
isp_hal_context_t hal;
|
||||||
|
#if SOC_ISP_SHARE_CSI_BRG
|
||||||
|
int csi_brg_id;
|
||||||
|
void *csi_brg_hw;
|
||||||
|
#endif
|
||||||
|
isp_fsm_t isp_fsm;
|
||||||
|
portMUX_TYPE spinlock;
|
||||||
|
intr_handle_t intr_hdl;
|
||||||
|
|
||||||
|
/* sub module contexts */
|
||||||
|
isp_af_controller_t *af_ctlr[SOC_ISP_AF_CTLR_NUMS];
|
||||||
|
|
||||||
|
/* should be accessed within isp_processor_t spinlock */
|
||||||
|
int isr_ref_counts;
|
||||||
|
bool af_isr_added;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
INTR
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule);
|
||||||
|
esp_err_t esp_isp_deregister_isr(isp_proc_handle_t proc, isp_submodule_t submodule);
|
||||||
|
bool esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,5 @@
|
|||||||
|
components/esp_driver_isp/test_apps/isp:
|
||||||
|
disable:
|
||||||
|
- if: SOC_ISP_SUPPORTED != 1
|
||||||
|
depends_components:
|
||||||
|
- esp_driver_isp
|
8
components/esp_driver_isp/test_apps/isp/CMakeLists.txt
Normal file
8
components/esp_driver_isp/test_apps/isp/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||||
|
|
||||||
|
set(COMPONENTS main)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(test_isp)
|
2
components/esp_driver_isp/test_apps/isp/README.md
Normal file
2
components/esp_driver_isp/test_apps/isp/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
| Supported Targets | ESP32-P4 |
|
||||||
|
| ----------------- | -------- |
|
16
components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt
Normal file
16
components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
set(srcs "test_app_main.c"
|
||||||
|
"test_isp_driver.c")
|
||||||
|
|
||||||
|
if(CONFIG_SOC_ISP_SHARE_CSI_BRG)
|
||||||
|
list(APPEND srcs "test_isp_csi.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(priv_requires
|
||||||
|
unity
|
||||||
|
esp_driver_isp
|
||||||
|
)
|
||||||
|
|
||||||
|
idf_component_register(SRCS ${srcs}
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
PRIV_REQUIRES ${priv_requires}
|
||||||
|
WHOLE_ARCHIVE TRUE)
|
40
components/esp_driver_isp/test_apps/isp/main/test_app_main.c
Normal file
40
components/esp_driver_isp/test_apps/isp/main/test_app_main.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "unity.h"
|
||||||
|
#include "unity_test_utils.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#define TEST_MEMORY_LEAK_THRESHOLD (400)
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
unity_utils_record_free_mem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
____________________ ___________
|
||||||
|
/_ __/ __/ __/_ __/ / _/ __/ _ \
|
||||||
|
/ / / _/_\ \ / / _/ /_\ \/ ___/
|
||||||
|
/_/ /___/___/ /_/ /___/___/_/
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
printf(" ____________________ ___________\n");
|
||||||
|
printf("/_ __/ __/ __/_ __/ / _/ __/ _ \\\n");
|
||||||
|
printf(" / / / _/_\\ \\ / / _/ /_\\ \\/ ___/\n");
|
||||||
|
printf("/_/ /___/___/ /_/ /___/___/_/\n");
|
||||||
|
|
||||||
|
unity_run_menu();
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "driver/isp.h"
|
||||||
|
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
|
||||||
|
TEST_CASE("ISP processor exhausted allocation", "[isp]")
|
||||||
|
{
|
||||||
|
esp_isp_processor_cfg_t isp_config = {
|
||||||
|
.clk_hz = 80 * 1000 * 1000,
|
||||||
|
.input_data_source = ISP_INPUT_DATA_SOURCE_CSI,
|
||||||
|
.input_data_color_type = ISP_COLOR_RAW8,
|
||||||
|
.output_data_color_type = ISP_COLOR_RGB565,
|
||||||
|
};
|
||||||
|
isp_proc_t isp_proc[SOC_ISP_NUMS + 1] = {};
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc[i]));
|
||||||
|
esp_rom_printf("first alloc ok\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT(esp_isp_new_processor(&isp_config, &isp_proc[SOC_ISP_NUMS]) == ESP_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_del_processor(isp_proc[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ISP AF controller exhausted allocation", "[isp]")
|
||||||
|
{
|
||||||
|
esp_isp_processor_cfg_t isp_config = {
|
||||||
|
.clk_hz = 80 * 1000 * 1000,
|
||||||
|
.input_data_source = ISP_INPUT_DATA_SOURCE_CSI,
|
||||||
|
.input_data_color_type = ISP_COLOR_RAW8,
|
||||||
|
.output_data_color_type = ISP_COLOR_RGB565,
|
||||||
|
};
|
||||||
|
isp_proc_t isp_proc = NULL;
|
||||||
|
TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc));
|
||||||
|
|
||||||
|
esp_isp_af_config_t af_config = {
|
||||||
|
.edge_thresh = 128,
|
||||||
|
};
|
||||||
|
isp_af_ctrlr_t af_ctrlr[SOC_ISP_AF_CTLR_NUMS + 1] = {};
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr[SOC_ISP_AF_CTLR_NUMS]) == ESP_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_del_af_controller(af_ctrlr[i]));
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(esp_isp_del_processor(isp_proc));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ISP AF env detector exhausted allocation", "[isp]")
|
||||||
|
{
|
||||||
|
esp_isp_processor_cfg_t isp_config = {
|
||||||
|
.clk_hz = 80 * 1000 * 1000,
|
||||||
|
.input_data_source = ISP_INPUT_DATA_SOURCE_CSI,
|
||||||
|
.input_data_color_type = ISP_COLOR_RAW8,
|
||||||
|
.output_data_color_type = ISP_COLOR_RGB565,
|
||||||
|
};
|
||||||
|
isp_proc_t isp_proc = NULL;
|
||||||
|
TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc));
|
||||||
|
|
||||||
|
esp_isp_af_config_t af_config = {
|
||||||
|
.edge_thresh = 128,
|
||||||
|
};
|
||||||
|
isp_af_ctrlr_t af_ctrlr = NULL;
|
||||||
|
TEST_ESP_OK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr));
|
||||||
|
|
||||||
|
esp_isp_af_env_config_t env_config = {
|
||||||
|
.interval = 10,
|
||||||
|
};
|
||||||
|
isp_af_env_detr_t env_detector[SOC_ISP_AF_ENV_DETECTOR_NUMS + 1] = {};
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_ENV_DETECTOR_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_new_af_env_detector(af_ctrlr, &env_config, &env_detector[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT(esp_isp_new_af_env_detector(af_ctrlr, &env_config, &env_detector[SOC_ISP_AF_ENV_DETECTOR_NUMS]) == ESP_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
for (int i = 0; i < SOC_ISP_AF_ENV_DETECTOR_NUMS; i++) {
|
||||||
|
TEST_ESP_OK(esp_isp_del_af_env_detector(env_detector[i]));
|
||||||
|
}
|
||||||
|
TEST_ESP_OK(esp_isp_del_af_controller(af_ctrlr));
|
||||||
|
TEST_ESP_OK(esp_isp_del_processor(isp_proc));
|
||||||
|
}
|
7
components/esp_driver_isp/test_apps/isp/pytest_isp.py
Normal file
7
components/esp_driver_isp/test_apps/isp/pytest_isp.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
from pytest_embedded_idf import IdfDut
|
||||||
|
|
||||||
|
|
||||||
|
def test_isp(dut: IdfDut) -> None:
|
||||||
|
dut.run_all_single_board_cases()
|
@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_ESP_TASK_WDT_EN=n
|
@ -73,6 +73,7 @@ esp_err_t mipi_csi_brg_declaim(int id)
|
|||||||
|
|
||||||
s_ctx.ref_cnt[id]--;
|
s_ctx.ref_cnt[id]--;
|
||||||
if (s_ctx.ref_cnt[id] < 0) {
|
if (s_ctx.ref_cnt[id] < 0) {
|
||||||
|
s_ctx.ref_cnt[id] = 0;
|
||||||
portEXIT_CRITICAL(&s_ctx.spinlock);
|
portEXIT_CRITICAL(&s_ctx.spinlock);
|
||||||
ESP_LOGE(TAG, "%s called, but s_ctx.ref_cnt[%d] == 0", __func__, id);
|
ESP_LOGE(TAG, "%s called, but s_ctx.ref_cnt[%d] == 0", __func__, id);
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
0
components/hal/esp32p4/include/hal/clk_gate_ll.h
Normal file
0
components/hal/esp32p4/include/hal/clk_gate_ll.h
Normal file
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -10,6 +10,7 @@
|
|||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
|
#include "hal/hal_utils.h"
|
||||||
#include "hal/isp_types.h"
|
#include "hal/isp_types.h"
|
||||||
#include "hal/color_types.h"
|
#include "hal/color_types.h"
|
||||||
#include "soc/isp_struct.h"
|
#include "soc/isp_struct.h"
|
||||||
@ -23,6 +24,11 @@ extern "C" {
|
|||||||
|
|
||||||
#define ISP_LL_GET_HW(num) (((num) == 0) ? (&ISP) : NULL)
|
#define ISP_LL_GET_HW(num) (((num) == 0) ? (&ISP) : NULL)
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
Clock
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
#define ISP_LL_TX_MAX_CLK_INT_DIV 0x100
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------
|
/*---------------------------------------------------------------
|
||||||
INTR
|
INTR
|
||||||
@ -151,11 +157,12 @@ static inline void isp_ll_select_clk_source(isp_dev_t *hw, soc_periph_isp_clk_sr
|
|||||||
* @brief Set ISP clock div
|
* @brief Set ISP clock div
|
||||||
*
|
*
|
||||||
* @param hw Hardware instance address
|
* @param hw Hardware instance address
|
||||||
* @param div divider value
|
* @param div Clock division with integral and decimal part
|
||||||
*/
|
*/
|
||||||
static inline void isp_ll_set_clock_div(isp_dev_t *hw, uint32_t div)
|
static inline void isp_ll_set_clock_div(isp_dev_t *hw, const hal_utils_clk_div_t *clk_div)
|
||||||
{
|
{
|
||||||
HP_SYS_CLKRST.peri_clk_ctrl26.reg_isp_clk_div_num = div;
|
HAL_ASSERT(clk_div->integer > 0 && clk_div->integer <= ISP_LL_TX_MAX_CLK_INT_DIV);
|
||||||
|
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl26, reg_isp_clk_div_num, clk_div->integer - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||||
@ -518,6 +525,7 @@ static inline void isp_ll_af_set_window_range(isp_dev_t *hw, uint32_t window_id,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
HAL_ASSERT(false);
|
HAL_ASSERT(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,6 +548,7 @@ static inline uint32_t isp_ll_af_get_window_sum(isp_dev_t *hw, uint32_t window_i
|
|||||||
return hw->af_sum_c.af_sumc;
|
return hw->af_sum_c.af_sumc;
|
||||||
default:
|
default:
|
||||||
HAL_ASSERT(false);
|
HAL_ASSERT(false);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,6 +571,7 @@ static inline uint32_t isp_ll_af_get_window_lum(isp_dev_t *hw, uint32_t window_i
|
|||||||
return hw->af_lum_c.af_lumc;
|
return hw->af_lum_c.af_lumc;
|
||||||
default:
|
default:
|
||||||
HAL_ASSERT(false);
|
HAL_ASSERT(false);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,10 @@ if(CONFIG_SOC_SDM_SUPPORTED)
|
|||||||
list(APPEND srcs "${target_folder}/sdm_periph.c")
|
list(APPEND srcs "${target_folder}/sdm_periph.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_SOC_ISP_SUPPORTED)
|
||||||
|
list(APPEND srcs "${target}/isp_periph.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CONFIG_SOC_I2S_SUPPORTED)
|
if(CONFIG_SOC_I2S_SUPPORTED)
|
||||||
list(APPEND srcs "${target_folder}/i2s_periph.c")
|
list(APPEND srcs "${target_folder}/i2s_periph.c")
|
||||||
endif()
|
endif()
|
||||||
|
@ -127,6 +127,10 @@ config SOC_LEDC_SUPPORTED
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_ISP_SUPPORTED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_I2C_SUPPORTED
|
config SOC_I2C_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#define SOC_SDM_SUPPORTED 1
|
#define SOC_SDM_SUPPORTED 1
|
||||||
#define SOC_GPSPI_SUPPORTED 1
|
#define SOC_GPSPI_SUPPORTED 1
|
||||||
#define SOC_LEDC_SUPPORTED 1
|
#define SOC_LEDC_SUPPORTED 1
|
||||||
|
#define SOC_ISP_SUPPORTED 1
|
||||||
#define SOC_I2C_SUPPORTED 1
|
#define SOC_I2C_SUPPORTED 1
|
||||||
#define SOC_SYSTIMER_SUPPORTED 1
|
#define SOC_SYSTIMER_SUPPORTED 1
|
||||||
#define SOC_AES_SUPPORTED 1
|
#define SOC_AES_SUPPORTED 1
|
||||||
|
24
components/soc/esp32p4/isp_periph.c
Normal file
24
components/soc/esp32p4/isp_periph.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "soc/periph_defs.h"
|
||||||
|
#include "soc/isp_periph.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const isp_info_t isp_hw_info = {
|
||||||
|
.instances = {
|
||||||
|
[0] = {
|
||||||
|
.irq = ETS_ISP_INTR_SOURCE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
29
components/soc/include/soc/isp_periph.h
Normal file
29
components/soc/include/soc/isp_periph.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
#include "soc/periph_defs.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SOC_ISP_SUPPORTED
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
const uint32_t irq;
|
||||||
|
} instances[SOC_ISP_NUMS];
|
||||||
|
} isp_info_t;
|
||||||
|
|
||||||
|
extern const isp_info_t isp_hw_info;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "isp_af_scheme.h"
|
||||||
|
#include "driver/isp_af.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
ISP AF Step Approximation Scheme (SA Scheme)
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
int first_step_val; ///< Step of the camera sensor focus value for first stage approximation
|
||||||
|
int first_approx_cycles; ///< First stage approximation cycles
|
||||||
|
int second_step_val; ///< Step of the camera sensor focus value for second stage approximation
|
||||||
|
int second_approx_cycles; ///< Second stage approximation cycles
|
||||||
|
} isp_af_sa_scheme_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int focus_val_max; ///< Max camera sensor focus value
|
||||||
|
} isp_af_sa_scheme_sensor_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief Sensor driver API to set sensor focus value
|
||||||
|
*
|
||||||
|
* @param[in] focus_val Camera sensor focus value
|
||||||
|
*/
|
||||||
|
esp_err_t (*af_sensor_set_focus)(int focus_val);
|
||||||
|
|
||||||
|
} isp_af_sa_scheme_sensor_drv_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create an AF step approximation scheme
|
||||||
|
*
|
||||||
|
* @param[in] af_ctrlr AF controller handle
|
||||||
|
* @param[in] config AF SA scheme configurations, see `isp_af_sa_scheme_config_t`
|
||||||
|
* @param[out] ret_scheme AF scheme handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||||
|
* - ESP_ERR_INVALID_STATE Invalid state
|
||||||
|
* - ESP_ERR_NO_MEM If out of memory
|
||||||
|
*/
|
||||||
|
esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctrlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an AF step approximation scheme
|
||||||
|
*
|
||||||
|
* @param[in] scheme AF scheme handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||||
|
* - ESP_ERR_INVALID_STATE Invalid state
|
||||||
|
* - ESP_ERR_NO_MEM If out of memory
|
||||||
|
*/
|
||||||
|
esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register camera sensor driver to the SA scheme
|
||||||
|
*
|
||||||
|
* @param[in] scheme AF scheme handle
|
||||||
|
* @param[in] sensor_drv Sensor driver, see `isp_af_sa_scheme_sensor_drv_t`
|
||||||
|
* @param[in] info Sensor info
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK On success
|
||||||
|
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid
|
||||||
|
* - ESP_ERR_INVALID_STATE Invalid state
|
||||||
|
*/
|
||||||
|
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "driver/isp_af.h"
|
||||||
|
#include "isp_af_scheme_sa.h"
|
||||||
|
#include "isp_af_scheme_interface.h"
|
||||||
|
|
||||||
|
#define ISP_AF_SCHEME_SA_DEFAULT_WINDOW_NUMS 3
|
||||||
|
#define ISP_AF_SCHEME_SA_ENV_THRESH_SEARCH_NUMS 30
|
||||||
|
|
||||||
|
static const char *TAG = "AF_SCHEME";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
isp_af_ctrlr_t af_ctlr;
|
||||||
|
int first_step_val;
|
||||||
|
int first_approx_cycles;
|
||||||
|
int second_step_val;
|
||||||
|
int second_approx_cycles;
|
||||||
|
|
||||||
|
isp_af_sa_scheme_sensor_info_t sensor_info;
|
||||||
|
isp_af_sa_scheme_sensor_drv_t sensor_drv;
|
||||||
|
} af_scheme_context_t;
|
||||||
|
|
||||||
|
/* ------------------------ Interface Functions --------------------------- */
|
||||||
|
static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_luminance_thresh);
|
||||||
|
|
||||||
|
/* ------------------------- Public API ------------------------------------- */
|
||||||
|
esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
ESP_RETURN_ON_FALSE(af_ctlr && config && ret_scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
|
||||||
|
|
||||||
|
isp_af_scheme_t *scheme = (isp_af_scheme_t *)heap_caps_calloc(1, sizeof(isp_af_scheme_t), MALLOC_CAP_DEFAULT);
|
||||||
|
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for scheme");
|
||||||
|
|
||||||
|
af_scheme_context_t *ctx = (af_scheme_context_t *)heap_caps_calloc(1, sizeof(af_scheme_context_t), MALLOC_CAP_DEFAULT);
|
||||||
|
ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem scheme context");
|
||||||
|
|
||||||
|
scheme->af_process = s_af_process;
|
||||||
|
scheme->ctx = ctx;
|
||||||
|
|
||||||
|
ctx->af_ctlr = af_ctlr;
|
||||||
|
ctx->first_step_val = config->first_step_val;
|
||||||
|
ctx->first_approx_cycles = config->first_approx_cycles;
|
||||||
|
ctx->second_step_val = config->second_step_val;
|
||||||
|
ctx->second_approx_cycles = config->second_approx_cycles;
|
||||||
|
|
||||||
|
*ret_scheme = scheme;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(scheme);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
|
|
||||||
|
free(scheme->ctx);
|
||||||
|
scheme->ctx = NULL;
|
||||||
|
|
||||||
|
free(scheme);
|
||||||
|
scheme = NULL;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info)
|
||||||
|
{
|
||||||
|
ESP_RETURN_ON_FALSE(scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer");
|
||||||
|
ESP_RETURN_ON_FALSE(scheme->ctx, ESP_ERR_INVALID_STATE, TAG, "no scheme created yet");
|
||||||
|
|
||||||
|
af_scheme_context_t *ctx = scheme->ctx;
|
||||||
|
ctx->sensor_drv.af_sensor_set_focus = sensor_drv->af_sensor_set_focus;
|
||||||
|
ctx->sensor_info.focus_val_max = info->focus_val_max;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------ Interface Functions --------------------------- */
|
||||||
|
static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_luminance_thresh)
|
||||||
|
{
|
||||||
|
//arg pointer is checked in the upper layer
|
||||||
|
|
||||||
|
af_scheme_context_t *ctx = arg;
|
||||||
|
ESP_RETURN_ON_FALSE(ctx->af_ctlr, ESP_ERR_INVALID_STATE, TAG, "no AF controller registered");
|
||||||
|
ESP_RETURN_ON_FALSE(ctx->sensor_drv.af_sensor_set_focus, ESP_ERR_INVALID_STATE, TAG, "no sensor driver function `af_sensor_set_focus` registered");
|
||||||
|
|
||||||
|
int af_sum = 0;
|
||||||
|
int af_lum = 0;
|
||||||
|
int af_sum_max = 0;
|
||||||
|
|
||||||
|
int af_current_base = 0;
|
||||||
|
int af_current = 0;
|
||||||
|
int af_current_best = 0;
|
||||||
|
|
||||||
|
int af_sum_env_th = 0;
|
||||||
|
int af_lum_env_th = 0;
|
||||||
|
int af_sum_tmp[ISP_AF_SCHEME_SA_ENV_THRESH_SEARCH_NUMS] = {0};
|
||||||
|
int af_lum_tmp[ISP_AF_SCHEME_SA_ENV_THRESH_SEARCH_NUMS] = {0};
|
||||||
|
|
||||||
|
int ref_x = ISP_AF_SCHEME_SA_ENV_THRESH_SEARCH_NUMS;
|
||||||
|
int ref_x_fallback = ISP_AF_SCHEME_SA_ENV_THRESH_SEARCH_NUMS - 1;
|
||||||
|
|
||||||
|
isp_af_result_t result = {};
|
||||||
|
|
||||||
|
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(0), TAG, "sensor set focus val fail");
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "//----------- af start ----------//");
|
||||||
|
|
||||||
|
// first search
|
||||||
|
ESP_LOGV(TAG, "//----------- first search ----------//");
|
||||||
|
af_sum_max = 0;
|
||||||
|
af_current_base = 0;
|
||||||
|
|
||||||
|
for (int x = 0; x <= ctx->first_approx_cycles; x++) {
|
||||||
|
af_current = af_current_base + x * ctx->first_step_val;
|
||||||
|
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail");
|
||||||
|
ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail");
|
||||||
|
af_sum = result.definition[0] + result.definition[1] + result.definition[2];
|
||||||
|
if (af_sum > af_sum_max) {
|
||||||
|
af_sum_max = af_sum;
|
||||||
|
af_current_best = af_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "af_sum: %d, af_current: %d.%d", af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// second search
|
||||||
|
ESP_LOGV(TAG, "//----------- second search ----------//");
|
||||||
|
af_sum_max = 0;
|
||||||
|
af_current_base = af_current_best + 10;
|
||||||
|
|
||||||
|
if (af_current_base > ctx->sensor_info.focus_val_max) {
|
||||||
|
af_current_base = ctx->sensor_info.focus_val_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x <= ctx->second_approx_cycles; x++) {
|
||||||
|
af_current = af_current_base - x * ctx->second_step_val;
|
||||||
|
if (af_current < 0) {
|
||||||
|
af_current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail");
|
||||||
|
ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail");
|
||||||
|
af_sum = result.definition[0] + result.definition[1] + result.definition[2];
|
||||||
|
if (af_sum > af_sum_max) {
|
||||||
|
af_sum_max = af_sum;
|
||||||
|
af_current_best = af_current;
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "af_sum: %d, af_current: %d.%d", af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
// af done
|
||||||
|
ESP_LOGV(TAG, "//----------- af done ----------//");
|
||||||
|
ESP_LOGV(TAG, "af_sum_max: %d, af_current_best: %d.%d", af_sum_max, (int)af_current_best, (int)((int)(af_current_best * 1000) % 1000));
|
||||||
|
ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current_best), TAG, "sensor set focus val fail");
|
||||||
|
|
||||||
|
// update env threshold
|
||||||
|
ESP_LOGV(TAG, "//------- update env threshold -------//");
|
||||||
|
|
||||||
|
bool use_fallback_th = true;
|
||||||
|
for (int x = 0; x < ref_x; x++) {
|
||||||
|
ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail");
|
||||||
|
af_sum_tmp[x] = result.definition[0] + result.definition[1] + result.definition[2];
|
||||||
|
af_lum_tmp[x] = result.luminance[0] + result.luminance[1] + result.luminance[2];
|
||||||
|
|
||||||
|
if ((x >= 1) && (abs(af_sum_tmp[x] - af_sum_max) < af_sum_max * 0.3) && (abs(af_sum_tmp[x - 1] - af_sum_max) < af_sum_max * 0.3)) {
|
||||||
|
ref_x = x;
|
||||||
|
use_fallback_th = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_fallback_th) {
|
||||||
|
ref_x = ref_x_fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
af_sum = af_sum_tmp[ref_x];
|
||||||
|
af_lum = af_lum_tmp[ref_x];
|
||||||
|
af_sum_env_th = af_sum * 0.5;
|
||||||
|
af_lum_env_th = af_lum * 0.05;
|
||||||
|
*out_definition_thresh = af_sum_env_th;
|
||||||
|
*out_luminance_thresh = af_lum_env_th;
|
||||||
|
|
||||||
|
for (int x = 0; x < ref_x; x++) {
|
||||||
|
ESP_LOGV(TAG, "af_sum[%d]: %d, af_lum[%d]: %d", x, af_sum_tmp[x], x, af_lum_tmp[x]);
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "//------- update af env threshold done -------//");
|
||||||
|
ESP_LOGV(TAG, "af_sum: %d, af_sum_env_th: %d", af_sum, af_sum_env_th);
|
||||||
|
ESP_LOGV(TAG, "af_lum: %d, af_lum_env_th: %d", af_lum, af_lum_env_th);
|
||||||
|
ESP_LOGV(TAG, "//----------- af update done ----------//\n\n");
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user