Skip to content

Commit 1d73d88

Browse files
New feature: Added OV5640 Auto-Focus 🎉 (#831)
* New feature: Adeed OV5640 Auto-Focus 🎉 * refactor: make autofocus driver sensor-agnostic * fix: move TAG definition inside CONFIG_CAMERA_AF_SUPPORT and guard with log level check --------- Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
1 parent 23d1da7 commit 1d73d88

File tree

27 files changed

+1088
-1
lines changed

27 files changed

+1088
-1
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ set(include_dirs
2424
if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3")
2525
list(APPEND srcs
2626
driver/esp_camera.c
27+
driver/esp_camera_af.c
2728
driver/cam_hal.c
2829
driver/sensor.c
2930
sensors/ov2640.c
3031
sensors/ov3660.c
3132
sensors/ov5640.c
33+
sensors/ov5640_af.c
3234
sensors/ov7725.c
3335
sensors/ov7670.c
3436
sensors/nt99141.c

Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@ menu "Camera configuration"
4242
Enable this option if you want to use the OV5640.
4343
Disable this option to save memory.
4444

45+
config CAMERA_AF_SUPPORT
46+
bool "Enable autofocus (OV5640)"
47+
depends on OV5640_SUPPORT
48+
default n
49+
help
50+
Enable OV5640 autofocus support via the esp_camera_af API.
51+
If disabled, the AF API will return ESP_ERR_NOT_SUPPORTED.
52+
53+
config CAMERA_AF_DEFAULT_TIMEOUT_MS
54+
int "Autofocus default timeout (ms)"
55+
depends on CAMERA_AF_SUPPORT
56+
range 100 20000
57+
default 2000
58+
help
59+
Default timeout used for autofocus operations (firmware load, trigger/wait).
60+
4561
config GC2145_SUPPORT
4662
bool "Support GC2145 2MP"
4763
default y

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ESP32 Camera Driver
22

33
[![Build examples](https://github.com/espressif/esp32-camera/actions/workflows/build.yml/badge.svg)](https://github.com/espressif/esp32-camera/actions/workflows/build.yml) [![Component Registry](https://components.espressif.com/components/espressif/esp32-camera/badge.svg)](https://components.espressif.com/components/espressif/esp32-camera)
4+
45
## General Information
56

67
This repository hosts ESP32 series Soc compatible driver for image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
@@ -43,7 +44,6 @@ This repository hosts ESP32 series Soc compatible driver for image sensors. Addi
4344

4445
## Installation Instructions
4546

46-
4747
### Using with ESP-IDF
4848

4949
- Add a dependency on `espressif/esp32-camera` component:
@@ -366,5 +366,37 @@ esp_err_t bmp_httpd_handler(httpd_req_t *req){
366366
}
367367
```
368368
369+
### Autofocus (OV5640)
370+
371+
This component includes an optional autofocus helper for OV5640 modules that have an AF-capable lens.
372+
373+
- Enable it in `menuconfig`: `Component config` → `Camera configuration` → `Enable autofocus (OV5640)`.
374+
- Include the header: `#include "esp_camera_af.h"`.
375+
376+
Basic usage:
377+
378+
```c
379+
#include "esp_camera.h"
380+
#include "esp_camera_af.h"
381+
382+
// After esp_camera_init(...)
383+
sensor_t *s = esp_camera_sensor_get();
384+
385+
esp_camera_af_config_t af_cfg = {
386+
.mode = ESP_CAMERA_AF_MODE_AUTO,
387+
.timeout_ms = 2000,
388+
};
389+
390+
ESP_ERROR_CHECK(esp_camera_af_init(s, &af_cfg));
391+
392+
// Optional: trigger a single AF cycle and wait for completion
393+
ESP_ERROR_CHECK(esp_camera_af_trigger(s));
394+
395+
esp_camera_af_status_t st;
396+
ESP_ERROR_CHECK(esp_camera_af_wait(s, 0, &st));
397+
```
369398

399+
Notes:
370400

401+
- If autofocus is disabled (or the sensor is not OV5640), the AF APIs return `ESP_ERR_NOT_SUPPORTED`.
402+
- OV5640 autofocus relies on loading an internal firmware blob over SCCB during `esp_camera_af_init()`.

driver/esp_camera_af.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#include "sdkconfig.h"
2+
3+
#include "esp_camera_af.h"
4+
5+
#include <string.h>
6+
7+
#include "freertos/FreeRTOS.h"
8+
#include "freertos/task.h"
9+
#include "esp_timer.h"
10+
11+
#ifndef CONFIG_CAMERA_AF_DEFAULT_TIMEOUT_MS
12+
#define CONFIG_CAMERA_AF_DEFAULT_TIMEOUT_MS 2000
13+
#endif
14+
15+
#if defined(CONFIG_CAMERA_AF_SUPPORT) && CONFIG_CAMERA_AF_SUPPORT
16+
17+
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
18+
#include "esp32-hal-log.h"
19+
#define TAG ""
20+
#else
21+
#include "esp_log.h"
22+
#if CONFIG_LOG_DEFAULT_LEVEL > 0
23+
static const char *TAG = "camera_af";
24+
#endif
25+
#endif
26+
27+
static uint32_t s_default_timeout_ms = CONFIG_CAMERA_AF_DEFAULT_TIMEOUT_MS;
28+
29+
bool esp_camera_af_is_supported(const sensor_t *sensor)
30+
{
31+
if (!sensor || !sensor->af_is_supported) {
32+
return false;
33+
}
34+
return sensor->af_is_supported((sensor_t *)sensor) != 0;
35+
}
36+
37+
esp_err_t esp_camera_af_init(sensor_t *sensor, const esp_camera_af_config_t *config)
38+
{
39+
if (!sensor || !config) {
40+
return ESP_ERR_INVALID_ARG;
41+
}
42+
43+
if (config->timeout_ms) {
44+
s_default_timeout_ms = config->timeout_ms;
45+
}
46+
47+
if (!esp_camera_af_is_supported(sensor)) {
48+
return ESP_ERR_NOT_SUPPORTED;
49+
}
50+
51+
if (!sensor->af_init) {
52+
return ESP_ERR_NOT_SUPPORTED;
53+
}
54+
55+
int ret = sensor->af_init(sensor, s_default_timeout_ms);
56+
if (ret < 0) {
57+
ESP_LOGE(TAG, "AF init failed");
58+
return ESP_FAIL;
59+
}
60+
61+
return esp_camera_af_set_mode(sensor, config->mode);
62+
}
63+
64+
esp_err_t esp_camera_af_set_mode(sensor_t *sensor, esp_camera_af_mode_t mode)
65+
{
66+
if (!sensor) {
67+
return ESP_ERR_INVALID_ARG;
68+
}
69+
if (!esp_camera_af_is_supported(sensor)) {
70+
return ESP_ERR_NOT_SUPPORTED;
71+
}
72+
73+
if (!sensor->af_set_mode) {
74+
return ESP_ERR_NOT_SUPPORTED;
75+
}
76+
77+
int ret = sensor->af_set_mode(sensor, (int)mode);
78+
return (ret == 0) ? ESP_OK : ESP_FAIL;
79+
}
80+
81+
esp_err_t esp_camera_af_trigger(sensor_t *sensor)
82+
{
83+
if (!sensor) {
84+
return ESP_ERR_INVALID_ARG;
85+
}
86+
if (!esp_camera_af_is_supported(sensor)) {
87+
return ESP_ERR_NOT_SUPPORTED;
88+
}
89+
90+
if (!sensor->af_trigger) {
91+
return ESP_ERR_NOT_SUPPORTED;
92+
}
93+
94+
int ret = sensor->af_trigger(sensor);
95+
return (ret == 0) ? ESP_OK : ESP_FAIL;
96+
}
97+
98+
esp_err_t esp_camera_af_get_status(sensor_t *sensor, esp_camera_af_status_t *out_status)
99+
{
100+
if (!sensor || !out_status) {
101+
return ESP_ERR_INVALID_ARG;
102+
}
103+
if (!esp_camera_af_is_supported(sensor)) {
104+
return ESP_ERR_NOT_SUPPORTED;
105+
}
106+
107+
if (!sensor->af_get_status) {
108+
return ESP_ERR_NOT_SUPPORTED;
109+
}
110+
111+
memset(out_status, 0, sizeof(*out_status));
112+
int ret = sensor->af_get_status(sensor, &out_status->raw, &out_status->focused, &out_status->busy);
113+
return (ret == 0) ? ESP_OK : ESP_FAIL;
114+
}
115+
116+
esp_err_t esp_camera_af_wait(sensor_t *sensor, uint32_t timeout_ms, esp_camera_af_status_t *out_status)
117+
{
118+
if (!sensor || !out_status) {
119+
return ESP_ERR_INVALID_ARG;
120+
}
121+
if (!esp_camera_af_is_supported(sensor)) {
122+
return ESP_ERR_NOT_SUPPORTED;
123+
}
124+
125+
if (!timeout_ms) {
126+
timeout_ms = s_default_timeout_ms;
127+
}
128+
129+
const uint64_t start = esp_timer_get_time();
130+
while (true) {
131+
esp_err_t ret = esp_camera_af_get_status(sensor, out_status);
132+
if (ret != ESP_OK) {
133+
return ret;
134+
}
135+
136+
if (!out_status->busy) {
137+
return ESP_OK;
138+
}
139+
140+
if (timeout_ms && ((esp_timer_get_time() - start) / 1000ULL) > timeout_ms) {
141+
return ESP_ERR_TIMEOUT;
142+
}
143+
144+
vTaskDelay(pdMS_TO_TICKS(5));
145+
}
146+
}
147+
148+
esp_err_t esp_camera_af_set_manual_position(sensor_t *sensor, uint16_t position)
149+
{
150+
if (!sensor) {
151+
return ESP_ERR_INVALID_ARG;
152+
}
153+
if (!esp_camera_af_is_supported(sensor)) {
154+
return ESP_ERR_NOT_SUPPORTED;
155+
}
156+
157+
if (!sensor->af_set_manual_position) {
158+
return ESP_ERR_NOT_SUPPORTED;
159+
}
160+
161+
int ret = sensor->af_set_manual_position(sensor, position);
162+
return (ret == 0) ? ESP_OK : ESP_FAIL;
163+
}
164+
165+
#else // CONFIG_CAMERA_AF_SUPPORT
166+
167+
bool esp_camera_af_is_supported(const sensor_t *sensor)
168+
{
169+
(void)sensor;
170+
return false;
171+
}
172+
173+
esp_err_t esp_camera_af_init(sensor_t *sensor, const esp_camera_af_config_t *config)
174+
{
175+
(void)sensor;
176+
(void)config;
177+
return ESP_ERR_NOT_SUPPORTED;
178+
}
179+
180+
esp_err_t esp_camera_af_set_mode(sensor_t *sensor, esp_camera_af_mode_t mode)
181+
{
182+
(void)sensor;
183+
(void)mode;
184+
return ESP_ERR_NOT_SUPPORTED;
185+
}
186+
187+
esp_err_t esp_camera_af_trigger(sensor_t *sensor)
188+
{
189+
(void)sensor;
190+
return ESP_ERR_NOT_SUPPORTED;
191+
}
192+
193+
esp_err_t esp_camera_af_get_status(sensor_t *sensor, esp_camera_af_status_t *out_status)
194+
{
195+
(void)sensor;
196+
(void)out_status;
197+
return ESP_ERR_NOT_SUPPORTED;
198+
}
199+
200+
esp_err_t esp_camera_af_wait(sensor_t *sensor, uint32_t timeout_ms, esp_camera_af_status_t *out_status)
201+
{
202+
(void)sensor;
203+
(void)timeout_ms;
204+
(void)out_status;
205+
return ESP_ERR_NOT_SUPPORTED;
206+
}
207+
208+
esp_err_t esp_camera_af_set_manual_position(sensor_t *sensor, uint16_t position)
209+
{
210+
(void)sensor;
211+
(void)position;
212+
return ESP_ERR_NOT_SUPPORTED;
213+
}
214+
215+
#endif // CONFIG_CAMERA_AF_SUPPORT

0 commit comments

Comments
 (0)