ESP32-CAM AI-Thinker Board Overview: Pinout, OV2640, PSRAM and Limits

The AI-Thinker ESP32-CAM is a small, low-cost board that combines an ESP32 Wi-Fi and Bluetooth chip, an OV2640 camera, extra PSRAM, a microSD slot and a bright white LED. It is the cheapest way to build a Wi-Fi camera, but it is also a board with very few free pins, no USB port and a reputation for strange resets. Most of those problems disappear once you know what is on the board and which pins are already taken.

This article walks through the hardware block by block, gives the exact camera pin map used by the esp_camera driver, lists the pins you can actually use for your own projects, and ends with a self-test sketch that confirms your board, PSRAM and camera are working before you start a bigger project.

What Is on the Board

PartDetailsWhy it matters
ESP32 module (ESP32-S)Dual-core Xtensa LX6, Wi-Fi 2.4 GHz, Bluetooth, 520 KB internal SRAMRuns your Arduino sketch and the camera driver
Flash memory4 MB SPI flashHolds the program; sets which partition schemes fit
PSRAMExternal SPI RAM, 4 MB usableNeeded for large frame buffers and high resolutions
OV2640 camera2 MP sensor, outputs JPEG directly, max 1600 x 1200 (UXGA)Hardware JPEG keeps images small enough for Wi-Fi
microSD slotUses the SD_MMC peripheral on GPIO 2, 4, 12, 13, 14, 15Storage for photos, but it uses most free pins
Flash LEDBright white LED on GPIO 4, driven through a transistorLighting for photos; draws significant current
Red status LEDSmall LED on GPIO 33, active LOWHandy for status blinks without extra parts
RegulatorAMS1117 3.3 V linear regulator fed from the 5V pinExplains why a weak 5 V supply causes brownouts
AntennaPCB antenna plus an IPEX connector selected by a small resistorExternal antenna improves range in metal enclosures

The board has no USB-to-serial chip. To upload code you need an external USB-to-TTL adapter or the ESP32-CAM-MB plug-in board, which is covered in a separate tutorial. The RESET button on the board is on the underside, next to the camera connector.

Camera Pin Map (AI-Thinker)

The OV2640 is connected through an 8-bit parallel data bus plus clock, sync and SCCB (I2C-like) control lines. These pins are fixed by the PCB, so every ESP32-CAM sketch must use exactly this map. Other camera boards such as the ESP-EYE or M5Stack use different maps, which is a common reason for the error Camera probe failed.

Signal   GPIO      Signal   GPIO
PWDN     32        Y5       21
RESET    -1 (n/c)  Y4       19
XCLK     0         Y3       18
SIOD     26        Y2       5
SIOC     27        VSYNC    25
Y9       35        HREF     23
Y8       34        PCLK     22
Y7       39        Flash    4
Y6       36        Red LED  33

Note that XCLK is on GPIO 0. The ESP32 generates a 20 MHz clock on this pin for the sensor using the LEDC peripheral, and GPIO 0 is also the boot-mode strapping pin. That is why GPIO 0 must be pulled to GND only during upload and left free during normal running.

Which GPIOs Can You Use?

The header pins exposed on the board are 5V, GND, 3V3 (marked VCC or 3.3V), GPIO 0, 1, 3, 2, 4, 12, 13, 14, 15 and 16. Most of them have a second job, so choose carefully:

  • GPIO 1 and 3 are U0TXD and U0RXD, the serial port used for uploading and Serial.print. Use them only if you give up serial debugging.
  • GPIO 2, 4, 12, 13, 14, 15 are the microSD lines. If you do not use the SD card they are free. In 1-bit SD mode, GPIO 4, 12 and 13 are released.
  • GPIO 12 is a strapping pin that selects flash voltage. It must be LOW at boot; a pull-up on this pin can stop the board from starting.
  • GPIO 0 is XCLK and the boot pin. Do not connect anything to it.
  • GPIO 16 is used as the PSRAM chip-select on this module. Avoid it if you use PSRAM.
  • GPIO 4 drives the flash LED, so anything connected there will also light the LED.
  • GPIO 33 is only the on-board red LED and is not on the header.

Board Self-Test Sketch

In the Arduino IDE, install the esp32 board package by Espressif, select the board AI Thinker ESP32-CAM, and upload the sketch below. It prints chip, flash and PSRAM information, starts the camera, reads the sensor ID, takes one test frame and blinks the red LED if everything passed.

ESP32-CAM self-test: chip info, PSRAM, camera probe and one test frame
#include "esp_camera.h"

