Skip to content

Commit

Permalink
Merge branch 'feature/support_isp_hisp_p4' into 'master'
Browse files Browse the repository at this point in the history
feature(isp): Add ISP histogram support for esp32p4

Closes IDF-10192

See merge request espressif/esp-idf!31342
  • Loading branch information
Bruce297 committed Aug 28, 2024
2 parents 0058444 + c3155c3 commit 0e4464c
Show file tree
Hide file tree
Showing 18 changed files with 1,034 additions and 268 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 @@ -14,7 +14,8 @@ if(CONFIG_SOC_ISP_SUPPORTED)
"src/isp_ccm.c"
"src/isp_awb.c"
"src/isp_ae.c"
"src/isp_gamma.c")
"src/isp_gamma.c"
"src/isp_hist.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 @@ -18,3 +18,4 @@
#include "driver/isp_bf.h"
#include "driver/isp_ccm.h"
#include "driver/isp_sharpen.h"
#include "driver/isp_hist.h"
2 changes: 1 addition & 1 deletion components/esp_driver_isp/include/driver/isp_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,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
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_processor_cfg_t;

/**
Expand Down
186 changes: 186 additions & 0 deletions components/esp_driver_isp/include/driver/isp_hist.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* 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

/*
* ISP Histogram Struct
* |<----------------------------- INTERVAL_NUMS = 16 ------------------------------>|
* | | | | |
* | Segment 0 | Segment 1 | ............ | Segment 15 |
* 0 threshold 0 threshold 1 ... threshold 14 255
* |<------------------------------------------------------------------------------->|
*/

/**
* @brief Hist controller config
*/
typedef struct {
isp_window_t window; /*!< The sampling window of histogram, see `isp_window_t`*/
isp_hist_sampling_mode_t hist_mode; /*!< ISP histogram sampling mode */
isp_hist_rgb_coefficient_t rgb_coefficient; /*!< RGB coefficients, adjust the sensitivity to red, geen, and blue colors in the image,
only effect when hist_mode is ISP_HIST_SAMPLING_RGB, the sum of all coefficients decimal should be 256**/
isp_hist_weight_t window_weight[ISP_HIST_BLOCK_X_NUM * ISP_HIST_BLOCK_Y_NUM]; /*!< Weights of histogram's each subwindows, the sum of all subwindows's weight decimal should be 256*/
uint32_t segment_threshold[ISP_HIST_INTERVAL_NUMS]; /*!< Threshold to segment the histogram into intervals, range 0~255 */
} esp_isp_hist_config_t;

/**
* @brief New an ISP hist controller
*
* @param[in] isp_proc ISP Processor handle
* @param[in] hist_cfg Pointer to hist config. Refer to ``esp_isp_hist_config_t``.
* @param[out] ret_hdl hist 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_hist_controller(isp_proc_handle_t isp_proc, const esp_isp_hist_config_t *hist_cfg, isp_hist_ctlr_t *ret_hdl);

/**
* @brief Delete an ISP hist controller
*
* @param[in] hist_ctlr hist 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_hist_controller(isp_hist_ctlr_t hist_ctlr);

/**
* @brief Enable an ISP hist controller
*
* @param[in] hist_ctlr hist 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_hist_controller_enable(isp_hist_ctlr_t hist_ctlr);

/**
* @brief Disable an ISP hist controller
*
* @param[in] hist_ctlr hist 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_hist_controller_disable(isp_hist_ctlr_t hist_ctlr);

/**
* @brief Trigger hist reference statistics for one time and get the result
*
* @param[in] hist_ctlr hist 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_hist_cbs_t::on_statistics_done`
* - timeout_ms > 0: Wait for specified milliseconds, if not finished, then return timeout error
* @param[out] out_res hist reference statistics result
*
* @return
* - ESP_OK On success
* - ESP_ERR_TIMEOUT Wait for the result 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_hist_controller_get_oneshot_statistics(isp_hist_ctlr_t hist_ctlr, int timeout_ms, isp_hist_result_t *out_res);

/**
* @brief Start hist continuous statistics of the reference in the window
* @note This function is an asynchronous and non-block function,
* it will start the continuous statistics and return immediately.
* You have to register the hist callback and get the result from the callback event data.
*
* @param[in] hist_ctlr hist 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_hist_controller_start_continuous_statistics(isp_hist_ctlr_t hist_ctlr);

/**
* @brief Stop hist continuous statistics of the reference in the window
*
* @param[in] hist_ctlr hist 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_hist_controller_stop_continuous_statistics(isp_hist_ctlr_t hist_ctlr);

/**
* @brief Event data of callbacks
*/
typedef struct {
isp_hist_result_t hist_result; /*!< The histogram reference statistics result */
} esp_isp_hist_evt_data_t;

/**
* @brief Prototype of ISP hist event callback
*
* @param[in] handle ISP hist controller handle
* @param[in] edata ISP hist event data
* @param[in] user_data User registered context, registered when in `esp_isp_hist_register_event_callbacks()`
*
* @return Whether a high priority task is woken up by this function
*/
typedef bool (*esp_isp_hist_callback_t)(isp_hist_ctlr_t hist_ctlr, const esp_isp_hist_evt_data_t *edata, void *user_data);

/**
* @brief Group of ISP hist 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_hist_callback_t on_statistics_done; ///< Event callback, invoked when histogram statistic done.
} esp_isp_hist_cbs_t;

/**
* @brief Register hist 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] hist_ctlr hist 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_hist_register_event_callbacks(isp_hist_ctlr_t hist_ctlr, const esp_isp_hist_cbs_t *cbs, void *user_data);

#ifdef __cplusplus
}
#endif
5 changes: 5 additions & 0 deletions components/esp_driver_isp/include/driver/isp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ typedef struct isp_awb_controller_t *isp_awb_ctlr_t;
*/
typedef struct isp_ae_controller_t *isp_ae_ctlr_t;

/**
* @brief Type of ISP HIST controller handle
*/
typedef struct isp_hist_controller_t *isp_hist_ctlr_t;

/*---------------------------------------------
Event Callbacks
----------------------------------------------*/
Expand Down
4 changes: 4 additions & 0 deletions components/esp_driver_isp/include/esp_private/isp_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct isp_processor_t {
isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS];
isp_awb_ctlr_t awb_ctlr;
isp_ae_ctlr_t ae_ctlr;
isp_hist_ctlr_t hist_ctlr;
isp_fsm_t bf_fsm;
isp_fsm_t sharpen_fsm;
esp_isp_evt_cbs_t cbs;
Expand All @@ -82,6 +83,7 @@ typedef struct isp_processor_t {
uint32_t ae_isr_added: 1;
uint32_t awb_isr_added: 1;
uint32_t sharp_isr_added: 1;
uint32_t hist_isr_added: 1;
} isr_users;

} isp_processor_t;
Expand All @@ -92,6 +94,7 @@ typedef enum {
ISP_SUBMODULE_AE,
ISP_SUBMODULE_AWB,
ISP_SUBMODULE_SHARPEN,
ISP_SUBMODULE_HIST,
} isp_submodule_t;

/*---------------------------------------------------------------
Expand All @@ -103,6 +106,7 @@ 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);
bool esp_isp_sharpen_isr(isp_proc_handle_t proc, uint32_t sharp_events);
bool esp_isp_hist_isr(isp_proc_handle_t proc, uint32_t hist_events);

#ifdef __cplusplus
}
Expand Down
18 changes: 17 additions & 1 deletion components/esp_driver_isp/src/isp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ static void IRAM_ATTR s_isp_isr_dispatcher(void *arg)
uint32_t awb_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AWB_MASK);
uint32_t ae_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AE_MASK);
uint32_t sharp_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_SHARP_MASK);
uint32_t hist_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_HIST_MASK);

bool do_dispatch = false;
//Deal with hw events
Expand Down Expand Up @@ -274,7 +275,16 @@ static void IRAM_ATTR s_isp_isr_dispatcher(void *arg)
}
do_dispatch = false;
}
if (hist_events) {
portENTER_CRITICAL_ISR(&proc->spinlock);
do_dispatch = proc->isr_users.hist_isr_added;
portEXIT_CRITICAL_ISR(&proc->spinlock);

if (do_dispatch) {
need_yield |= esp_isp_hist_isr(proc, hist_events);
}
do_dispatch = false;
}
if (need_yield) {
portYIELD_FROM_ISR();
}
Expand Down Expand Up @@ -306,6 +316,9 @@ esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule
case ISP_SUBMODULE_SHARPEN:
proc->isr_users.sharp_isr_added = true;
break;
case ISP_SUBMODULE_HIST:
proc->isr_users.hist_isr_added = true;
break;
default:
assert(false);
}
Expand All @@ -314,7 +327,7 @@ esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule
if (do_alloc) {

uint32_t intr_st_reg_addr = isp_ll_get_intr_status_reg_addr(proc->hal.hw);
uint32_t intr_st_mask = ISP_LL_EVENT_AF_MASK | ISP_LL_EVENT_AE_MASK | ISP_LL_EVENT_AWB_MASK;
uint32_t intr_st_mask = ISP_LL_EVENT_AF_MASK | ISP_LL_EVENT_AE_MASK | ISP_LL_EVENT_AWB_MASK | ISP_LL_EVENT_HIST_MASK;
ret = esp_intr_alloc_intrstatus(isp_hw_info.instances[proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | proc->intr_priority, intr_st_reg_addr, intr_st_mask,
s_isp_isr_dispatcher, (void *)proc, &proc->intr_hdl);
if (ret != ESP_OK) {
Expand Down Expand Up @@ -354,6 +367,9 @@ esp_err_t esp_isp_deregister_isr(isp_proc_handle_t proc, isp_submodule_t submodu
case ISP_SUBMODULE_SHARPEN:
proc->isr_users.sharp_isr_added = false;
break;
case ISP_SUBMODULE_HIST:
proc->isr_users.hist_isr_added = false;
break;
default:
assert(false);
}
Expand Down
Loading

0 comments on commit 0e4464c

Please sign in to comment.