4.8 KiB
07 — OV2640 SCCB / I²C register spec
The minimum register set our QEMU OV2640 device must implement to keep
the upstream espressif/esp32-camera driver happy. Sourced from:
- OmniVision OV2640 datasheet rev 1.6 (Feb 2006).
espressif/esp32-camera/sensors/ov2640.c— driver source.espressif/esp32-camera/sensors/private_include/ov2640_regs.h.
The Phase-1 deliverable is a QEMU device that passes the chip-detect
dance below. A more complete model (Phase 2) covers the full
OV2640_JPEG_INIT / OV2640_YUV422 / OV2640_RGB565 register
sequences so that pixel-format switches behave like real hardware.
SCCB transport
- Same as I²C, but 8-bit register addresses (no 16-bit auto-increment).
- 7-bit slave address:
0x30(write0x60, read0x61). - Single-register transactions:
START / 0x60 / regaddr / val / STOPfor write;START / 0x60 / regaddr / RSTART / 0x61 / val / STOPfor read.
Bank-select (BANK_SEL = 0xFF)
The OV2640 has two register pages, switched by writing to 0xFF:
| Value | Bank | Holds |
|---|---|---|
| 0x00 | DSP | output format, scaling, JPEG, ISP |
| 0x01 | SENSOR | timing, exposure, gain, chip ID |
Implementation: keep one current_bank byte; every register access
looks at it before deciding which 256-entry table to hit.
Chip identification (Phase 1 — minimum viable)
Write 0xFF = 0x01 (sensor bank), then read:
| Reg | Name | Value (OV2640) |
|---|---|---|
| 0x0A | REG_PID | 0x26 |
| 0x0B | REG_VER | 0x42 |
| 0x1C | REG_MIDH | 0xa2 |
| 0x1D | REG_MIDL | 0x7f |
These four reads alone are what esp32_camera_ov2640_detect() checks.
Everything below is for esp_camera_init() to not return errors after
detection.
Init register sequences (Phase 2)
The driver pushes three large {reg, val} arrays in sequence:
ov2640_init_regs— 102 registers, mixed banks (interleaved0xFF=0x00/0xFF=0x01switches). Pure setup; values are written verbatim, our model just stores them in the per-bank tables and acks.ov2640_init_jpeg_regs— 26 registers, after format switch to JPEG. Configures the on-chip JPEG ISP. Same: store + ack.ov2640_yuv422_regs/ov2640_rgb565_regs— alternative format paths, each ~12 regs.
Our QEMU model stores them all in two 256-byte per-bank arrays. No register has read-modify-write side effects beyond:
0x12(COM7): bit 7 =RESET. Writing 0x80 here triggers a soft reset. Implementation: zero both bank tables, restore chip-ID regs, setcurrent_bank=0x01.0xFF: bank-select (already covered).0x09(COM2): bit 4 =SOFT_SLEEP. Doesn't affect bus behaviour; fine to ignore.
Reset behaviour
After power-on or 0x12 = 0x80:
- All registers go to chip default. Most defaults are zero except the chip-ID regs (which are ROM, never change).
current_bankresets to0x01(sensor).- The driver waits ~10 ms after a soft reset before reading PID. We can ignore that timing — QEMU's I²C bus is instant.
What we don't model
- Auto-exposure / auto-white-balance / auto-gain — these never get read back by the driver, only written to. We accept any value.
- Test-pattern register (
0x12bit 1). The real chip emits stripes; our emulator emits whatever the host pushed (see08_dvp_i2s_spec.md). - The "OV2640 Window" registers (
0x17 / 0x18 / 0x19 / 0x1A). The driver writes them; we accept and ignore — the frame source is the host webcam, no on-sensor windowing.
Open question: SCCB vs I²C inside the ESP32-CAM driver
The upstream driver has historically supported two paths for talking to the sensor:
CONFIG_SCCB_HARDWARE_I2C(default): use the ESP32 I²C controller. This is what hitsesp32_i2c.cin our QEMU.CONFIG_SCCB_HARDWARE_I2C=n: bit-bang via GPIO. Triggers GPIO toggles on SIOD/SIOC.
For Phase 1 we assume hardware I²C (the Arduino default for
esp32:esp32:esp32cam). The bit-bang path would need IOMUX-based
intercepting that's out of scope.