// AI-Thinker ESP32-CAM camera pins
#define PWDN_GPIO_NUM  32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM   0
#define SIOD_GPIO_NUM  26
#define SIOC_GPIO_NUM  27
#define Y9_GPIO_NUM    35
#define Y8_GPIO_NUM    34
#define Y7_GPIO_NUM    39
#define Y6_GPIO_NUM    36
#define Y5_GPIO_NUM    21
#define Y4_GPIO_NUM    19
#define Y3_GPIO_NUM    18
#define Y2_GPIO_NUM     5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM  23
#define PCLK_GPIO_NUM  22

#define RED_LED 33   // on-board red LED, active LOW

bool initCamera() {
  camera_config_t config = {};          // zero all fields first
  config.ledc_channel = LEDC_CHANNEL_0;   // LEDC makes the 20 MHz XCLK
  config.ledc_timer   = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk  = XCLK_GPIO_NUM;
  config.pin_pclk  = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href  = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn  = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size   = FRAMESIZE_VGA;     // 640 x 480 for the test
  config.jpeg_quality = 12;
  config.fb_count     = 1;
  config.fb_location  = psramFound() ? CAMERA_FB_IN_PSRAM : CAMERA_FB_IN_DRAM;
  config.grab_mode    = CAMERA_GRAB_LATEST;
  return esp_camera_init(&config) == ESP_OK;
}

void setup() {
  Serial.begin(115200);
  delay(500);
  pinMode(RED_LED, OUTPUT);
  digitalWrite(RED_LED, HIGH);            // LED off (active LOW)

  Serial.printf("Chip: %s rev %d, %d cores\n", ESP.getChipModel(), ESP.getChipRevision(), ESP.getChipCores());
  Serial.printf("Flash size: %u bytes\n", ESP.getFlashChipSize());
  Serial.printf("PSRAM found: %s, size %u bytes\n", psramFound() ? "yes" : "no", ESP.getPsramSize());

  if (!initCamera()) {
    Serial.println("Camera init FAILED - check ribbon cable and board selection");
    return;
  }

  sensor_t *s = esp_camera_sensor_get();
  Serial.printf("Sensor PID: 0x%02X (OV2640 is 0x%02X)\n", s->id.PID, OV2640_PID);

  camera_fb_t *fb = esp_camera_fb_get();  // grab one frame
  if (!fb) {
    Serial.println("Frame capture FAILED");
    return;
  }
  Serial.printf("Test frame: %ux%u, %u bytes JPEG\n", fb->width, fb->height, fb->len);
  esp_camera_fb_return(fb);              // always give the buffer back

  Serial.println("All tests passed");
  for (int i = 0; i < 5; i++) {          // blink red LED as a pass signal
    digitalWrite(RED_LED, LOW);
    delay(200);
    digitalWrite(RED_LED, HIGH);
    delay(200);
  }
}

void loop() {
}

A healthy board reports PSRAM as found with a size of roughly 4 MB, a sensor PID of 0x26 and a VGA test frame of a few tens of kilobytes, depending on the scene. If PSRAM shows as not found, check that the board selection is AI Thinker ESP32-CAM, or that PSRAM is enabled when you use the generic ESP32 Dev Module.

Practical Limits and Common Problems

  • Brownout detector was triggered: the supply cannot handle Wi-Fi and camera current peaks. Use a solid 5 V supply rated for at least 1 A to 2 A, with short, thick wires, rather than the 3.3 V pin of a USB-TTL adapter.
  • Camera probe failed (0x105 / 0x20004): ribbon cable not fully latched, wrong board pin map, or a damaged sensor. Reseat the flat cable with the contacts facing the board.
  • Weak Wi-Fi: the PCB antenna is small and partly shadowed by the camera. Some boards ship with the resistor set to the IPEX connector, in which case the PCB antenna is not connected at all.
  • Heat: the ESP32 and regulator run warm during continuous streaming. Leave airflow around the board in an enclosure.
  • Frame rate: expect smooth video only at VGA or smaller sizes. UXGA works for stills, but streaming at full size is slow over Wi-Fi.

Summary

The AI-Thinker ESP32-CAM packs an ESP32, an OV2640 with hardware JPEG, PSRAM and a microSD slot onto one board. The camera pin map is fixed, GPIO 0 doubles as XCLK and boot pin, GPIO 12 must stay low at boot, and the SD card uses most of the remaining pins. Run the self-test sketch on every new board: it confirms PSRAM, the sensor ID and frame capture, so later problems can be traced to your code rather than the hardware.