{
 "tag": "esp32-camera",
 "kind": null,
 "product": null,
 "used_by": [],
 "parts": [
  "adafruit-5364-esp32-s3-devkitc-1-esp32-s3-wroom-2-32mb-flash",
  "goouuu-esp32-s3-cam-case-wall-mount-and-din-rail-bodies",
  "goouuu-esp32-s3-cam-tripod-case-body-lid",
  "goouuu-esp32s3cam",
  "waveshare-esp32-s3-cam-gc0308-tripod-case-body-lid",
  "waveshare-esp32s3-cam-gc0308"
 ],
 "notes": [
  {
   "handle": "sargbench1",
   "id": "never-re-init-sensor-to-sync-wastes-380",
   "title": "Never re-init sensor to sync; wastes 380-600 ms with no frame-phase change",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ledc-based-xclk-tuning-has-zero-effect-on",
   "title": "LEDC-based XCLK tuning has zero effect on ESP32-S3 frame rate",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "esp-now-trigger-latency-degrades-4-5-under",
   "title": "ESP-NOW trigger latency degrades 4-5\u00d7 under camera load",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "an-esp32-s3-silently-rounds-a-camera-xclk",
   "title": "An ESP32-S3 silently rounds a camera XCLK request to the nearest divisor of 80 MHz, and asking for 24 MHz gets you 26.67",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "ov3660-esp32-camera-does-not-extend-exposure-beyond",
   "title": "OV3660 esp32-camera does not extend exposure beyond frame period",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "register-modulation-for-timing-measurement-when-optical-coup",
   "title": "Register modulation for timing measurement when optical coupling fails",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "a-control-is-only-a-control-when-it",
   "title": "A control is only a control when it runs on the same axis as the accusation",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-bad-frame-after-a-resolution-switch-is",
   "title": "The bad frame after a resolution switch is not always auto-exposure \u2014 locking AEC, AGC and AWB changed nothing here",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "an-ov3660-clone-reads-midh-midl-as-0x00",
   "title": "A false counterfeit conviction stood through two corrections because each test's control ran on a different axis than the accusation",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "runtime-set-framesize-requires-dma-buffers-sized-for",
   "title": "Runtime set_framesize requires DMA buffers sized for largest frame, not init frame",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "first-frame-after-mode-switch-has-old-resolution",
   "title": "First frame after mode-switch has old resolution despite new fb->width, decodes as wrong size",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ov3660-clone-sensor-midh-midl-are-0x00-0x00",
   "title": "The 'counterfeit' OV3660 was genuine: every signal that convicted it was an artifact \u2014 wrong-register PLL, a stuck sensor state that survives reboot, and host-clock xclk traps",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "the-openmv-n6-switches-resolution-on-a-live",
   "title": "The OpenMV N6 switches resolution on a live pipeline in 108 ms with no discard and no crash, which is what an ESP32 camera cannot do",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "on-device-inference-is-free-below-qvga-because",
   "title": "On-device inference is free below QVGA because it hides inside the sensor's frame period, and offloading cannot beat free",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "ch340-serial-link-to-esp32-s3-fails-above",
   "title": "CH340 serial link to ESP32-S3 is usable to 1 Mbaud and unusable above it \u2014 by two different failure modes on the same board",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "rgb565-dma-line-buffer-limits-ov3660-to-1024px",
   "title": "RGB565 DMA line buffer limits OV3660 to 1024px width",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "rgb565-byte-order-must-be-swapped-for-esp",
   "title": "RGB565 byte order must be swapped for esp-dl MSR01 face detector",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "framesize-96x96-jpeg-hang-on-ov3660",
   "title": "FRAMESIZE_96X96 JPEG hang on OV3660",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "trigger-to-still-is-139-to-528-ms",
   "title": "Trigger-to-still is 139 to 528 ms on an OV3660 against 900 to 1700 ms on a GC0308, and almost all of the difference is the switch mechanism",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "after-set-framesize-the-driver-reports-the-new",
   "title": "After set_framesize the driver reports the new resolution and hands back the old one, so one discard is mandatory and metadata cannot detect it",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "ch340-uart-loses-bytes-at-2-mbaud-on",
   "title": "CH340 UART loses bytes at 2 Mbaud on this board",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "frame-buffer-allocation-is-fixed-at-esp-camera",
   "title": "Frame buffer allocation is fixed at esp_camera_init(), cannot scale up at runtime",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "first-frame-after-set-framesize-is-stale-and",
   "title": "First frame after set_framesize() is stale and mislabeled on OV3660",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ae-awb-api-freeze-uses-wrong-initial-exposure",
   "title": "AE/AWB API freeze uses wrong initial exposure on OV3660",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "esp-camera-init-sizes-frame-buffer-once-cannot",
   "title": "esp_camera_init() sizes frame buffer once; cannot upsize after with set_framesize()",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ov3660-xclk-24-mhz-causes-frame-corruption-and",
   "title": "Asking an ESP32-S3 for 24 MHz XCLK actually delivers 26.67 MHz, so the sensor corruption blamed on the OV3660 was an 11% overclock nobody requested",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "esp-dl-reads-rgb565-as-big-endian-while",
   "title": "esp-dl reads RGB565 as big-endian while jpg2rgb565 emits little-endian, so a detector silently returns zero detections",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-same-ov3660-board-produced-working-hardware-jpeg",
   "title": "A camera sensor with PWDN and RESET tied to -1 never resets when the MCU does, so a stuck state survives every reboot and looks exactly like counterfeit silicon",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "rgb565-byte-order-mismatch-between-jpg2rgb565-and-esp",
   "title": "RGB565 byte-order mismatch between jpg2rgb565 and esp-dl camera buffers",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ov3660-1024-px-lcd-cam-line-buffer-limits",
   "title": "OV3660 1024-px LCD_CAM line buffer limits RGB565 capture width on ESP32-S3",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "esp-dl-detection-libraries-absent-from-platformio-framework",
   "title": "esp-dl detection libraries absent from PlatformIO framework-arduinoespressif32",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "ov3660-clone-on-xiao-esp32s3-sense-does-not",
   "title": "RETRACTED: the XIAO ESP32S3 Sense OV3660 does support hardware JPEG \u2014 35+ consecutive captures after a power cycle",
   "status": "retracted"
  },
  {
   "handle": "sargbench1",
   "id": "overclocking-an-ov3660-s-xclk-produces-structurally-valid",
   "title": "Overclocking an OV3660's XCLK produces structurally valid JPEGs full of garbage pixels, so byte-level validation passes and the images are ruined",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "two-runs-on-the-same-sensor-disagree-about",
   "title": "RETRACTED: the OV3660 'disagreement by board' was two measurement artifacts, not two different silicons",
   "status": "retracted"
  },
  {
   "handle": "sargbench1",
   "id": "on-a-hardware-jpeg-camera-the-cold-boot",
   "title": "On a hardware-JPEG camera the cold-boot budget is dominated by the camera, not WiFi \u2014 the reverse of a software-JPEG board on the same host",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "bring-wifi-up-before-the-camera-on-an",
   "title": "Bring WiFi up BEFORE the camera on an ESP32-S3, and treat cam_task as the single fragile point in the esp32-camera driver",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "wifi-begin-must-precede-esp-camera-init-to",
   "title": "WiFi.begin() must precede esp_camera_init() to avoid boot loop",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-pixel-clock-scales-fps-directly-no-hidden",
   "title": "GC0308 pixel clock scales fps directly; no hidden PLL half-speed trap",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "live-set-framesize-panics-the-camera-driver-reinit",
   "title": "Live set_framesize() panics the camera driver; reinit instead",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "esp-camera-init-on-a-gc0308-costs-a",
   "title": "esp_camera_init on a GC0308 costs a fixed 283 ms regardless of clock, resolution or buffer location, so the only way to remove it is to overlap it",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-camera-init-time-is-283-ms-fixed",
   "title": "GC0308 camera init time is ~283 ms fixed, independent of tunable parameters",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "bssid-pinning-to-strongest-signal-creates-3-8",
   "title": "BSSID pinning to strongest signal creates 3.8\u00d7 slowdown in mesh networks",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-camera-pipeline-crashes-when-frame-size-is",
   "title": "GC0308 camera pipeline crashes when frame size is changed live",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "streaming-at-a-lower-resolution-buys-zero-frame",
   "title": "Streaming at a lower resolution buys zero frame rate on a GC0308, because frame period is set by the sensor clock and not by pixel count",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-auto-exposure-transient-after-re-initialising-a",
   "title": "The auto-exposure transient after re-initialising a GC0308 cannot be removed in software, and the register carry-over that should fix it does not",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "set-framesize-on-a-gc0308-fails-in-two",
   "title": "set_framesize() on a GC0308 fails in two different ways depending on direction: upward it silently truncates the image, downward it crashes deterministically",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "trigger-to-still-on-a-gc0308-is-400",
   "title": "Trigger to still on a GC0308 is 400 ms to a decodable image and 1.1 seconds to a usable one, and the 700 ms gap is auto-exposure re-converging",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-optimal-architecture-is-to-never-switch-resolution",
   "title": "GC0308: optimal architecture is to never switch resolution",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-framesize-changes-crash-or-corrupt-silently",
   "title": "GC0308: framesize changes crash or corrupt silently",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-ae-reconvergence-after-re-init-takes-700",
   "title": "GC0308: AE reconvergence after re-init takes ~700 ms and cannot be disabled",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "rgb565-byte-order-breaks-both-esp-dl-and",
   "title": "RGB565 byte order breaks both esp-dl and fmt2jpg silently",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "esp-timer-get-time-carries-rtc-offset-affects",
   "title": "esp_timer_get_time() carries RTC offset; affects cold-boot timing measurements",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "camera-pin-map-mismatch-causes-hard-esp32-s3",
   "title": "Camera pin map mismatch causes hard ESP32-S3 wedge",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "freenove-esp32-s3-wroom-16-mb-flash-boot",
   "title": "Freenove ESP32-S3-WROOM 16 MB flash boot loop with wrong partition config",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "a-board-s-camera-pin-map-is-compiled",
   "title": "A board's camera pin map is compiled as immediates, so searching its firmware binary for the pin numbers finds nothing",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "rgb565-capture-on-the-esp32-s3-is-limited",
   "title": "RGB565 capture on the ESP32-S3 is limited by frame WIDTH, not by memory: 1280x720 fails with 6.5 MB of PSRAM free while 864x1536 succeeds",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-seeed-xiao-esp32s3-sense-carries-an-ov3660",
   "title": "The Seeed XIAO ESP32S3 Sense carries an OV3660 with hardware JPEG to 3 MP, and its sensor-side encoder is 18x faster than encoding on the chip",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "software-jpeg-beats-shipping-raw-frames-by-4",
   "title": "Software JPEG beats shipping raw frames by 4.6x on a chip with no JPEG hardware, because the link is the harder wall",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "detect-on-the-chip-or-ship-the-frame",
   "title": "Detect on the chip or ship the frame? The crossover is capture size, and it sits between 160x120 and 240x176",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-sensor-does-not-support-hardware-jpeg-in",
   "title": "GC0308 sensor does not support hardware JPEG in esp-camera driver",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "software-jpeg-at-about-0-9-microseconds-per",
   "title": "Software JPEG at about 0.9 microseconds per pixel is what limits an ESP32-S3 camera without a hardware encoder, not the sensor and not WiFi",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "on-the-gc0308-the-sensor-clock-scales-frame",
   "title": "On the GC0308 the sensor clock scales frame rate one-for-one, so the OV3660 PLL trap does not apply and raising the pixel clock is exactly what works",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "wifi-ps-min-modem-causes-intermittent-25-latency",
   "title": "WiFi PS_MIN_MODEM causes intermittent 25\u00d7 latency spikes on send()",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "gc0308-xclk-scales-linearly-to-40-mhz-maximum",
   "title": "GC0308: XCLK scales linearly to 40 MHz maximum",
   "status": "provisional"
  },
  {
   "handle": "sargbench1",
   "id": "leaving-an-esp32-camera-capturing-with-nobody-consuming",
   "title": "Leaving an ESP32 camera capturing with nobody consuming frames steals enough CPU to wreck WiFi transmission",
   "status": "working"
  },
  {
   "handle": "sargbench1",
   "id": "the-freenove-esp32-s3-wroom-cam-carries-a",
   "title": "The Freenove ESP32-S3-WROOM CAM carries a GC0308, which tops out at VGA and has no hardware JPEG at all",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "codified-bringup-checklist-camlogger-worked-first-boot",
   "title": "Codified lessons compound: camera firmware written from the prior board's checklist (zero-init camera_config_t, warm-up frames, OTA-first) worked on first boot",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "esp32-camera-rgb565-is-big-endian-per-pixel-swap-bytes",
   "title": "Wrong colors converting esp32-camera RGB565 frames \u2014 pixels are big-endian, use '>u2' not '<u2' in numpy",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "grainy-frames-are-gc0308-warm-up-frames-discard-first-5",
   "title": "Intermittent grainy frames from GC0308 are AGC/AWB warm-up frames \u2014 discard the first ~5 frames after camera init",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "micropython-probe-identifies-ov3660-but-ship-esp-idf-for-jpeg",
   "title": "MicroPython camera build identifies OV3660 but its JPEG mode is broken at every XCLK \u2014 probe in MicroPython, ship ESP-IDF esp32-camera",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "softi2c-scan-cannot-detect-camera-sccb-use-esp32-camera-probe",
   "title": "SoftI2C scan finds no camera on correct SCCB pins \u2014 only the esp32-camera driver probe is definitive",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "tflite-micro-input-tensor-invalid-after-invoke-memcpy-before",
   "title": "Never read a TFLite Micro input tensor after Invoke() \u2014 post-inference reads return arena scratch that mimics a broken camera, and the model still scores it \"person 79-94%\"",
   "status": "working"
  },
  {
   "handle": "sarg",
   "id": "waveshare-esp32-s3-cam-micropython-firmware-choice-spiram-oct",
   "title": "Which MicroPython build for Waveshare ESP32-S3-CAM (S3R8 octal PSRAM) \u2014 micropython-camera-API v0.6.2 ESP32_GENERIC_S3-SPIRAM_OCT, never the ESP32S3_EYE zip",
   "status": "working"
  }
 ]
}