# terraview — ESP32-CAM pinout & the OV3660-clone quirk

Hardware reference for the terraview camera node. The board is a standard
**AI-Thinker ESP32-CAM**; the sensor that shipped on mine was **not** the
OV2640 it was sold as. More on that below.

## Camera (DVP) — AI-Thinker ESP32-CAM

These are fixed by the board's traces, not a wiring choice. Listed here so the
pin map is in one place with everything else.

| Signal            | ESP32 GPIO | Notes                          |
|-------------------|-----------|--------------------------------|
| PWDN              | 32        | power-down                     |
| RESET             | —         | not wired (-1 in firmware)     |
| XCLK              | 0         | master clock out to sensor     |
| SIOD (SCCB SDA)   | 26        | sensor control bus, data       |
| SIOC (SCCB SCL)   | 27        | sensor control bus, clock      |
| VSYNC             | 25        | frame sync                     |
| HREF              | 23        | line sync                      |
| PCLK              | 22        | pixel clock                    |
| D7 (Y9)           | 35        | pixel data MSB                 |
| D6 (Y8)           | 34        |                                |
| D5 (Y7)           | 39        |                                |
| D4 (Y6)           | 36        |                                |
| D3 (Y5)           | 21        |                                |
| D2 (Y4)           | 19        |                                |
| D1 (Y3)           | 18        |                                |
| D0 (Y2)           | 5         | pixel data LSB                 |

Streaming settings that made the image clean on this board:

- **XCLK = 10 MHz** (not the usual 20). A slower pixel clock gives the ESP32's
  DVP capture cleaner sampling; at 20 MHz the frames were garbage.
- **VGA (640×480), JPEG, quality 12, 2 frame buffers in PSRAM.**

## Sensor / KY-015 (DHT11)

| Signal | Pin        | Notes                                                   |
|--------|-----------|---------------------------------------------------------|
| DATA   | GPIO 13    | KY-015 module has its own pull-up                       |
| VCC    | 3V3        | **not** 3.7 V — the data line idles at VCC; >3.6 V stresses the pin |
| GND    | GND        | common                                                  |

## Power (bring-up notes)

- Feed **5.0 V into the 5V pin** (via an MT3608 boost from the LiPo). That pin
  feeds the onboard regulator, which is the only path that can supply the
  camera's turn-on inrush. Do **not** power the 3V3 pin or the silkscreen VCC
  pin directly.

## The OV3660-clone quirk (why the camera "wouldn't work")

The sensor was an **OV3660 clone mislabeled as an OV2640**. It's marginal on the
SCCB control bus and hard-refuses four cosmetic auto-white-balance registers.
The stock `esp32-camera` driver aborts the whole init on the first refused
write, so the camera never came up — in Arduino **or** ESP-IDF. It wasn't a
wiring, power, or core-version fault; every camera pin above is correct.

**Fix — two edits to `esp32-camera/driver/sccb.c`, in `SCCB_Write16()`:**

1. Retry each SCCB write up to 8× instead of giving up on the first failure.
2. Don't abort on a NAK — `return 0` (success) so a refused cosmetic register
   doesn't kill the whole init.

Plus, at the config level:

- SCCB bus clock hardwired to **20 kHz** (the clone won't hold higher reliably).
- **3 MB app partition** (the patched driver + JPEG buffers don't fit the
  default table).
- **Init the camera FIRST in `app_main`** — the DHT read's critical section and
  `nvs_flash_init()` were disturbing the camera clock/DMA bring-up and causing
  capture timeouts.

With those, the sensor detects and streams: `frame: ~90000 bytes (800x600)` on
the bench, clean VGA frames in the tank.

## Files here

- `main.c` — the ESP-IDF firmware (capture → WiFi → POST → deep sleep).
- `CMakeLists.txt` — the app component's build file.
- `config.h.example` — copy to `config.h` and fill in your WiFi + Worker token.

The patched `esp32-camera` driver isn't reproduced here; the two-line change
above is the whole of it.
