Design a site like this with WordPress.com
Get started

ESP32-CAM Take Photo and Save to MicroSD Card

Learn how to take photos with the ESP32-CAM board and save them to a microSD card using Arduino IDE. When you press the ESP32-CAM RESET button, it wakes up, takes a photo and saves it in the microSD card.

We’ll be using the ESP32-CAM board labelled as AI-Thinker module, but other modules should also work by making the correct pin assignment in the code.

The ESP32-CAM board is a $9 device (or less) that combines an ESP32-S chip, an OV2640 camera, a microSD card slot and several GPIO pins.

For an introduction to the ESP32-CAM, you can follow the next tutorials:

Parts Required

To follow this tutorial you need the following components:

  • ESP32-CAM with OV2640 – read Best ESP32-CAM Dev Boards
  • MicroSD card
  • FTDI programmer
  • Female-to-female jumper wires
  • 5V power supply for ESP32-CAM or power bank (optional)

Project Overview

Here is a quick overview on how the project works.

  • The ESP32-CAM is in deep sleep mode
  • Press the RESET button to wake up the board
  • The camera takes a photo
  • The photo is saved in the microSD card with the name: pictureX.jpg, where X corresponds to the picture number
  • The picture number will be saved in the ESP32 flash memory so that it is not erased during RESET and we can keep track of the number of photos taken.

Formatting MicroSD Card

The first thing we recommend doing is formatting your microSD card. You can use the Windows formatter tool or any other microSD formatter software.

1. Insert the microSD card in your computer. Go to My Computer and right click in the SD card. Select Format as shown in figure below.

2. A new window pops up. Select FAT32, press Start to initialize the formatting process and follow the onscreen instructions.

Note: according to the product specifications, the ESP32-CAM should only support 4 GB SD cards. However, we’ve tested with 16 GB SD card and it works well.

Installing the ESP32 add-on

We’ll program the ESP32 board using Arduino IDE. So you need the Arduino IDE installed as well as the ESP32 add-on. You can follow one of the next tutorials to install the ESP32 add-on, if you haven’t already:

Take and Save Photo Sketch

Copy the following code to your Arduino IDE.

