
In today’s tutorial, we’ll show you how to program the ESP32-CAM module. ESP32-CAM module is suitable for building basic surveillance or monitoring systems. Its price is quite reasonable. You can use it for lots of AI-based projects like object detection, face recognition etc.
However, many users face hard luck when setting up and uploading code to ESP32-CAM development boards. This tutorial will provide you with a guideline for successfully programming the ESP32-CAM.
Overview of the ESP32-CAM Development Board
The ESP32-CAM is a standalone development board that integrates an ESP32-S chip, a camera module, onboard flash memory, and a microSD card slot. It features built-in Wi-Fi and Bluetooth connectivity and supports OV2640 or OV7670 cameras with a resolution of up to 2 megapixels.

Key Features:
Ultra-small 802.11b/g/n Wi-Fi + Bluetooth/BLE SoC module
Low-power, dual-core 32-bit processor with a clock speed of up to 240MHz and computing power of 600 DMIPS
520 KB built-in SRAM and 4M external PSRAM
Supports multiple interfaces: UART, SPI, I2C, PWM, ADC, and DAC
Compatible with OV2640 and OV7670 cameras and includes built-in flash storage
Enables Wi-Fi-based image uploads and supports TF cards
Multiple sleep modes for power efficiency
Operates in STA, AP, and STA+AP modes
Specifications:
Dimensions: 27 × 40.5 × 4.5 mm
SPI Flash: Default 32Mbit
RAM: 520KB internal + 4M external PSRAM
Bluetooth: BT 4.2 BR/EDR and BLE
Wi-Fi Standards: 802.11 b/g/n/e/i
Interfaces: UART, SPI, I2C, PWM
TF Card Support: Up to 16GB (4G recommended)
GPIO Pins: 9 available
Image Output Formats: JPEG (only with OV2640), BMP, Grayscale
Antenna: Onboard with 2dBi gain
Security: WPA/WPA2/WPAS-Enterprise/WPS
Power Supply: 5V
Operating Temperature: -20°C to 85°C
Power Consumption:
Without flash: 180mA @ 5V
With max brightness flash: 310mA @ 5V
Deep sleep mode: 6mA @ 5V
Modem sleep mode: 20mA @ 5V
Light sleep mode: 6.7mA @ 5V
ESP32-CAM Pinout
The ESP32-CAM module has fewer accessible GPIO pins compared to a standard ESP32 board since many are allocated for the camera and SD card module. Certain pins should be avoided during programming:
GPIO1, GPIO3, and GPIO0 are essential for uploading code and should not be used for other functions.
GPIO0 is linked to the camera XCLK pin and should remain unconnected during normal operation. It must be pulled to GND only when uploading firmware.
P_OUT Pin: Labeled as VCC on some boards, this pin provides 3.3V or 5V output depending on the solder pad configuration. It cannot be used to power the board—use the dedicated 5V pin instead.
GPIO 2, 4, 12, 13, 14, and 15 are assigned to the SD card reader. If the SD card module is unused, these pins can be repurposed as general I/O.

Notably, the onboard flash LED is connected to GPIO 4, meaning it may turn on when using the SD card reader. To prevent this behaviour, use the following code snippet:
SD_MMC.begin("/sdcard", true);
For an in-depth explanation of the ESP32-CAM pinout and GPIO usage, refer to the Random Nerd Tutorials guide: ESP32-CAM AI-Thinker Pinout Guide: GPIOs Usage Explained.
Schematic
Following is a full schematic of the ESP32-CAM.

Driver installation
You need to install the CP210X driver on your computer to get the ESP32-CAM working. You can download the driver from here .
Board installation
No matter which method you choose to program your ESP32-CAM, you need to do the board installation. If ESP32 boards are already installed in your Arduino IDE, feel free to skip this installation section. Go to File > preferences, type https://dl.espressif.com/dl/package_esp32_index.json and click OK.

Go to Tools>Board>Boards Manager and click ‘install’.

Install the ESP32-CAM library.
Download the ESP32-CAM library from Github (the link is given in the reference section). Follow the path sketch>include library> add.zip library.

Now select the correct path to the library, click on the library folder and press open.

Board selection and code uploading
Connect the camera board to your computer. Some camera boards come with a micro USB connector of their own. You can connect the camera to the computer using a micro USB data cable. If the board has no connector, you need to connect the FTDI module to the computer with the data cable. You will need to install the FTDI driver first.
When you’re done with the connection, Go to Tools>boards>esp32>Ai thinker ESP32-CAM

After selecting the board, select the appropriate COM port and upload the following code:
Method 1: Using the ESP32-CAM Programmer Shield
ESP32-CAM programmer shield is made exclusively to program the ESP32-CAM. The shield is equipped with a USB-to-serial converter. The built-in USB-to-serial converter simplifies the process of connecting the board to a computer for programming and debugging. It also includes a microSD card slot for expanded storage, enabling easy data storage and retrieval. Additionally, the shield features a power switch and an LED indicator, allowing for straightforward power control and status monitoring. With its compact design and user-friendly functionality, the ESP32-CAM-MB Programmer Shield is a valuable tool for developers working with the ESP32-CAM-MB board.

