forked from espressif/esp-idf
feat(isp_ae): support isp auto exposure
This commit is contained in:
@@ -12,7 +12,8 @@ if(CONFIG_SOC_ISP_SUPPORTED)
|
||||
list(APPEND srcs "src/isp_core.c"
|
||||
"src/isp_af.c"
|
||||
"src/isp_ccm.c"
|
||||
"src/isp_awb.c")
|
||||
"src/isp_awb.c"
|
||||
"src/isp_ae.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_ISP_BF_SUPPORTED)
|
||||
|
@@ -16,3 +16,4 @@
|
||||
#include "driver/isp_awb.h"
|
||||
#include "driver/isp_bf.h"
|
||||
#include "driver/isp_ccm.h"
|
||||
#include "driver/isp_ae.h"
|
||||
|
221
components/esp_driver_isp/include/driver/isp_ae.h
Normal file
221
components/esp_driver_isp/include/driver/isp_ae.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief AE controller config
|
||||
*/
|
||||
typedef struct {
|
||||
isp_ae_sample_point_t sample_point; ///< The input data source, ISP_AE_SAMPLE_POINT_AFTER_DEMOSAIC: AE input data after demosaic, ISP_AE_SAMPLE_POINT_AFTER_GAMMA: AE input data after gamma
|
||||
isp_window_t window; ///< The sampling windows of AE
|
||||
int intr_priority; ///< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) otherwise the larger the higher, 7 is NMI
|
||||
} esp_isp_ae_config_t;
|
||||
|
||||
/**
|
||||
* @brief New an ISP AE controller
|
||||
*
|
||||
* @param[in] isp_proc ISP Processor handle
|
||||
* @param[in] ae_config Pointer to AE config. Refer to ``esp_isp_ae_config_t``.
|
||||
* @param[out] ret_hdl AE 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_ae_controller(isp_proc_handle_t isp_proc, const esp_isp_ae_config_t *ae_config, isp_ae_ctlr_t *ret_hdl);
|
||||
|
||||
/**
|
||||
* @brief Delete an ISP AE controller
|
||||
*
|
||||
* @param[in] ae_ctlr AE 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_ae_controller(isp_ae_ctlr_t ae_ctlr);
|
||||
|
||||
/**
|
||||
* @brief Enable an ISP AE controller
|
||||
*
|
||||
* @param[in] ae_ctlr AE 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_ae_controller_enable(isp_ae_ctlr_t ae_ctlr);
|
||||
|
||||
/**
|
||||
* @brief Disable an ISP AE controller
|
||||
*
|
||||
* @param[in] ae_ctlr AE 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_ae_controller_disable(isp_ae_ctlr_t ae_ctlr);
|
||||
|
||||
/**
|
||||
* @brief Trigger AE luminance statistics for one time and get the result
|
||||
*
|
||||
* @param[in] ae_ctlr AE controller handle
|
||||
* @param[in] timeout_ms Timeout in millisecond
|
||||
* - timeout_ms < 0: Won't return until finished
|
||||
* - timeout_ms = 0: No timeout, trigger one time statistics and return immediately,
|
||||
* in this case, the result won't be assigned in this function,
|
||||
* but you can get the result in the callback `esp_isp_ae_env_detector_evt_cbs_t::on_env_statistics_done`
|
||||
* - timeout_ms > 0: Wait for specified milliseconds, if not finished, then return timeout error
|
||||
* @param[out] out_res AE luminance statistics result, can be NULL if `timeout_ms = 0`
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_TIMEOUT If the waiting time exceeds the specified timeout.
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
*/
|
||||
esp_err_t esp_isp_ae_controller_get_oneshot_statistics(isp_ae_ctlr_t ae_ctlr, int timeout_ms, isp_ae_result_t *out_res);
|
||||
|
||||
/**
|
||||
* @brief Start AE continuous statistics of the luminance in the windows
|
||||
* @note This function is an asynchronous and non-block function,
|
||||
* it will start the continuous statistics and return immediately.
|
||||
* You have to register the AE callback and get the result from the callback event data.
|
||||
* When you call `esp_isp_ae_controller_get_oneshot_statistics` during continuous mode,
|
||||
* continuous will be invalid, you need to restart continuous mode again.
|
||||
* @param[in] ae_ctlr AE controller handle
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Null pointer
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
*/
|
||||
esp_err_t esp_isp_ae_controller_start_continuous_statistics(isp_ae_ctlr_t ae_ctlr);
|
||||
|
||||
/**
|
||||
* @brief Stop AE continuous statistics of the luminance in the windows
|
||||
*
|
||||
* @param[in] ae_ctlr AE controller handle
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG Null pointer
|
||||
* - ESP_ERR_INVALID_STATE Driver state is invalid.
|
||||
*/
|
||||
esp_err_t esp_isp_ae_controller_stop_continuous_statistics(isp_ae_ctlr_t ae_ctlr);
|
||||
|
||||
/*---------------------------------------------
|
||||
AE env detector
|
||||
----------------------------------------------*/
|
||||
/**
|
||||
* @brief AE environment detector config
|
||||
*/
|
||||
typedef struct {
|
||||
int interval; /*!< Interval between environment detection, in frames.
|
||||
* i.e., AE controller will trigger the statistic periodically to detect the environment change.
|
||||
*/
|
||||
} esp_isp_ae_env_config_t;
|
||||
|
||||
/**
|
||||
* @brief AE environment detector config
|
||||
*/
|
||||
typedef struct {
|
||||
int low_thresh; /*!< Low threshold for AE environment detector luminance */
|
||||
int high_thresh; /*!< High threshold for AE environment detector luminance */
|
||||
} esp_isp_ae_env_thresh_t;
|
||||
|
||||
/**
|
||||
* @brief Set ISP AE environment detector
|
||||
*
|
||||
* @param[in] ae_ctlr AE controller handle
|
||||
* @param[in] env_config AE Env detector configuration
|
||||
*
|
||||
* @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_ae_controller_set_env_detector(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_config_t *env_config);
|
||||
|
||||
/**
|
||||
* @brief Set ISP AE environment detector detecting threshold
|
||||
*
|
||||
* @param[in] ae_ctlr AE controller handle
|
||||
* @param[in] env_thresh Luminance thresholds for AE env detector
|
||||
*
|
||||
* @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_ae_controller_set_env_detector_threshold(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_thresh_t *env_thresh);
|
||||
|
||||
/**
|
||||
* @brief Event data structure
|
||||
*/
|
||||
typedef struct {
|
||||
isp_ae_result_t ae_result; /*!< The AE statistics result */
|
||||
} esp_isp_ae_env_detector_evt_data_t;
|
||||
|
||||
/**
|
||||
* @brief Prototype of ISP AE Env detector event callback
|
||||
*
|
||||
* @param[in] ae_ctlr ISP AE controller handle
|
||||
* @param[in] edata ISP AE Env detector event data
|
||||
* @param[in] user_data User registered context, registered when in `esp_isp_ae_env_detector_register_event_callbacks()`
|
||||
*
|
||||
* @return Whether a high priority task is woken up by this function
|
||||
*/
|
||||
typedef bool (*esp_isp_ae_env_detector_callback_t)(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_detector_evt_data_t *edata, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Group of ISP AE env_detector
|
||||
* @note These callbacks are all running in an ISR environment.
|
||||
* @note When CONFIG_ISP_ISR_IRAM_SAEE 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_ae_env_detector_callback_t on_env_statistics_done; ///< Event callback, invoked when environment sample done.
|
||||
esp_isp_ae_env_detector_callback_t on_env_change; ///< Event callback, invoked when environment change happens.
|
||||
} esp_isp_ae_env_detector_evt_cbs_t;
|
||||
|
||||
/**
|
||||
* @brief Register AE Env 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_SAEE 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] ae_ctlr AE controller 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_ae_env_detector_register_event_callbacks(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_detector_evt_cbs_t *cbs, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -78,9 +78,6 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctlr_t af_ctrlr);
|
||||
|
||||
/**
|
||||
* @brief Trigger AF luminance and definition statistics for one time and get the result
|
||||
* @note This function is a synchronous and block function,
|
||||
* it only returns when AF luminance and definition statistics is done or timeout.
|
||||
* It's a simple method to get the result directly for one time.
|
||||
*
|
||||
* @param[in] af_ctrlr AF controller handle
|
||||
* @param[in] timeout_ms Timeout in millisecond
|
||||
@@ -109,6 +106,7 @@ esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, i
|
||||
* @note This function is an asynchronous and non-block function,
|
||||
* it will start the continuous statistics and return immediately.
|
||||
* You have to register the AF callback and get the result from the callback event data.
|
||||
* @note When continuous mode start, AF environment detector will be invalid
|
||||
*
|
||||
* @param[in] af_ctrlr AF controller handle
|
||||
* @return
|
||||
@@ -130,7 +128,7 @@ esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctr
|
||||
esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr);
|
||||
|
||||
/*---------------------------------------------
|
||||
AF Env Monitor
|
||||
AF Env Detector
|
||||
----------------------------------------------*/
|
||||
/**
|
||||
* @brief AF environment detector config
|
||||
@@ -147,6 +145,7 @@ typedef struct {
|
||||
* @param[in] af_ctrlr AF controller handle
|
||||
* @param[in] env_config AF Env detector configuration
|
||||
*
|
||||
* @note When continuous mode start, AF environment detector will be invalid
|
||||
* @return
|
||||
* - ESP_OK On success
|
||||
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
|
||||
|
@@ -121,9 +121,6 @@ esp_err_t esp_isp_awb_controller_disable(isp_awb_ctlr_t awb_ctlr);
|
||||
|
||||
/**
|
||||
* @brief Trigger AWB white patch statistics for one time and get the result
|
||||
* @note This function is a synchronous and block function,
|
||||
* it only returns when AWB white patch statistics is done or timeout.
|
||||
* It's a simple method to get the result directly for one time.
|
||||
*
|
||||
* @param[in] awb_ctlr AWB controller handle
|
||||
* @param[in] timeout_ms Timeout in millisecond
|
||||
|
@@ -48,6 +48,13 @@ typedef struct {
|
||||
uint32_t sum_b; ///< The sum of B channel of these white patches
|
||||
} isp_awb_stat_result_t;
|
||||
|
||||
/**
|
||||
* @brief ISP AE result
|
||||
*/
|
||||
typedef struct {
|
||||
int luminance[ISP_AE_BLOCK_X_NUM][ISP_AE_BLOCK_Y_NUM]; ///< Luminance, it refers how luminant an image is
|
||||
} isp_ae_result_t;
|
||||
|
||||
/**
|
||||
* @brief Type of ISP processor handle
|
||||
*/
|
||||
@@ -63,6 +70,11 @@ typedef struct isp_af_controller_t *isp_af_ctlr_t;
|
||||
*/
|
||||
typedef struct isp_awb_controller_t *isp_awb_ctlr_t;
|
||||
|
||||
/**
|
||||
* @brief Type of ISP AE controller handle
|
||||
*/
|
||||
typedef struct isp_ae_controller_t *isp_ae_ctlr_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -66,6 +66,7 @@ typedef struct isp_processor_t {
|
||||
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
|
||||
isp_awb_ctlr_t awb_ctlr;
|
||||
isp_fsm_t bf_fsm;
|
||||
isp_ae_ctlr_t ae_ctlr;
|
||||
} isp_processor_t;
|
||||
#endif
|
||||
|
||||
|
350
components/esp_driver_isp/src/isp_ae.c
Normal file
350
components/esp_driver_isp/src/isp_ae.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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_ae.h"
|
||||
#include "esp_private/isp_private.h"
|
||||
|
||||
static const char *TAG = "ISP_AE";
|
||||
|
||||
typedef struct isp_ae_controller_t {
|
||||
int id;
|
||||
isp_fsm_t fsm;
|
||||
portMUX_TYPE spinlock;
|
||||
intr_handle_t intr_handle;
|
||||
int intr_priority;
|
||||
isp_proc_handle_t isp_proc;
|
||||
QueueHandle_t evt_que;
|
||||
SemaphoreHandle_t stat_lock;
|
||||
int low_thresh;
|
||||
int high_thresh;
|
||||
esp_isp_ae_env_detector_evt_cbs_t cbs;
|
||||
void *user_data;
|
||||
} isp_ae_controller_t;
|
||||
|
||||
extern portMUX_TYPE fsm_spinlock;
|
||||
|
||||
static void s_isp_ae_default_isr(void *arg);
|
||||
|
||||
/*---------------------------------------------
|
||||
AE
|
||||
----------------------------------------------*/
|
||||
static esp_err_t s_isp_claim_ae_controller(isp_proc_handle_t isp_proc, isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
assert(isp_proc && ae_ctlr);
|
||||
|
||||
esp_err_t ret = ESP_ERR_NOT_FOUND;
|
||||
portENTER_CRITICAL(&isp_proc->spinlock);
|
||||
if (!isp_proc->ae_ctlr) {
|
||||
isp_proc->ae_ctlr = ae_ctlr;
|
||||
ret = ESP_OK;
|
||||
}
|
||||
portEXIT_CRITICAL(&isp_proc->spinlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void s_isp_declaim_ae_controller(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
if (ae_ctlr && ae_ctlr->isp_proc) {
|
||||
portENTER_CRITICAL(&ae_ctlr->isp_proc->spinlock);
|
||||
ae_ctlr->isp_proc->ae_ctlr = NULL;
|
||||
portEXIT_CRITICAL(&ae_ctlr->isp_proc->spinlock);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_isp_ae_free_controller(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
if (ae_ctlr) {
|
||||
if (ae_ctlr->intr_handle) {
|
||||
esp_intr_free(ae_ctlr->intr_handle);
|
||||
}
|
||||
if (ae_ctlr->evt_que) {
|
||||
vQueueDelete(ae_ctlr->evt_que);
|
||||
}
|
||||
if (ae_ctlr->stat_lock) {
|
||||
vSemaphoreDelete(ae_ctlr->stat_lock);
|
||||
}
|
||||
free(ae_ctlr);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_new_ae_controller(isp_proc_handle_t isp_proc, const esp_isp_ae_config_t *ae_config, isp_ae_ctlr_t *ret_hdl)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
ESP_RETURN_ON_FALSE(isp_proc && ae_config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
ESP_RETURN_ON_FALSE(((ae_config->window.top_left.x < ISP_LL_AE_WINDOW_MAX_RANGE) &&
|
||||
(ae_config->window.btm_right.x >= ae_config->window.top_left.x) &&
|
||||
(ae_config->window.btm_right.x < ISP_LL_AE_WINDOW_MAX_RANGE) &&
|
||||
(ae_config->window.top_left.y < ISP_LL_AE_WINDOW_MAX_RANGE) &&
|
||||
(ae_config->window.btm_right.y >= ae_config->window.top_left.y) &&
|
||||
(ae_config->window.btm_right.y < ISP_LL_AE_WINDOW_MAX_RANGE)), ESP_ERR_INVALID_ARG, TAG, "invalid window");
|
||||
|
||||
isp_ae_ctlr_t ae_ctlr = heap_caps_calloc(1, sizeof(isp_ae_controller_t), ISP_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr, ESP_ERR_NO_MEM, TAG, "no mem");
|
||||
ae_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_ae_result_t), ISP_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(ae_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for ae event queue");
|
||||
ae_ctlr->stat_lock = xSemaphoreCreateBinaryWithCaps(ISP_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(ae_ctlr->stat_lock, ESP_ERR_NO_MEM, err1, TAG, "no mem for ae semaphore");
|
||||
|
||||
ae_ctlr->fsm = ISP_FSM_INIT;
|
||||
ae_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
ae_ctlr->isp_proc = isp_proc;
|
||||
|
||||
//claim an AE controller
|
||||
ESP_GOTO_ON_ERROR(s_isp_claim_ae_controller(isp_proc, ae_ctlr), err1, TAG, "no available controller");
|
||||
|
||||
// Register the AE ISR
|
||||
uint32_t intr_st_reg_addr = isp_ll_get_intr_status_reg_addr(isp_proc->hal.hw);
|
||||
int intr_priority = ae_config->intr_priority > 0 && ae_config->intr_priority <= 7 ? BIT(ae_config->intr_priority) : ESP_INTR_FLAG_LOWMED;
|
||||
ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(isp_hw_info.instances[isp_proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | intr_priority, intr_st_reg_addr, ISP_LL_EVENT_AE_MASK,
|
||||
s_isp_ae_default_isr, ae_ctlr, &ae_ctlr->intr_handle), err2, TAG, "allocate interrupt failed");
|
||||
|
||||
isp_ll_ae_set_sample_point(isp_proc->hal.hw, ae_config->sample_point);
|
||||
isp_ll_ae_enable(isp_proc->hal.hw, false);
|
||||
isp_hal_ae_window_config(&isp_proc->hal, &ae_config->window);
|
||||
|
||||
isp_ll_clear_intr(isp_proc->hal.hw, ISP_LL_EVENT_AE_MASK);
|
||||
|
||||
*ret_hdl = ae_ctlr;
|
||||
|
||||
return ESP_OK;
|
||||
err2:
|
||||
s_isp_declaim_ae_controller(ae_ctlr);
|
||||
err1:
|
||||
s_isp_ae_free_controller(ae_ctlr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_del_ae_controller(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr && ae_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->isp_proc->ae_ctlr == ae_ctlr, ESP_ERR_INVALID_ARG, TAG, "controller isn't in use");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state");
|
||||
s_isp_declaim_ae_controller(ae_ctlr);
|
||||
|
||||
s_isp_ae_free_controller(ae_ctlr);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_enable(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr && ae_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state");
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_ERROR(esp_intr_enable(ae_ctlr->intr_handle), err, TAG, "failed to enable the AE interrupt");
|
||||
isp_ll_ae_clk_enable(ae_ctlr->isp_proc->hal.hw, true);
|
||||
isp_ll_enable_intr(ae_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AE_MASK, true);
|
||||
isp_ll_ae_enable(ae_ctlr->isp_proc->hal.hw, true);
|
||||
xSemaphoreGive(ae_ctlr->stat_lock);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
ae_ctlr->fsm = ISP_FSM_INIT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_disable(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr && ae_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state");
|
||||
xSemaphoreTake(ae_ctlr->stat_lock, 0);
|
||||
ae_ctlr->fsm = ISP_FSM_INIT;
|
||||
|
||||
isp_ll_ae_clk_enable(ae_ctlr->isp_proc->hal.hw, false);
|
||||
isp_ll_enable_intr(ae_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AE_MASK, false);
|
||||
isp_ll_ae_enable(ae_ctlr->isp_proc->hal.hw, false);
|
||||
esp_intr_disable(ae_ctlr->intr_handle);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_get_oneshot_statistics(isp_ae_ctlr_t ae_ctlr, int timeout_ms, isp_ae_result_t *out_res)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
TickType_t ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
|
||||
xSemaphoreTake(ae_ctlr->stat_lock, ticks);
|
||||
ESP_GOTO_ON_FALSE(ae_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, err, TAG, "controller isn't in enable state");
|
||||
|
||||
// Reset the queue in case receiving the legacy data in the queue
|
||||
xQueueReset(ae_ctlr->evt_que);
|
||||
|
||||
// Disable the env detector when manual statistics.
|
||||
// Otherwise, the env detector results may overwrite the manual statistics results when the statistics results are not read out in time
|
||||
isp_ll_ae_env_detector_set_thresh(ae_ctlr->isp_proc->hal.hw, 0, 0);
|
||||
// Trigger the AE statistics manually
|
||||
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);
|
||||
// Wait the statistics to finish and receive the result from the queue
|
||||
if ((ticks > 0) && xQueueReceive(ae_ctlr->evt_que, out_res, ticks) != pdTRUE) {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
}
|
||||
// Re-enable the env detector after manual statistics.
|
||||
isp_ll_ae_env_detector_set_thresh(ae_ctlr->isp_proc->hal.hw, ae_ctlr->low_thresh, ae_ctlr->high_thresh);
|
||||
|
||||
portENTER_CRITICAL(&fsm_spinlock);
|
||||
ae_ctlr->fsm = ISP_FSM_ENABLE;
|
||||
portEXIT_CRITICAL(&fsm_spinlock);
|
||||
|
||||
err:
|
||||
xSemaphoreGive(ae_ctlr->stat_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_start_continuous_statistics(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state");
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (xSemaphoreTake(ae_ctlr->stat_lock, 0) == pdFALSE) {
|
||||
ESP_LOGW(TAG, "statistics lock is not acquired, controller is busy");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(ae_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, err, TAG, "controller isn't in enable state");
|
||||
|
||||
portENTER_CRITICAL(&fsm_spinlock);
|
||||
ae_ctlr->fsm = ISP_FSM_START;
|
||||
portEXIT_CRITICAL(&fsm_spinlock);
|
||||
|
||||
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);
|
||||
|
||||
err:
|
||||
xSemaphoreGive(ae_ctlr->stat_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_stop_continuous_statistics(isp_ae_ctlr_t ae_ctlr)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state");
|
||||
isp_ll_ae_env_detector_set_thresh(ae_ctlr->isp_proc->hal.hw, ae_ctlr->low_thresh, ae_ctlr->high_thresh);
|
||||
|
||||
portENTER_CRITICAL(&fsm_spinlock);
|
||||
ae_ctlr->fsm = ISP_FSM_ENABLE;
|
||||
portEXIT_CRITICAL(&fsm_spinlock);
|
||||
xSemaphoreGive(ae_ctlr->stat_lock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------
|
||||
AE Env Detector
|
||||
----------------------------------------------*/
|
||||
esp_err_t esp_isp_ae_controller_set_env_detector(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_config_t *env_config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr && env_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "invalid fsm, should be called when in init state");
|
||||
ESP_RETURN_ON_FALSE(env_config->interval > 0, ESP_ERR_INVALID_STATE, TAG, "invalid interval, should be greater than 0");
|
||||
|
||||
isp_ll_clear_intr(ae_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AE_ENV);
|
||||
isp_ll_ae_env_detector_set_period(ae_ctlr->isp_proc->hal.hw, env_config->interval);
|
||||
isp_ll_enable_intr(ae_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AE_ENV, true);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_env_detector_register_event_callbacks(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_detector_evt_cbs_t *cbs, void *user_data)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(ae_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state");
|
||||
|
||||
#if CONFIG_ISP_ISR_IRAM_SAEE
|
||||
if (cbs->on_env_statistics_done) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_env_statistics_done), ESP_ERR_INVALID_ARG, TAG, "on_env_statistics_done callback not in IRAM");
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (user_data) {
|
||||
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
|
||||
}
|
||||
#endif
|
||||
ae_ctlr->cbs.on_env_statistics_done = cbs->on_env_statistics_done;
|
||||
ae_ctlr->cbs.on_env_change = cbs->on_env_change;
|
||||
ae_ctlr->user_data = user_data;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_isp_ae_controller_set_env_detector_threshold(isp_ae_ctlr_t ae_ctlr, const esp_isp_ae_env_thresh_t *env_thresh)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(ae_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "AE env detector isn't in enable state");
|
||||
ESP_RETURN_ON_FALSE_ISR((env_thresh->low_thresh != 0 && env_thresh->high_thresh != 0) && (env_thresh->low_thresh <= env_thresh->high_thresh), ESP_ERR_INVALID_STATE, TAG, "invalid AE env detector thresh");
|
||||
|
||||
ae_ctlr->low_thresh = env_thresh->low_thresh;
|
||||
ae_ctlr->high_thresh = env_thresh->high_thresh;
|
||||
|
||||
isp_ll_ae_env_detector_set_thresh(ae_ctlr->isp_proc->hal.hw, ae_ctlr->low_thresh, ae_ctlr->high_thresh);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
INTR
|
||||
---------------------------------------------------------------*/
|
||||
static void IRAM_ATTR s_isp_ae_default_isr(void *arg)
|
||||
{
|
||||
isp_ae_ctlr_t ae_ctlr = (isp_ae_ctlr_t)arg;
|
||||
isp_proc_handle_t proc = ae_ctlr->isp_proc;
|
||||
|
||||
uint32_t ae_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AE_MASK);
|
||||
|
||||
bool need_yield = false;
|
||||
esp_isp_ae_env_detector_evt_data_t edata = {};
|
||||
|
||||
if (ae_events) {
|
||||
// Get the statistics result
|
||||
int block_id = 0;
|
||||
for (int i = 0; i < SOC_ISP_AE_BLOCK_X_NUMS; i++) {
|
||||
for (int j = 0; j < SOC_ISP_AE_BLOCK_Y_NUMS; j++) {
|
||||
edata.ae_result.luminance[i][j] = isp_ll_ae_get_block_mean_lum(proc->hal.hw, block_id);
|
||||
block_id++;
|
||||
}
|
||||
}
|
||||
BaseType_t high_task_awake = false;
|
||||
// Send the event data to the queue, overwrite the legacy one if exist
|
||||
xQueueOverwriteFromISR(ae_ctlr->evt_que, &edata.ae_result, &high_task_awake);
|
||||
// Invoke the callback if the callback is registered
|
||||
need_yield |= high_task_awake == pdTRUE;
|
||||
|
||||
/* If started continuous sampling, then trigger the next AE sample */
|
||||
if (ae_ctlr->fsm == ISP_FSM_START) {
|
||||
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deal with the interrupts.
|
||||
* Now only one detector.
|
||||
* Should decide a detector instance according to the hw event.
|
||||
*/
|
||||
if (ae_events & ISP_LL_EVENT_AE_FDONE) {
|
||||
if (ae_ctlr->cbs.on_env_statistics_done) {
|
||||
need_yield |= ae_ctlr->cbs.on_env_statistics_done(ae_ctlr, &edata, ae_ctlr->user_data);
|
||||
}
|
||||
}
|
||||
if (ae_events & ISP_LL_EVENT_AE_ENV) {
|
||||
if (ae_ctlr->cbs.on_env_change) {
|
||||
need_yield |= ae_ctlr->cbs.on_env_change(ae_ctlr, &edata, ae_ctlr->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (need_yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
@@ -126,7 +126,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af
|
||||
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_mode(isp_proc->hal.hw, ISP_LL_AF_EDGE_DETECTOR_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);
|
||||
|
||||
@@ -229,7 +229,7 @@ esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrl
|
||||
}
|
||||
|
||||
/*---------------------------------------------
|
||||
AF Env Monitor
|
||||
AF Env Detector
|
||||
----------------------------------------------*/
|
||||
esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config)
|
||||
{
|
||||
@@ -238,11 +238,11 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const e
|
||||
|
||||
af_ctrlr->config.interval = env_config->interval;
|
||||
|
||||
isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, 0);
|
||||
isp_ll_af_env_detector_set_period(af_ctrlr->isp_proc->hal.hw, 0);
|
||||
isp_ll_clear_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV);
|
||||
|
||||
isp_ll_af_env_monitor_set_mode(af_ctrlr->isp_proc->hal.hw, ISP_LL_AF_ENV_MONITOR_MODE_ABS);
|
||||
isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, af_ctrlr->config.interval);
|
||||
isp_ll_af_env_detector_set_mode(af_ctrlr->isp_proc->hal.hw, ISP_LL_AF_ENV_DETECTOR_MODE_ABS);
|
||||
isp_ll_af_env_detector_set_period(af_ctrlr->isp_proc->hal.hw, af_ctrlr->config.interval);
|
||||
isp_ll_enable_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV, true);
|
||||
|
||||
return ESP_OK;
|
||||
@@ -276,7 +276,7 @@ esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctrl
|
||||
ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state");
|
||||
|
||||
isp_ll_af_env_monitor_set_thresh(af_ctrlr->isp_proc->hal.hw, definition_thresh, luminance_thresh);
|
||||
isp_ll_af_env_detector_set_thresh(af_ctrlr->isp_proc->hal.hw, definition_thresh, luminance_thresh);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -41,8 +41,8 @@ extern "C" {
|
||||
#define ISP_LL_EVENT_MIPI_HNUM_UNMATCH (1<<5)
|
||||
#define ISP_LL_EVENT_DPC_CHECK_DONE (1<<6)
|
||||
#define ISP_LL_EVENT_GAMMA_XCOORD_ERR (1<<7)
|
||||
#define ISP_LL_EVENT_AE_MONITOR (1<<8)
|
||||
#define ISP_LL_EVENT_AE_FRAME_DONE (1<<9)
|
||||
#define ISP_LL_EVENT_AE_ENV (1<<8)
|
||||
#define ISP_LL_EVENT_AE_FDONE (1<<9)
|
||||
#define ISP_LL_EVENT_AF_FDONE (1<<10)
|
||||
#define ISP_LL_EVENT_AF_ENV (1<<11)
|
||||
#define ISP_LL_EVENT_AWB_FDONE (1<<12)
|
||||
@@ -65,6 +65,7 @@ extern "C" {
|
||||
|
||||
#define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF)
|
||||
#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)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
@@ -72,6 +73,11 @@ extern "C" {
|
||||
---------------------------------------------------------------*/
|
||||
#define ISP_LL_AF_WINDOW_MAX_RANGE ((1<<12) - 1)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AE
|
||||
---------------------------------------------------------------*/
|
||||
#define ISP_LL_AE_WINDOW_MAX_RANGE ((1<<12) - 1)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
BF
|
||||
---------------------------------------------------------------*/
|
||||
@@ -117,20 +123,20 @@ typedef union {
|
||||
} isp_ll_ccm_gain_t;
|
||||
|
||||
/**
|
||||
* @brief Env monitor mode
|
||||
* @brief Env detector mode
|
||||
*/
|
||||
typedef enum {
|
||||
ISP_LL_AF_ENV_MONITOR_MODE_ABS, ///< Use absolute val for threshold
|
||||
ISP_LL_AF_ENV_MONITOR_MODE_RATIO, ///< Use ratio val for threshold
|
||||
} isp_ll_af_env_monitor_mode_t;
|
||||
ISP_LL_AF_ENV_DETECTOR_MODE_ABS, ///< Use absolute val for threshold
|
||||
ISP_LL_AF_ENV_DETECTOR_MODE_RATIO, ///< Use ratio val for threshold
|
||||
} isp_ll_af_env_detector_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Edge monitor mode
|
||||
* @brief Edge detector mode
|
||||
*/
|
||||
typedef enum {
|
||||
ISP_LL_AF_EDGE_MONITOR_MODE_AUTO, ///< Auto set threshold
|
||||
ISP_LL_AF_EDGE_MONITOR_MODE_MANUAL, ///< Manual set threshold
|
||||
} isp_ll_af_edge_monitor_mode_t;
|
||||
ISP_LL_AF_EDGE_DETECTOR_MODE_AUTO, ///< Auto set threshold
|
||||
ISP_LL_AF_EDGE_DETECTOR_MODE_MANUAL, ///< Manual set threshold
|
||||
} isp_ll_af_edge_detector_mode_t;
|
||||
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
@@ -496,11 +502,11 @@ static inline void isp_ll_af_manual_update(isp_dev_t *hw)
|
||||
* @brief Set edge thresh mode
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] mode See `isp_ll_af_edge_monitor_mode_t`
|
||||
* @param[in] mode See `isp_ll_af_edge_detector_mode_t`
|
||||
*/
|
||||
static inline void isp_ll_af_set_edge_thresh_mode(isp_dev_t *hw, isp_ll_af_edge_monitor_mode_t mode)
|
||||
static inline void isp_ll_af_set_edge_thresh_mode(isp_dev_t *hw, isp_ll_af_edge_detector_mode_t mode)
|
||||
{
|
||||
if (mode == ISP_LL_AF_EDGE_MONITOR_MODE_AUTO) {
|
||||
if (mode == ISP_LL_AF_EDGE_DETECTOR_MODE_AUTO) {
|
||||
hw->af_threshold.af_threshold = 0;
|
||||
}
|
||||
}
|
||||
@@ -622,43 +628,43 @@ static inline uint32_t isp_ll_af_get_window_lum(isp_dev_t *hw, uint32_t window_i
|
||||
}
|
||||
|
||||
/*---------------------------------------------
|
||||
AF Env Monitor
|
||||
AF Env detector
|
||||
----------------------------------------------*/
|
||||
/**
|
||||
* @brief Set env monitor period
|
||||
* @brief Set env detector period
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] period period of the env monitor, in frames
|
||||
* @param[in] period period of the env detector, in frames
|
||||
*/
|
||||
static inline void isp_ll_af_env_monitor_set_period(isp_dev_t *hw, uint32_t period)
|
||||
static inline void isp_ll_af_env_detector_set_period(isp_dev_t *hw, uint32_t period)
|
||||
{
|
||||
hw->af_ctrl0.af_env_period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set env monitor mode
|
||||
* @brief Set env detector mode
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] mode See `isp_ll_af_env_monitor_mode_t`
|
||||
* @param[in] mode See `isp_ll_af_env_detector_mode_t`
|
||||
*/
|
||||
static inline void isp_ll_af_env_monitor_set_mode(isp_dev_t *hw, isp_ll_af_env_monitor_mode_t mode)
|
||||
static inline void isp_ll_af_env_detector_set_mode(isp_dev_t *hw, isp_ll_af_env_detector_mode_t mode)
|
||||
{
|
||||
if (mode == ISP_LL_AF_ENV_MONITOR_MODE_RATIO) {
|
||||
if (mode == ISP_LL_AF_ENV_DETECTOR_MODE_RATIO) {
|
||||
hw->af_env_user_th_sum.af_env_user_threshold_sum = 0x0;
|
||||
hw->af_env_user_th_lum.af_env_user_threshold_lum = 0x0;
|
||||
}
|
||||
|
||||
//nothing to do to if using abs mode, it'll be enabled after `isp_ll_af_env_monitor_set_thresh()`
|
||||
//nothing to do to if using abs mode, it'll be enabled after `isp_ll_af_env_detector_set_thresh()`
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set env monitor threshold
|
||||
* @brief Set env detector threshold
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] sum_thresh Threshold for definition
|
||||
* @param[in] lum_thresh Threshold for luminance
|
||||
*/
|
||||
static inline void isp_ll_af_env_monitor_set_thresh(isp_dev_t *hw, uint32_t sum_thresh, uint32_t lum_thresh)
|
||||
static inline void isp_ll_af_env_detector_set_thresh(isp_dev_t *hw, uint32_t sum_thresh, uint32_t lum_thresh)
|
||||
{
|
||||
HAL_ASSERT(sum_thresh != 0 || lum_thresh != 0);
|
||||
|
||||
@@ -667,12 +673,12 @@ static inline void isp_ll_af_env_monitor_set_thresh(isp_dev_t *hw, uint32_t sum_
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set env monitor ratio
|
||||
* @brief Set env detector ratio
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] ratio_val Threshold for ratio
|
||||
*/
|
||||
static inline void isp_ll_af_env_monitor_set_ratio(isp_dev_t *hw, uint32_t ratio_val)
|
||||
static inline void isp_ll_af_env_detector_set_ratio(isp_dev_t *hw, uint32_t ratio_val)
|
||||
{
|
||||
HAL_ASSERT(hw->af_env_user_th_sum.af_env_user_threshold_sum == 0 &&
|
||||
hw->af_env_user_th_lum.af_env_user_threshold_lum == 0);
|
||||
@@ -974,6 +980,122 @@ static inline void isp_ll_cam_enable(isp_dev_t *hw, bool enable)
|
||||
hw->cam_cntl.cam_en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AE
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Enable / Disable AE clock
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] enable Enable / Disable
|
||||
*/
|
||||
static inline void isp_ll_ae_clk_enable(isp_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->clk_en.clk_ae_force_on = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable / Disable AE
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] enable Enable / Disable
|
||||
*/
|
||||
static inline void isp_ll_ae_enable(isp_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->cntl.ae_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Manual aupdate AF once
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
*/
|
||||
static inline void isp_ll_ae_manual_update(isp_dev_t *hw)
|
||||
{
|
||||
hw->ae_ctrl.ae_update = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Select AE input data source
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] sample_point 0: AE input data after demosaic, 1: AE input data after gamma
|
||||
*/
|
||||
static inline void isp_ll_ae_set_sample_point(isp_dev_t *hw, isp_ae_sample_point_t sample_point)
|
||||
{
|
||||
hw->ae_ctrl.ae_select = sample_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set AE window range
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] x_start Top left pixel x axis value
|
||||
* @param[in] x_bsize Block size on x axis
|
||||
* @param[in] y_start Top left pixel y axis value
|
||||
* @param[in] y_bsize Block size on y axis
|
||||
*/
|
||||
static inline void isp_ll_ae_set_window_range(isp_dev_t *hw, int x_start, int x_bsize, int y_start, int y_bsize)
|
||||
{
|
||||
hw->ae_bx.ae_x_start = x_start;
|
||||
hw->ae_bx.ae_x_bsize = x_bsize;
|
||||
hw->ae_by.ae_y_start = y_start;
|
||||
hw->ae_by.ae_y_bsize = y_bsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get block mean luminance
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] block_id
|
||||
*
|
||||
* @return Mean luminance
|
||||
*/
|
||||
static inline int isp_ll_ae_get_block_mean_lum(isp_dev_t *hw, int block_id)
|
||||
{
|
||||
HAL_ASSERT(block_id >=0 && block_id < (SOC_ISP_AE_BLOCK_X_NUMS * SOC_ISP_AE_BLOCK_Y_NUMS));
|
||||
return hw->ae_block_mean[block_id / 4].ae_b_mean[3 - (block_id % 4)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AE set the pixel number of each subwin, and set the reciprocal of each subwin_pixnum, 20bit fraction
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] subwin_pixnum Pixel number
|
||||
*/
|
||||
static inline void isp_ll_ae_set_subwin_pixnum_recip(isp_dev_t *hw, int subwin_pixnum)
|
||||
{
|
||||
hw->ae_winpixnum.ae_subwin_pixnum = subwin_pixnum;
|
||||
int subwin_recip = (1 << 20) / subwin_pixnum;
|
||||
hw->ae_win_reciprocal.ae_subwin_recip = subwin_recip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set AE env detector threshold
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] low_thresh Lower lum threshold
|
||||
* @param[in] high_thresh Higher lum threshold
|
||||
*/
|
||||
static inline void isp_ll_ae_env_detector_set_thresh(isp_dev_t *hw, uint32_t low_thresh, uint32_t high_thresh)
|
||||
{
|
||||
hw->ae_monitor.ae_monitor_tl = low_thresh;
|
||||
hw->ae_monitor.ae_monitor_th = high_thresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set AE env detector period
|
||||
*
|
||||
* @param[in] hw Hardware instance address
|
||||
* @param[in] period period of the AE env detector, in frames
|
||||
*/
|
||||
static inline void isp_ll_ae_env_detector_set_period(isp_dev_t *hw, uint32_t period)
|
||||
{
|
||||
hw->ae_monitor.ae_monitor_period = period;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
INTR
|
||||
---------------------------------------------------------------*/
|
||||
|
@@ -66,6 +66,17 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id);
|
||||
*/
|
||||
void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_window_t *window);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AE
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Configure AE window
|
||||
*
|
||||
* @param[in] hal Context of the HAL layer
|
||||
* @param[in] window Window info, see `isp_window_t`
|
||||
*/
|
||||
void isp_hal_ae_window_config(const isp_hal_context_t *hal, const isp_window_t *window);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
INTR
|
||||
---------------------------------------------------------------*/
|
||||
|
@@ -122,6 +122,26 @@ typedef enum {
|
||||
ISP_AWB_SAMPLE_POINT_AFTER_CCM, ///< Sample AWB data after CCM (Color Correction Matrix)
|
||||
} isp_awb_sample_point_t;
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AE
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
#if (SOC_ISP_AE_BLOCK_X_NUMS && SOC_ISP_AE_BLOCK_Y_NUMS)
|
||||
#define ISP_AE_BLOCK_X_NUM SOC_ISP_AE_BLOCK_X_NUMS // The AF window number for sampling
|
||||
#define ISP_AE_BLOCK_Y_NUM SOC_ISP_AE_BLOCK_Y_NUMS // The AF window number for sampling
|
||||
#else
|
||||
#define ISP_AE_BLOCK_X_NUM 0
|
||||
#define ISP_AE_BLOCK_Y_NUM 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ISP AE input data source
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ISP_AE_SAMPLE_POINT_AFTER_DEMOSAIC, ///< AE input data after demosaic
|
||||
ISP_AE_SAMPLE_POINT_AFTER_GAMMA, ///< AE input data after gamma
|
||||
} isp_ae_sample_point_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -57,6 +57,24 @@ void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config)
|
||||
isp_ll_bf_set_template(hal->hw, default_template);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
AE
|
||||
---------------------------------------------------------------*/
|
||||
void isp_hal_ae_window_config(const isp_hal_context_t *hal, const isp_window_t *window)
|
||||
{
|
||||
uint32_t ae_x_start = window->top_left.x;
|
||||
uint32_t ae_x_bsize = (window->btm_right.x - window-> top_left.x) / SOC_ISP_AE_BLOCK_X_NUMS;
|
||||
|
||||
uint32_t ae_y_start = window->top_left.y;
|
||||
uint32_t ae_y_bsize = (window->btm_right.y - window->top_left.y) / SOC_ISP_AE_BLOCK_Y_NUMS;
|
||||
|
||||
isp_ll_ae_set_window_range(hal->hw, ae_x_start, ae_x_bsize, ae_y_start, ae_y_bsize);
|
||||
|
||||
int ae_subwin_pixnum = ae_x_bsize * ae_y_bsize;
|
||||
isp_ll_ae_set_subwin_pixnum_recip(hal->hw, ae_subwin_pixnum);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
INTR, put in iram
|
||||
---------------------------------------------------------------*/
|
||||
|
@@ -827,6 +827,18 @@ config SOC_ISP_AF_WINDOW_NUMS
|
||||
int
|
||||
default 3
|
||||
|
||||
config SOC_ISP_AE_CTLR_NUMS
|
||||
int
|
||||
default 1
|
||||
|
||||
config SOC_ISP_AE_BLOCK_X_NUMS
|
||||
int
|
||||
default 5
|
||||
|
||||
config SOC_ISP_AE_BLOCK_Y_NUMS
|
||||
int
|
||||
default 5
|
||||
|
||||
config SOC_ISP_SHARE_CSI_BRG
|
||||
bool
|
||||
default y
|
||||
|
@@ -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
|
||||
*/
|
||||
@@ -398,35 +398,35 @@ typedef union {
|
||||
typedef union {
|
||||
struct {
|
||||
/** gau_template21 : R/W; bitpos: [3:0]; default: 15;
|
||||
* this field configures index 21 of gausian template
|
||||
* this field configures index 21 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template21:4;
|
||||
/** gau_template20 : R/W; bitpos: [7:4]; default: 15;
|
||||
* this field configures index 20 of gausian template
|
||||
* this field configures index 20 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template20:4;
|
||||
/** gau_template12 : R/W; bitpos: [11:8]; default: 15;
|
||||
* this field configures index 12 of gausian template
|
||||
* this field configures index 12 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template12:4;
|
||||
/** gau_template11 : R/W; bitpos: [15:12]; default: 15;
|
||||
* this field configures index 11 of gausian template
|
||||
* this field configures index 11 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template11:4;
|
||||
/** gau_template10 : R/W; bitpos: [19:16]; default: 15;
|
||||
* this field configures index 10 of gausian template
|
||||
* this field configures index 10 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template10:4;
|
||||
/** gau_template02 : R/W; bitpos: [23:20]; default: 15;
|
||||
* this field configures index 02 of gausian template
|
||||
* this field configures index 02 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template02:4;
|
||||
/** gau_template01 : R/W; bitpos: [27:24]; default: 15;
|
||||
* this field configures index 01 of gausian template
|
||||
* this field configures index 01 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template01:4;
|
||||
/** gau_template00 : R/W; bitpos: [31:28]; default: 15;
|
||||
* this field configures index 00 of gausian template
|
||||
* this field configures index 00 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template00:4;
|
||||
};
|
||||
@@ -439,7 +439,7 @@ typedef union {
|
||||
typedef union {
|
||||
struct {
|
||||
/** gau_template22 : R/W; bitpos: [3:0]; default: 15;
|
||||
* this field configures index 22 of gausian template
|
||||
* this field configures index 22 of gaussian template
|
||||
*/
|
||||
uint32_t gau_template22:4;
|
||||
uint32_t reserved_4:28;
|
||||
@@ -1321,7 +1321,7 @@ typedef union {
|
||||
*/
|
||||
uint32_t ae_monitor_th:8;
|
||||
/** ae_monitor_period : R/W; bitpos: [21:16]; default: 0;
|
||||
* this field cnfigures ae monitor frame period
|
||||
* this field configures ae monitor frame period
|
||||
*/
|
||||
uint32_t ae_monitor_period:6;
|
||||
uint32_t reserved_22:10;
|
||||
@@ -1536,7 +1536,7 @@ typedef union {
|
||||
typedef union {
|
||||
struct {
|
||||
/** dma_en : WT; bitpos: [0]; default: 0;
|
||||
* write 1 to triger dma to get 1 frame
|
||||
* write 1 to trigger dma to get 1 frame
|
||||
*/
|
||||
uint32_t dma_en:1;
|
||||
/** dma_update_reg : R/W; bitpos: [1]; default: 0;
|
||||
@@ -1584,7 +1584,7 @@ typedef union {
|
||||
typedef union {
|
||||
struct {
|
||||
/** cam_en : R/W; bitpos: [0]; default: 0;
|
||||
* write 1 to start recive camera data, write 0 to disable
|
||||
* write 1 to start receive camera data, write 0 to disable
|
||||
*/
|
||||
uint32_t cam_en:1;
|
||||
/** cam_update_reg : R/W; bitpos: [1]; default: 0;
|
||||
@@ -1596,7 +1596,7 @@ typedef union {
|
||||
*/
|
||||
uint32_t cam_reset:1;
|
||||
/** cam_clk_inv : R/W; bitpos: [3]; default: 0;
|
||||
* this bit configures the invertion of cam clk from pad. 0: not invert cam clk, 1:
|
||||
* this bit configures the inversion of cam clk from pad. 0: not invert cam clk, 1:
|
||||
* invert cam clk
|
||||
*/
|
||||
uint32_t cam_clk_inv:1;
|
||||
@@ -1880,7 +1880,7 @@ typedef union {
|
||||
typedef union {
|
||||
struct {
|
||||
/** awb_mode : R/W; bitpos: [1:0]; default: 3;
|
||||
* this field configures awb algo sel. 00: none sellected. 01: sel algo0. 10: sel
|
||||
* this field configures awb algo sel. 00: none selected. 01: sel algo0. 10: sel
|
||||
* algo1. 11: sel both algo0 and algo1
|
||||
*/
|
||||
uint32_t awb_mode:2;
|
||||
@@ -2627,6 +2627,19 @@ typedef union {
|
||||
uint32_t val;
|
||||
} isp_lut_rdata_reg_t;
|
||||
|
||||
/** Type of ae_block_mean register
|
||||
* ae statistic result
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** ae_lum : RO; bitpos: [31:0]; default: 0;
|
||||
* this field represents the result of AE block
|
||||
*/
|
||||
uint8_t ae_b_mean[4];
|
||||
};
|
||||
uint32_t val;
|
||||
} isp_ae_block_mean_reg_t;
|
||||
|
||||
/** Type of ae_block_mean_0 register
|
||||
* ae statistic result register 0
|
||||
*/
|
||||
@@ -2790,7 +2803,6 @@ typedef union {
|
||||
};
|
||||
uint32_t val;
|
||||
} isp_ae_block_mean_6_reg_t;
|
||||
|
||||
/** Type of af_sum_a register
|
||||
* result of sum of af window a
|
||||
*/
|
||||
@@ -3764,13 +3776,7 @@ typedef struct {
|
||||
volatile isp_ae_by_reg_t ae_by;
|
||||
volatile isp_ae_winpixnum_reg_t ae_winpixnum;
|
||||
volatile isp_ae_win_reciprocal_reg_t ae_win_reciprocal;
|
||||
volatile isp_ae_block_mean_0_reg_t ae_block_mean_0;
|
||||
volatile isp_ae_block_mean_1_reg_t ae_block_mean_1;
|
||||
volatile isp_ae_block_mean_2_reg_t ae_block_mean_2;
|
||||
volatile isp_ae_block_mean_3_reg_t ae_block_mean_3;
|
||||
volatile isp_ae_block_mean_4_reg_t ae_block_mean_4;
|
||||
volatile isp_ae_block_mean_5_reg_t ae_block_mean_5;
|
||||
volatile isp_ae_block_mean_6_reg_t ae_block_mean_6;
|
||||
volatile isp_ae_block_mean_reg_t ae_block_mean[7];
|
||||
volatile isp_sharp_ctrl0_reg_t sharp_ctrl0;
|
||||
volatile isp_sharp_filter0_reg_t sharp_filter0;
|
||||
volatile isp_sharp_filter1_reg_t sharp_filter1;
|
||||
|
@@ -328,6 +328,9 @@
|
||||
#define SOC_ISP_DVP_CTLR_NUMS 1U
|
||||
#define SOC_ISP_AF_CTLR_NUMS 1U
|
||||
#define SOC_ISP_AF_WINDOW_NUMS 3
|
||||
#define SOC_ISP_AE_CTLR_NUMS 1U
|
||||
#define SOC_ISP_AE_BLOCK_X_NUMS 5
|
||||
#define SOC_ISP_AE_BLOCK_Y_NUMS 5
|
||||
#define SOC_ISP_SHARE_CSI_BRG 1
|
||||
#define SOC_ISP_BF_TEMPLATE_X_NUMS 3
|
||||
#define SOC_ISP_BF_TEMPLATE_Y_NUMS 3
|
||||
|
Reference in New Issue
Block a user