/*********
  Gnd_To_Vcc
  
  IMPORTANT!!! 
   - Select Board "AI Thinker ESP32-CAM"
   - GPIO 0 must be connected to GND to upload a sketch
   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>            // read and write from flash memory

// define the number of bytes you want to access
#define EEPROM_SIZE 1

// Pin definition for CAMERA_MODEL_AI_THINKER
#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

int pictureNumber = 0;

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  //Serial.println();
  
  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; 
  
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
  
  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  
  //Serial.println("Starting SD Card");
  if(!SD_MMC.begin()){
    Serial.println("SD Card Mount Failed");
    return;
  }
  
  uint8_t cardType = SD_MMC.cardType();
  if(cardType == CARD_NONE){
    Serial.println("No SD Card attached");
    return;
  }
    
  camera_fb_t * fb = NULL;
  
  // Take Picture with Camera
  fb = esp_camera_fb_get();  
  if(!fb) {
    Serial.println("Camera capture failed");
    return;
  }
  // initialize EEPROM with predefined size
  EEPROM.begin(EEPROM_SIZE);
  pictureNumber = EEPROM.read(0) + 1;

  // Path where new picture will be saved in SD Card
  String path = "/picture" + String(pictureNumber) +".jpg";

  fs::FS &fs = SD_MMC; 
  Serial.printf("Picture file name: %s\n", path.c_str());
  
  File file = fs.open(path.c_str(), FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file in writing mode");
  } 
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Saved file to path: %s\n", path.c_str());
    EEPROM.write(0, pictureNumber);
    EEPROM.commit();
  }
  file.close();
  esp_camera_fb_return(fb); 
  
  // Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
  rtc_gpio_hold_en(GPIO_NUM_4);
  
  delay(2000);
  Serial.println("Going to sleep now");
  delay(2000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  
}

The code starts by including the necessary libraries to use the camera. We also include the libraries needed to interact with the microSD card:

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>            // read and write from flash memory

And the EEPROM library to save permanent data in the flash memory.

#include <EEPROM.h>

If you want to learn more about how to read and write data to the flash memory, you can follow the next tutorial:

Define the number of bytes you want to access in the flash memory. Here, we’ll only use one byte that allows us to generate up to 256 picture numbers.

#define EEPROM_SIZE 1

Then, define the pins for the AI-THINKER camera module.

// Pin definition for CAMERA_MODEL_AI_THINKER 
#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

Note: you might need to change the pin definition depending on the board you’re using. Wrong pin assignment will result in a failure to init the camera.

Initialize an int variable called pictureNumber that that will generate the photo name: picture1.jpg, picture2.jpg, and so on.

int pictureNumber = 0;

All our code is in the setup(). The code only runs once when the ESP32 wakes up (in this case when you press the on-board RESET button).

Define the camera settings:

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; 

Use the following settings for a camera with PSRAM (like the one we’re using in this tutorial).

if(psramFound()){
  config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10;
  config.fb_count = 2;
}

If the board doesn’t have PSRAM, set the following:

else {
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
}

Initialize the camera:

// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
  Serial.printf("Camera init failed with error 0x%x", err);
  return;
}

Initialize the microSD card:

//Serial.println("Starting SD Card");
if(!SD_MMC.begin()){
  Serial.println("SD Card Mount Failed");
  return;
}
 
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
  Serial.println("No SD Card attached");
  return;
}

More information about how to use the microSD card can be found in the following project:

The following lines take a photo with the camera:

camera_fb_t * fb = NULL;

// Take Picture with Camera
fb = esp_camera_fb_get();  
if(!fb) {
  Serial.println("Camera capture failed");
  return;
}

After that, initialize the EEPROM with the size defined earlier:

EEPROM.begin(EEPROM_SIZE);

The picture number is generated by adding 1 to the current number saved in the flash memory.

pictureNumber = EEPROM.read(0) + 1;

To save the photo in the microSD card, create a path to your file. We’ll save the photo in the main directory of the microSD card and the file name is going to be (picture1.jpg, picture2.jpg, picture3.jpg, etc…).

String path = "/picture" + String(pictureNumber) +".jpg";

These next lines save the photo in the microSD card:

fs::FS &fs = SD_MMC; 
Serial.printf("Picture file name: %s\n", path.c_str());

File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
  Serial.println("Failed to open file in writing mode");
} 
else {
  file.write(fb->buf, fb->len); // payload (image), payload length
  Serial.printf("Saved file to path: %s\n", path.c_str());
  EEPROM.write(0, pictureNumber);
  EEPROM.commit();
}
file.close();

After saving a photo, we save the current picture number in the flash memory to keep track of the number of photos taken.

EEPROM.write(0, pictureNumber);
EEPROM.commit();

When the ESP32-CAM takes a photo, it flashes the on-board LED. After taking the photo, the LED remains on, so we send instructions to turn it off. The LED is connected to GPIO 4.

pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);

Finally, we put the ESP32 in deep sleep.

esp_deep_sleep_start();

Because we don’t pass any argument to the deep sleep function, the ESP32 board will be sleeping indefinitely until RESET.

ESP32-CAM Upload Code

To upload code to the ESP32-CAM board, connect it to your computer using an FTDI programmer. Follow the next schematic diagram:

Many FTDI programmers have a jumper that allows you to select 3.3V or 5V. Make sure the jumper is in the right place to select 5V.

Important: GPIO 0 needs to be connected to GND so that you’re able to upload code.

ESP32-CAMFTDI Programmer
GNDGND
5VVCC (5V)
U0RTX
U0TRX
GPIO 0GND

To upload the code, follow the next steps:

1) Go to Tools Board and select AI-Thinker ESP32-CAM.

2) Go to Tools Port and select the COM port the ESP32 is connected to.

3) Then, click the upload button to upload the code.

4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.

After a few seconds, the code should be successfully uploaded to your board.

Demonstration

After uploading the code, remove the jumper that connects GPIO 0 from GND.

Open the Serial Monitor at a baud rate of 115200. Press the ESP32-CAM reset button. It should initialize and take a photo. When it takes a photo it turns on the flash (GPIO 4).

Check the Arduino IDE Serial Monitor window to see if everything is working as expected. As you can see, the picture was successfully saved in the microSD card.

Note: if you’re having issues with the ESP32-CAM, take a look at our troubleshooting guide and see if it helps: ESP32-CAM Troubleshooting Guide: Most Common Problems Fixed

After making sure that everything is working as expected, you can disconnect the ESP32-CAM from the FTDI programmer and power it using an independent power supply.

To see the photos taken, remove the microSD card from the microSD card slot and insert it into your computer. You should have all the photos saved.

The quality of your photo depends on your lighting conditions. Too much light can ruin your photos and dark environments will result in many black pixels.

Troubleshooting

If you’re getting any of the following errors, read our ESP32-CAM Troubleshooting Guide: Most Common Problems Fixed

  • Failed to connect to ESP32: Timed out waiting for packet header
  • Camera init failed with error 0x20001 or similar
  • Brownout detector or Guru meditation error
  • Sketch too big error – Wrong partition scheme selected
  • Board at COMX is not available – COM Port Not Selected
  • Psram error: GPIO isr service is not installed
  • Weak Wi-Fi Signal
  • No IP Address in Arduino IDE Serial Monitor
  • Can’t open web server
  • The image lags/shows lots of latency

Wrapping Up

As mentioned previously, we have other tutorials about the ESP32-CAM that you may like:

Thank you for reading.

Advertisement

Published by Gnd_To_Vcc

Here to spread my knowledge . Knowledge should always be spread not stored.

14 thoughts on “ESP32-CAM Take Photo and Save to MicroSD Card

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: