vision/managed_components/espressif__esp32-camera/sensors/ov5640_af.c

242 lines
6.1 KiB
C

/*
* OV5640 Autofocus Implementation
*
* This file contains the sensor-specific autofocus implementation for OV5640.
*/
#include "sdkconfig.h"
#if defined(CONFIG_CAMERA_AF_SUPPORT) && CONFIG_CAMERA_AF_SUPPORT
#if defined(CONFIG_OV5640_SUPPORT) && CONFIG_OV5640_SUPPORT
#include "ov5640.h"
#include "ov5640_af_firmware.h"
#include "sensor.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define TAG ""
#else
#include "esp_log.h"
static const char *TAG = "ov5640_af";
#endif
// OV5640 AF registers
#define OV5640_CMD_MAIN 0x3022
#define OV5640_CMD_ACK 0x3023
#define OV5640_CMD_PARA0 0x3024
#define OV5640_CMD_PARA1 0x3025
#define OV5640_CMD_PARA2 0x3026
#define OV5640_CMD_PARA3 0x3027
#define OV5640_CMD_PARA4 0x3028
#define OV5640_CMD_FW_STATUS 0x3029
#define OV5640_AF_TRIG_SINGLE 0x03
#define OV5640_AF_CONTINUOUS 0x04
#define OV5640_FW_STATUS_IDLE 0x70
#define OV5640_FW_STATUS_FOCUSED 0x10
static esp_err_t ov5640_reg_write(sensor_t *sensor, int reg, int value)
{
if (sensor->set_reg(sensor, reg, 0xff, value) < 0) {
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t ov5640_reg_read(sensor_t *sensor, int reg, int *out_value)
{
int v = sensor->get_reg(sensor, reg, 0xff);
if (v < 0) {
return ESP_FAIL;
}
*out_value = v;
return ESP_OK;
}
static esp_err_t ov5640_af_wait_ack_clear(sensor_t *sensor, uint32_t timeout_ms)
{
const uint64_t start = esp_timer_get_time();
while (true) {
int ack = 0;
if (ov5640_reg_read(sensor, OV5640_CMD_ACK, &ack) != ESP_OK) {
return ESP_FAIL;
}
if (ack == 0x00) {
return ESP_OK;
}
if (timeout_ms && ((esp_timer_get_time() - start) / 1000ULL) > timeout_ms) {
return ESP_ERR_TIMEOUT;
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
static esp_err_t ov5640_af_wait_fw_idle(sensor_t *sensor, uint32_t timeout_ms)
{
const uint64_t start = esp_timer_get_time();
while (true) {
int st = 0;
if (ov5640_reg_read(sensor, OV5640_CMD_FW_STATUS, &st) != ESP_OK) {
return ESP_FAIL;
}
if ((uint8_t)st == OV5640_FW_STATUS_IDLE) {
return ESP_OK;
}
if (timeout_ms && ((esp_timer_get_time() - start) / 1000ULL) > timeout_ms) {
return ESP_ERR_TIMEOUT;
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
static esp_err_t ov5640_af_firmware_load(sensor_t *sensor, uint32_t timeout_ms)
{
esp_err_t ret = ov5640_reg_write(sensor, 0x3000, 0x20); // reset MCU
if (ret != ESP_OK) {
return ret;
}
uint16_t addr = 0x8000;
for (size_t i = 0; i < sizeof(ov5640_af_firmware); i++) {
ret = ov5640_reg_write(sensor, addr, ov5640_af_firmware[i]);
if (ret != ESP_OK) {
return ret;
}
addr++;
}
(void)ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_ACK, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA0, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA1, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA2, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA3, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA4, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_FW_STATUS, 0x7f);
(void)ov5640_reg_write(sensor, 0x3000, 0x00); // start MCU
return ov5640_af_wait_fw_idle(sensor, timeout_ms);
}
static esp_err_t ov5640_af_start(sensor_t *sensor, bool continuous, uint32_t timeout_ms)
{
esp_err_t ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x01);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x08);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_af_wait_ack_clear(sensor, timeout_ms);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_ACK, 0x01);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, continuous ? OV5640_AF_CONTINUOUS : OV5640_AF_TRIG_SINGLE);
if (ret != ESP_OK) {
return ret;
}
return ov5640_af_wait_ack_clear(sensor, timeout_ms);
}
// Sensor function pointer implementations
int ov5640_af_is_supported(sensor_t *sensor)
{
(void)sensor;
return 1; // OV5640 always supports AF
}
int ov5640_af_init(sensor_t *sensor, uint32_t timeout_ms)
{
if (!sensor) {
return -1;
}
esp_err_t ret = ov5640_af_firmware_load(sensor, timeout_ms);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "AF firmware init failed: %s", esp_err_to_name(ret));
return -1;
}
return 0;
}
int ov5640_af_set_mode(sensor_t *sensor, int mode)
{
if (!sensor) {
return -1;
}
esp_err_t ret;
switch (mode) {
case 0: // ESP_CAMERA_AF_MODE_AUTO
ret = ov5640_af_start(sensor, true, 2000);
break;
case 1: // ESP_CAMERA_AF_MODE_MANUAL
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x00);
break;
default:
return -1;
}
return (ret == ESP_OK) ? 0 : -1;
}
int ov5640_af_trigger(sensor_t *sensor)
{
if (!sensor) {
return -1;
}
esp_err_t ret = ov5640_af_start(sensor, false, 2000);
return (ret == ESP_OK) ? 0 : -1;
}
int ov5640_af_get_status(sensor_t *sensor, uint8_t *out_raw, bool *out_focused, bool *out_busy)
{
if (!sensor || !out_raw || !out_focused || !out_busy) {
return -1;
}
int st = 0;
esp_err_t ret = ov5640_reg_read(sensor, OV5640_CMD_FW_STATUS, &st);
if (ret != ESP_OK) {
return -1;
}
*out_raw = (uint8_t)st;
*out_focused = ((uint8_t)st == OV5640_FW_STATUS_FOCUSED);
*out_busy = !(((uint8_t)st == OV5640_FW_STATUS_IDLE) || *out_focused);
return 0;
}
int ov5640_af_set_manual_position(sensor_t *sensor, uint16_t position)
{
(void)sensor;
(void)position;
// Manual lens position is not exposed safely in this driver yet.
return -1;
}
#endif // CONFIG_OV5640_SUPPORT
#endif // CONFIG_CAMERA_AF_SUPPORT