mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-26 05:09:19 +00:00
227 lines
7.0 KiB
C
227 lines
7.0 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "example_af.h"
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "driver/isp_af.h"
|
|
#include "isp_af_scheme_sa.h"
|
|
#include "esp_sccb_intf.h"
|
|
#include "example_config.h"
|
|
|
|
static const char *TAG = "isp_af";
|
|
|
|
// DW9714 register structure
|
|
typedef union {
|
|
struct {
|
|
uint16_t s : 4;
|
|
uint16_t d : 10;
|
|
uint16_t flag : 1;
|
|
uint16_t pd : 1;
|
|
};
|
|
struct {
|
|
uint16_t byte2 : 8;
|
|
uint16_t byte1 : 8;
|
|
};
|
|
uint16_t val;
|
|
} dw9714_reg_t;
|
|
|
|
static example_isp_af_task_param_t s_af_task_param = {0};
|
|
static TaskHandle_t s_af_task_handle = NULL;
|
|
|
|
/**
|
|
* @brief AF environment change callback (called from ISR)
|
|
*/
|
|
static bool IRAM_ATTR s_af_env_change_cb(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data)
|
|
{
|
|
BaseType_t mustYield = pdFALSE;
|
|
TaskHandle_t task_handle = (TaskHandle_t)user_data;
|
|
vTaskNotifyGiveFromISR(task_handle, &mustYield);
|
|
return (mustYield == pdTRUE);
|
|
}
|
|
|
|
/**
|
|
* @brief Set focus value to DW9714 VCM
|
|
*/
|
|
static esp_err_t s_sensor_set_focus_val(int focus_val, void *arg)
|
|
{
|
|
esp_sccb_io_handle_t dw9714_io_handle = arg;
|
|
|
|
dw9714_reg_t reg = {0};
|
|
reg.d = (uint16_t)((focus_val / 120.0) * 1023.0);
|
|
|
|
uint8_t data[2] = {0};
|
|
data[0] = reg.byte1;
|
|
data[1] = reg.byte2;
|
|
|
|
uint16_t reg_addr = (data[0] << 8) + (data[1]);
|
|
uint8_t reg_val = 0;
|
|
|
|
esp_err_t ret = esp_sccb_transmit_reg_a16v8(dw9714_io_handle, reg_addr, reg_val);
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "dw9714 esp_sccb_transmit_reg_a16v8 failed");
|
|
return ret;
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief AF task - continuously monitors and adjusts focus
|
|
*/
|
|
static void example_af_task(void *arg)
|
|
{
|
|
TaskHandle_t task_handle = xTaskGetCurrentTaskHandle();
|
|
example_isp_af_task_param_t af_task_param = *(example_isp_af_task_param_t *)arg;
|
|
|
|
// Default AF window configuration (centered window)
|
|
int window_size = 100;
|
|
int edge_thresh = 128;
|
|
int env_interval = 10;
|
|
int first_step_val = 12;
|
|
int first_approx_cycles = 10;
|
|
int second_step_val = 2;
|
|
int second_approx_cycles = 10;
|
|
int focus_val_max = 120;
|
|
|
|
// Use default values from example_config if available
|
|
int h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES;
|
|
int v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES;
|
|
|
|
/**
|
|
* AF window configuration
|
|
* Windows for ISP hardware to record the luminance and definition
|
|
*/
|
|
esp_isp_af_config_t af_config = {
|
|
.window = {
|
|
[0] = {
|
|
.top_left = {
|
|
.x = (h_res / 2) - window_size,
|
|
.y = (v_res / 2) - window_size,
|
|
},
|
|
.btm_right = {
|
|
.x = (h_res / 2) + window_size - 1,
|
|
.y = (v_res / 2) + window_size - 1,
|
|
},
|
|
},
|
|
[1] = {
|
|
.top_left = {
|
|
.x = (h_res / 2) - window_size,
|
|
.y = (v_res / 2) - window_size,
|
|
},
|
|
.btm_right = {
|
|
.x = (h_res / 2) + window_size - 1,
|
|
.y = (v_res / 2) + window_size - 1,
|
|
},
|
|
},
|
|
[2] = {
|
|
.top_left = {
|
|
.x = (h_res / 2) - window_size,
|
|
.y = (v_res / 2) - window_size,
|
|
},
|
|
.btm_right = {
|
|
.x = (h_res / 2) + window_size - 1,
|
|
.y = (v_res / 2) + window_size - 1,
|
|
},
|
|
},
|
|
},
|
|
.edge_thresh = edge_thresh,
|
|
};
|
|
|
|
isp_af_ctlr_t af_ctrlr = NULL;
|
|
ESP_ERROR_CHECK(esp_isp_new_af_controller(af_task_param.isp_proc, &af_config, &af_ctrlr));
|
|
|
|
// Configure environment detector
|
|
esp_isp_af_env_config_t env_config = {
|
|
.interval = env_interval,
|
|
};
|
|
ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config));
|
|
|
|
// Register environment change callback
|
|
esp_isp_af_env_detector_evt_cbs_t cbs = {
|
|
.on_env_change = s_af_env_change_cb,
|
|
};
|
|
ESP_ERROR_CHECK(esp_isp_af_env_detector_register_event_callbacks(af_ctrlr, &cbs, task_handle));
|
|
|
|
// Create SA (Step-and-Approach) scheme
|
|
isp_af_sa_scheme_config_t af_scheme_config = {
|
|
.first_step_val = first_step_val,
|
|
.first_approx_cycles = first_approx_cycles,
|
|
.second_step_val = second_step_val,
|
|
.second_approx_cycles = second_approx_cycles,
|
|
};
|
|
isp_af_scheme_handle_t af_scheme = NULL;
|
|
ESP_ERROR_CHECK(isp_af_create_sa_scheme(af_ctrlr, &af_scheme_config, &af_scheme));
|
|
|
|
// Register sensor driver
|
|
isp_af_sa_scheme_sensor_drv_t sensor_driver = {
|
|
.af_sensor_set_focus = s_sensor_set_focus_val,
|
|
};
|
|
isp_af_sa_scheme_sensor_info_t sensor_info = {
|
|
.focus_val_max = focus_val_max,
|
|
};
|
|
ESP_ERROR_CHECK(isp_af_sa_scheme_register_sensor_driver(af_scheme, &sensor_driver, &sensor_info, af_task_param.dw9714_io_handle));
|
|
|
|
// Enable AF controller
|
|
int definition_thresh = 0;
|
|
int luminance_thresh = 0;
|
|
ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr));
|
|
|
|
ESP_LOGI(TAG, "AF task started");
|
|
|
|
// Main AF loop
|
|
while (1) {
|
|
// Wait for environment change notification
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
|
|
// Process AF: adjust focus based on definition and luminance
|
|
ESP_ERROR_CHECK(isp_af_process(af_scheme, &definition_thresh, &luminance_thresh));
|
|
|
|
// Update environment detector thresholds
|
|
ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector_threshold(af_ctrlr, definition_thresh, luminance_thresh));
|
|
}
|
|
}
|
|
|
|
esp_err_t example_isp_af_init(isp_proc_handle_t isp_proc,
|
|
esp_sccb_io_handle_t dw9714_io_handle,
|
|
const example_isp_af_config_t *config)
|
|
{
|
|
if (isp_proc == NULL || dw9714_io_handle == NULL) {
|
|
ESP_LOGE(TAG, "Invalid arguments");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
s_af_task_param.isp_proc = isp_proc;
|
|
s_af_task_param.dw9714_io_handle = dw9714_io_handle;
|
|
|
|
ESP_LOGI(TAG, "AF module initialized");
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t example_isp_af_start(int task_priority, int core_id)
|
|
{
|
|
if (s_af_task_param.isp_proc == NULL) {
|
|
ESP_LOGE(TAG, "AF not initialized, call example_isp_af_init() first");
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
BaseType_t ret = xTaskCreatePinnedToCore(example_af_task,
|
|
"af_task",
|
|
8192,
|
|
&s_af_task_param,
|
|
task_priority,
|
|
&s_af_task_handle,
|
|
core_id);
|
|
if (ret != pdPASS) {
|
|
ESP_LOGE(TAG, "Failed to create AF task");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "AF task created");
|
|
return ESP_OK;
|
|
}
|