Connecting ESP32-CAM with the Programmer Shield
Just connect the ESP32-CAM module on top of the Programming Shield as shown below, and connect a USB cable from the Programming Shield to your computer. Now you can program your ESP32-CAM.

Connecting the Programming Shield to Your Computer
First, take a functional USB cable. It should be securely connected and to the USB port of your computer. When plugged in, you should hear a notification sound from your computer. A red LED on the Programming Shield should illuminate. Next, confirm that you have selected the AI Thinker ESP32-CAM board and the appropriate Serial Port. Refer to the image below for guidance.

Press the upload button to upload your code.

Press the IOo button of the programming shield.

The text ‘connecting’ should appear in the output panel.

While holding down the IOo button, press the RST button and release. See the following picture to know the location of the RST button, that you need to press.

When the dots in the text “Connecting …..” stop appearing you can release the IO0 button as well. If the following text appears, it indicates that the code is being uploaded:

Running Mode
When the code is uploaded, you will see the message “Hard resetting via RTS pin…” in the Output Panel. You must press the RST button on the ESP32-CAM module to run the uploaded program. Avoid using the RST button on the Programming Shield. Also, do not press the IO0 button.
Test Code for ESP32-CAM with Programming Shield
This simple Blink program turns on the Flash LED on the ESP32-CAM for 10 milliseconds, then waits for 2 seconds before repeating the cycle.
int flashPin = 4;
void setup() {
pinMode(flashPin, OUTPUT);
}
void loop() {
digitalWrite(flashPin, HIGH);
delay(10);
digitalWrite(flashPin, LOW);
delay(2000);
}
You will see the LED flashing if the code is uploaded without any problem.
Method 2: Programming ESP32-CAM with FTDI programmer.
List of components

Components |
Quantity |
ESP32-CAM WiFi + Bluetooth Camera Module | 1 |
FTDI USB to Serial Converter 3V3-5V | 1 |
Male-to-female jumper wires |
4 |
Female-to-female jumper wire |
1 |
MicroUSB data cable |
1 |
Circuit diagram
Following is the circuit diagram of this project.


