Skip to content

Commit

Permalink
Merge branch 'feature/support_isp_ae' into 'master'
Browse files Browse the repository at this point in the history
feat(isp): Support ISP Auto Exposure (AE)

Closes IDF-9592, IDF-10193, and IDF-10580

See merge request espressif/esp-idf!31671
  • Loading branch information
Bruce297 committed Aug 1, 2024
2 parents 33b4d64 + 51a7de2 commit 3e974bd
Show file tree
Hide file tree
Showing 21 changed files with 1,208 additions and 128 deletions.
3 changes: 2 additions & 1 deletion components/esp_driver_isp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions components/esp_driver_isp/include/driver/isp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 221 additions & 0 deletions components/esp_driver_isp/include/driver/isp_ae.h
Original file line number Diff line number Diff line change
@@ -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~3, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
} 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.
* @note When using oneshot statistics, the AE Environment Detector will be temporarily disabled
* and will automatically recover once the oneshot is complete.
* @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
9 changes: 4 additions & 5 deletions components/esp_driver_isp/include/driver/isp_af.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern "C" {
typedef struct {
isp_window_t window[ISP_AF_WINDOW_NUM]; ///< The sampling windows of AF
int edge_thresh; ///< Edge threshold, definition higher than this value will be counted as a valid pixel for calculating AF result
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
int intr_priority; ///< The interrupt priority, range 0~3, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
} esp_isp_af_config_t;

/**
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down
3 changes: 0 additions & 3 deletions components/esp_driver_isp/include/driver/isp_awb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions components/esp_driver_isp/include/driver/isp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct {
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
int intr_priority; ///< The interrupt priority, range 0~3
} esp_isp_processor_cfg_t;

/**
Expand Down
12 changes: 12 additions & 0 deletions components/esp_driver_isp/include/driver/isp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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
39 changes: 34 additions & 5 deletions components/esp_driver_isp/include/esp_private/isp_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ extern "C" {
#endif

#if CONFIG_ISP_ISR_IRAM_SAFE
#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM)
#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM)
#define ISP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else
#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)
#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED)
#define ISP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif

typedef enum {
ISP_FSM_INIT,
ISP_FSM_ENABLE,
ISP_FSM_START,
ISP_FSM_INIT, // Controller is initialized, but not enabled
ISP_FSM_ENABLE, // Controller is enabled, but is not running
ISP_FSM_START, // Controller is in running

ISP_FSM_ONESHOT, // Controller is in oneshot sampling
ISP_FSM_CONTINUOUS, // Controller is in continuous sampling
} isp_fsm_t;

#if SOC_ISP_SUPPORTED
Expand All @@ -66,9 +69,35 @@ 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;
/* ISR */
intr_handle_t intr_hdl;
int intr_priority;
int isr_ref_counts;
struct {
uint32_t af_isr_added: 1;
uint32_t ae_isr_added: 1;
uint32_t awb_isr_added: 1;
} isr_users;

} isp_processor_t;
#endif

typedef enum {
ISP_SUBMODULE_AF,
ISP_SUBMODULE_AE,
ISP_SUBMODULE_AWB,
} isp_submodule_t;

/*---------------------------------------------------------------
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);
bool esp_isp_ae_isr(isp_proc_handle_t proc, uint32_t ae_events);
bool esp_isp_awb_isr(isp_proc_handle_t proc, uint32_t awb_events);

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit 3e974bd

Please sign in to comment.