Skip to content

Commit

Permalink
Merge branch 'feature/manage_isp_continuous_oneshot_conflict' into 'm…
Browse files Browse the repository at this point in the history
…aster'

ISP: AE/AF/AWB continuous concurrent manage

Closes IDF-10579 and IDF-10672

See merge request espressif/esp-idf!32519
  • Loading branch information
Bruce297 committed Aug 5, 2024
2 parents 5dbf2ae + e3a717f commit ff4620a
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 113 deletions.
41 changes: 18 additions & 23 deletions components/esp_driver_isp/src/isp_ae.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,24 +171,22 @@ esp_err_t esp_isp_ae_controller_get_oneshot_statistics(isp_ae_ctlr_t ae_ctlr, in
TickType_t ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);

isp_fsm_t expected_fsm = ISP_FSM_ENABLE;
if (atomic_compare_exchange_strong(&ae_ctlr->fsm, &expected_fsm, ISP_FSM_ONESHOT)) {
// 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);
} else {
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "controller is not enabled yet");
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&ae_ctlr->fsm, &expected_fsm, ISP_FSM_ONESHOT), ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has started");

// 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);

atomic_store(&ae_ctlr->fsm, ISP_FSM_ENABLE);
return ret;
Expand All @@ -199,11 +197,8 @@ esp_err_t esp_isp_ae_controller_start_continuous_statistics(isp_ae_ctlr_t ae_ctl
ESP_RETURN_ON_FALSE_ISR(ae_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");

isp_fsm_t expected_fsm = ISP_FSM_ENABLE;
if (atomic_compare_exchange_strong(&ae_ctlr->fsm, &expected_fsm, ISP_FSM_CONTINUOUS)) {
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);
} else {
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "controller is not enabled yet");
}
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&ae_ctlr->fsm, &expected_fsm, ISP_FSM_CONTINUOUS), ESP_ERR_INVALID_STATE, TAG, "controller is not enabled yet");
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);

return ESP_OK;
}
Expand Down Expand Up @@ -297,7 +292,7 @@ bool IRAM_ATTR esp_isp_ae_isr(isp_proc_handle_t proc, uint32_t ae_events)
need_yield |= high_task_awake == pdTRUE;

/* If started continuous sampling, then trigger the next AE sample */
if (atomic_load(&ae_ctlr->fsm) == ISP_FSM_START) {
if (atomic_load(&ae_ctlr->fsm) == ISP_FSM_CONTINUOUS) {
isp_ll_ae_manual_update(ae_ctlr->isp_proc->hal.hw);
}
}
Expand Down
104 changes: 54 additions & 50 deletions components/esp_driver_isp/src/isp_af.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <esp_types.h>
#include <sys/lock.h>
#include <stdatomic.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
Expand All @@ -18,7 +19,7 @@ static const char *TAG = "ISP_AF";

typedef struct isp_af_controller_t {
int id;
isp_fsm_t fsm;
_Atomic isp_fsm_t fsm;
portMUX_TYPE spinlock;
intr_handle_t intr_handle;
isp_proc_handle_t isp_proc;
Expand Down Expand Up @@ -104,7 +105,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af
ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem");
af_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_af_result_t), ISP_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(af_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for af event queue");
af_ctlr->fsm = ISP_FSM_INIT;
atomic_init(&af_ctlr->fsm, ISP_FSM_INIT);
af_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
af_ctlr->isp_proc = isp_proc;

Expand Down Expand Up @@ -141,7 +142,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af
esp_err_t esp_isp_del_af_controller(isp_af_ctlr_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");
ESP_RETURN_ON_FALSE(atomic_load(&af_ctlr->fsm) == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller not in init state");
bool exist = false;
for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) {
if (af_ctlr->isp_proc->af_ctlr[i] == af_ctlr) {
Expand All @@ -163,95 +164,98 @@ esp_err_t esp_isp_del_af_controller(isp_af_ctlr_t af_ctlr)
esp_err_t esp_isp_af_controller_enable(isp_af_ctlr_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_fsm_t expected_fsm = ISP_FSM_INIT;
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&af_ctlr->fsm, &expected_fsm, ISP_FSM_ENABLE),
ESP_ERR_INVALID_STATE, TAG, "controller not in init state");

isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, true);
isp_ll_enable_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_MASK, 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_ctlr_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_fsm_t expected_fsm = ISP_FSM_ENABLE;
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&af_ctlr->fsm, &expected_fsm, ISP_FSM_INIT),
ESP_ERR_INVALID_STATE, TAG, "controller not in enable state");

isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, false);
isp_ll_enable_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_MASK, false);
isp_ll_af_enable(af_ctlr->isp_proc->hal.hw, false);
esp_intr_disable(af_ctlr->intr_handle);
af_ctlr->fsm = ISP_FSM_INIT;

return ESP_OK;
}

esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res)
esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctlr, int timeout_ms, isp_af_result_t *out_res)
{
ESP_RETURN_ON_FALSE_ISR(af_ctrlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has started");
ESP_RETURN_ON_FALSE_ISR(af_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);
isp_fsm_t expected_fsm = ISP_FSM_ENABLE;
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&af_ctlr->fsm, &expected_fsm, ISP_FSM_ONESHOT), ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has starte");

// Reset the queue in case receiving the legacy data in the queue
xQueueReset(af_ctrlr->evt_que);
xQueueReset(af_ctlr->evt_que);
// Trigger the AF statistics manually
isp_ll_af_manual_update(af_ctrlr->isp_proc->hal.hw);
isp_ll_af_manual_update(af_ctlr->isp_proc->hal.hw);
// Wait the statistics to finish and receive the result from the queue
if ((ticks > 0) && xQueueReceive(af_ctrlr->evt_que, out_res, ticks) != pdTRUE) {
if ((ticks > 0) && xQueueReceive(af_ctlr->evt_que, out_res, ticks) != pdTRUE) {
ret = ESP_ERR_TIMEOUT;
}

atomic_store(&af_ctlr->fsm, ISP_FSM_ENABLE);
return ret;
}

esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctrlr)
esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctlr)
{
ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state");

af_ctrlr->fsm = ISP_FSM_START;
isp_ll_af_enable_auto_update(af_ctrlr->isp_proc->hal.hw, true);
ESP_RETURN_ON_FALSE_ISR(af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
isp_fsm_t expected_fsm = ISP_FSM_ENABLE;
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&af_ctlr->fsm, &expected_fsm, ISP_FSM_CONTINUOUS), ESP_ERR_INVALID_STATE, TAG, "controller is not enabled yet");
isp_ll_af_enable_auto_update(af_ctlr->isp_proc->hal.hw, true);

return ESP_OK;
}

esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr)
esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctlr)
{
ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state");

isp_ll_af_enable_auto_update(af_ctrlr->isp_proc->hal.hw, false);
af_ctrlr->fsm = ISP_FSM_ENABLE;
ESP_RETURN_ON_FALSE_ISR(af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
isp_fsm_t expected_fsm = ISP_FSM_CONTINUOUS;
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&af_ctlr->fsm, &expected_fsm, ISP_FSM_ENABLE), ESP_ERR_INVALID_STATE, TAG, "controller is not enabled yet");
isp_ll_af_enable_auto_update(af_ctlr->isp_proc->hal.hw, false);

return ESP_OK;
}

/*---------------------------------------------
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)
esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctlr, const esp_isp_af_env_config_t *env_config)
{
ESP_RETURN_ON_FALSE(af_ctrlr && env_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "invalid fsm, should be called when in init state");
ESP_RETURN_ON_FALSE(af_ctlr && env_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
ESP_RETURN_ON_FALSE(atomic_load(&af_ctlr->fsm) == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller not in init state");

af_ctrlr->config.interval = env_config->interval;
af_ctlr->config.interval = env_config->interval;

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_detector_set_period(af_ctlr->isp_proc->hal.hw, 0);
isp_ll_clear_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV);

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);
isp_ll_af_env_detector_set_mode(af_ctlr->isp_proc->hal.hw, ISP_LL_AF_ENV_DETECTOR_MODE_ABS);
isp_ll_af_env_detector_set_period(af_ctlr->isp_proc->hal.hw, af_ctlr->config.interval);
isp_ll_enable_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV, true);

return ESP_OK;
}

esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data)
esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data)
{
ESP_RETURN_ON_FALSE(af_ctrlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state");
ESP_RETURN_ON_FALSE(af_ctlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(atomic_load(&af_ctlr->fsm) == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller not in init state");

#if CONFIG_ISP_ISR_IRAM_SAFE
if (cbs->on_env_statistics_done) {
Expand All @@ -264,19 +268,19 @@ esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrl
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
}
#endif
af_ctrlr->cbs.on_env_statistics_done = cbs->on_env_statistics_done;
af_ctrlr->cbs.on_env_change = cbs->on_env_change;
af_ctrlr->user_data = user_data;
af_ctlr->cbs.on_env_statistics_done = cbs->on_env_statistics_done;
af_ctlr->cbs.on_env_change = cbs->on_env_change;
af_ctlr->user_data = user_data;

return ESP_OK;
}

esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctrlr, int definition_thresh, int luminance_thresh)
esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctlr, int definition_thresh, int luminance_thresh)
{
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");
ESP_RETURN_ON_FALSE_ISR(af_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(atomic_load(&af_ctlr->fsm) == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller not in enable state");

isp_ll_af_env_detector_set_thresh(af_ctrlr->isp_proc->hal.hw, definition_thresh, luminance_thresh);
isp_ll_af_env_detector_set_thresh(af_ctlr->isp_proc->hal.hw, definition_thresh, luminance_thresh);

return ESP_OK;
}
Expand All @@ -286,7 +290,7 @@ esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctrl
---------------------------------------------------------------*/
bool IRAM_ATTR esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events)
{
isp_af_ctlr_t af_ctrlr = proc->af_ctlr[0];
isp_af_ctlr_t af_ctlr = proc->af_ctlr[0];

bool need_yield = false;
esp_isp_af_env_detector_evt_data_t edata = {};
Expand All @@ -307,17 +311,17 @@ bool IRAM_ATTR esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events)
if (af_events & ISP_LL_EVENT_AF_FDONE) {
BaseType_t high_task_awake = false;
// Send the event data to the queue, overwrite the legacy one if exist
xQueueOverwriteFromISR(af_ctrlr->evt_que, &edata.af_result, &high_task_awake);
xQueueOverwriteFromISR(af_ctlr->evt_que, &edata.af_result, &high_task_awake);
// Invoke the callback if the callback is registered
need_yield |= high_task_awake == pdTRUE;
if (af_ctrlr->cbs.on_env_statistics_done) {
need_yield |= af_ctrlr->cbs.on_env_statistics_done(af_ctrlr, &edata, af_ctrlr->user_data);
if (af_ctlr->cbs.on_env_statistics_done) {
need_yield |= af_ctlr->cbs.on_env_statistics_done(af_ctlr, &edata, af_ctlr->user_data);
}
}
if (af_events & ISP_LL_EVENT_AF_ENV) {
// Invoke the callback if the callback is registered
if (af_ctrlr->cbs.on_env_change) {
need_yield |= af_ctrlr->cbs.on_env_change(af_ctrlr, &edata, af_ctrlr->user_data);
if (af_ctlr->cbs.on_env_change) {
need_yield |= af_ctlr->cbs.on_env_change(af_ctlr, &edata, af_ctlr->user_data);
}
}
return need_yield;
Expand Down
Loading

0 comments on commit ff4620a

Please sign in to comment.