ESP32-CAM WiFi + Bluetooth Camera Module | FTDI USB to Serial Converter 3V3-5V (Voltage selection button should be in 5V position) |
---|---|
5V |
VCC |
GND |
GND |
UOT |
Rx |
UOR |
TX |
IO0 |
GND (FTDI or ESP32-CAM) |
Programming
Testing Code for ESP32-CAM with FTDI Programmer
This code functions similarly to a standard Blink program but gradually increases the brightness of the flash LED over 255 steps before turning it off for a second and repeating the cycle.
int flashPin = 4;
void setup() {
pinMode(flashPin, OUTPUT);
}
void loop() {
for (int brightness = 0; brightness < 255; brightness++) {
analogWrite(flashPin, brightness);
delay(1);
}
analogWrite(flashPin, 0);
delay(1000);
}
Since programming the ESP32-CAM (even with the FTDI Programmer) can be cumbersome, it’s advisable to first verify the functionality of the SD card and camera before attempting more complex projects. The following sections outline how to do this.
Testing the SD Card
The ESP32-CAM officially supports up to 4GB microSD cards, but 8GB and 16GB cards generally work fine. Larger cards require reformatting to FAT32, which can be done using guiformat.exe from Ridgecrop.
The test program below creates a file, writes a test message to it, and reads back the content. If the output matches expectations, the SD card is functioning correctly.
#include "SD_MMC.h"
#include "FS.h"
#include "LittleFS.h"
int flashPin = 4;
void setup() {
Serial.begin(115200);
SD_MMC.begin();
LittleFS.begin(true);
// Create and write a test file
File file = LittleFS.open("/test.txt", FILE_WRITE);
file.print("*** Test successful ***");
file.close();
file = LittleFS.open("/test.txt");
while (file.available()) {
Serial.write(file.read());
}
file.close();
// Set the flash LED as output
pinMode(flashPin, OUTPUT);
// turn the LED off
analogWrite(flashPin, 0);
}
void loop() {
}
Code Breakdown
1. Libraries & Initialization:
#include "SD_MMC.h"
#include "FS.h"
#include "LittleFS.h"
Additionally, we define flashPin to control the flash LED:
int flashPin = 4;
2. Setup Function:
The setup() function initializes serial communication at 115200 baud:
Serial.begin(115200);
Then we need to initialize the SD card and LittleFS file system. The argument true ensures that LittleFS is formatted if it isn't already:
SD_MMC.begin();
LittleFS.begin(true);
A file named test.txt is created, a test message is written, and the file is closed:
File file = LittleFS.open("/test.txt", FILE_WRITE);
file.print("*** Test successful ***");
file.close();
The file is reopened in read mode, its contents are printed to the serial monitor, and then it is closed:
file = LittleFS.open("/test.txt");
while (file.available()) {
Serial.write(file.read());
}
file.close();
We need to turn off the flash LED.
pinMode(flashPin, OUTPUT);
analogWrite(flashPin, 0);
3. Loop Function:
The loop() function remains empty since the entire process occurs within setup().
Serial Monitor Output
If the SD card test is successful, you will see *** Test successful ***
in the Serial Monitor.
This confirms that data can be written to and read from the SD card.
Additional SD Card Testing
For more extensive diagnostics, you can use the SDMMC_Test.ino example provided in the ESP32 library. This program includes additional debugging information and can be accessed via:
File > Examples > Examples for AI-Thinker ESP32-CAM > SDMMC > SDMMC_Test
Testing the Camera
After verifying the SD card, the next step is to test the camera module. The following is a simplified program that captures an image each time the ESP32-CAM is reset. The image will be saved in the SD card.
#include "esp_camera.h"
#include "soc/rtc_cntl_reg.h"
#include "SD_MMC.h"
#include "EEPROM.h"
// Pin configuration for AI-Thinker ESP32-CAM module
#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
void configCamera() {
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
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_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_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_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
esp_camera_init(&config);
}
unsigned int incrementCounter() {
unsigned int counter = 0;
EEPROM.get(0, counter);
EEPROM.put(0, counter + 1);
EEPROM.commit();
return counter;
}
void captureImage() {
camera_fb_t* fb = esp_camera_fb_get();
unsigned int counter = incrementCounter();
String filename = "/pic" + String(counter) + ".jpg";
Serial.println(filename);
File file = SD_MMC.open(filename.c_str(), FILE_WRITE);
file.write(fb->buf, fb->len);
file.close();
esp_camera_fb_return(fb);
}
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
SD_MMC.begin();
EEPROM.begin(16);
configCamera();
captureImage();
esp_deep_sleep_start();
}
void loop() {
}
Code Overview
The configCamera() function sets up the camera with the appropriate pin configurations.
The incrementCounter() function tracks the number of captured images using EEPROM.
The captureImage() function takes a picture and saves it to the SD card.
The setup() function initializes the camera and SD card, captures an image, and puts the ESP32-CAM into deep sleep mode to conserve power.
This basic framework can be expanded for use cases such as motion-triggered or interval-based image capture.
Frequently Asked Questions
Here are some common problems that you may face while working with the ESP32-CAM. You have provided the solutions too.
Wi-Fi Connectivity
Q: Why isn’t my ESP32-CAM connecting to Wi-Fi?
A: Check if you have entered the right SSID and password.
Camera & Image Quality
Q: Is there any way to improve the image quality of the camera?
A: Adjust the camera settings in your code, experimenting with different resolutions and frame rates for the best results.
Q: Why are my images blurry or unclear?
A: Poor lighting conditions can degrade image quality. Ensure proper lighting, fine-tune camera settings, and remove the protective lens foil.
Serial Communication & Code Upload
Q: Why the camera is not responding to serial monitor commands?
A: Check the connections between the board and the computer. Also, confirm that the baud rate (115200) in your code matches the serial monitor settings.
Q: Why do I see “Timed out waiting for packet header” during code upload?
A: An unstable USB connection may cause this problem. You can try a different USB cable or PORT.
Q: What to do if the ESP32-CAM freezes during code upload?
A: Disconnect and reconnect the USB cable, reset the board, and attempt the upload again. Check that your code isn't causing crashes.
Q: How to resolve the error “A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header”?
A: This may be caused by an incorrect baud rate or a faulty USB cable.
SD Card Issues
Q: Why isn’t my SD card being detected?
A: The SD card is properly inserted and formatted as FAT32. Cards between 4GB and 16GB work best, while higher-capacity cards may cause issues.
Power & Performance
Q: My ESP32-CAM gets hot—should I be concerned?
A: It’s normal for the board to warm up during operation, but excessive heat could indicate a short circuit or power issue.
Q: How can I reduce power consumption?
A: Use sleep modes.
Other Camera Issues
Q: Why isn’t my ESP32-CAM capturing images?
A: Check that the camera module is securely connected, and ensure the correct camera module type is defined in your code.
Q: Can I use ESP32-CAM for video streaming?
A: Use a web server library such as ESP32-CAM-Webserver to stream video over Wi-Fi. Ensure your network can handle the required bandwidth.
Bootloader & OTA Programming
Q: Why won’t my ESP32-CAM enter bootloader mode?
A: Ensure GPIO0 is connected to GND, and press the reset button at the correct moment to enter bootloader mode.
Q: Can I upload code wirelessly?
A: Yes, for that you have to use Over-The-Air (OTA) programming.
If you continue to experience issues, double-check the wiring, connections, and settings in your code.