In this tutorial, we will learn how to use ESP32-CAM with ESP-IDF to capture photos and save them to a microSD card. We will see how to add ESP-CAM library in esp-idf. Furthermore, An input pin of ESP32-CAM will be connected with a push button which will trigger the module to capture the photos and save them to SD card. The ESP32-CAM will be programmed in VS Code with ESP-IDF extension.
Before we move ahead, make sure you have the latest version of VS Code installed on your system with the ESP-IDF extension configured.
ESP32-CAM Introduction
The ESP32-CAM is part of the ESP32 development boards. It contains the ESP32-S chip, OV2640 video camera and a microSD card slot making it an inexpensive choice for IoT projects. It can be used in various projects including facial recognition, image tracking, wireless monitoring, and identification.
Key Features of ESP32-CAM
The key features of ESP32-CAM are given below:
- 802.11b/g/n Wi-Fi, Classic Bluetooth 4.2 and BLE
- Has two 32-bit LX6 CPUs
- Has 7 stage pipeline architecture
- Equipped with Hall, on-chip and temperature sensor
- Main frequency ranges from 80MHz-240MHz
- Supports UART/SPI/I2C/PWM/ADC/DAC interfaces
- 520 KB SRAM and 4MB PSRAM
- 160MHz clock speed with computing power up to 600 DMIPS
- Contains OV2640/OV7670 video cameras with built-in flash, image Wi-Fi upload, TF card, FOTA upgrades and various sleep modes
- FreeRTOS and embedded Lwip
ESP32-CAM OV2640 Video Camera Specifications
- 2 Megapixel sensor
- UXGA 1622×1200
- Output formats include: YUV422, YUV420, RGB565, RGB555
- 15-60 fps image transfer rate
For more information about ESP32-CAM, you can refer to the following article:
Hardware Setup
We will require the following components for this project
Required Components
- ESP32-CAM board with a camera
- USB to TTL converter
- microSD card
- Push button
- Connecting Wires
- External 5V Power Supply (optional)
The ESP32-CAM does not come with the USB port attached to it. Therefore, to upload a program sketch to the ESP32-CAM, we will need to use a FTDI programmer/USB to TTL Serial converter.
Connect 5V pin of USB to TTL converter with 5V pin of ESP32. Connect TX pin of USB to TTL converter with UOR (GPIO13) of ESP32-CAM. Similarly, connect RX pin of USB to TTL converter with UOT(GPIO1) of ESP32-CAM. Grounds will be common.
Follow the connections given in the table below to connect ESP32-CAM with the USB to TTL converter.
ESP32-CAM | USB to TTL Converter |
---|---|
5V | 5V |
UOR (GPIO3) | TX |
UOT (GPIO1) | RX |
GND | GND |
To upload code, connect GPIO0 of ESP32-CAM with GND pin of ESP32-CAM in order to enable it to go in flashing mode. After the code is successfully uploaded, remove this connection.
On uploading the code, if you get brown-out detector error then it means the USB power supply in inefficient. Therefore, you may use an external 5V power supply power the ESP32-CAM module. Follow the schematic diagram below for connections:
As we are capturing the photos with the pushbutton hence we will connect it with ESP32-CAM as well. After the code is uploaded, connect GPIO3 with one terminal of the push button. The other terminal of the push button will be grounded.
Format the MicroSD card
Lets format our microSD card as FAT32.
- Insert your microSD card in your system. Head over to ‘This PC’ and right click on SD card icon. Click on Format.
- Now select FAT32 (Default) from the File system option and then click the Start button.
- To format the disk, click the OK button. This will erase all the data on the disk.
- The format will complete shortly. Click the OK button.
ESP32-CAM Take Photo and Save to SD Card with ESP-IDF
We will create a project in VS Code using ESP-IDF extension. The ESP32 board connected with a push button will take a photo whenever the push button is pressed. The photo will get saved on the microSD card which is inserted in the microSD card slot.
Add ESP32 Camera Driver in ESP-IDF
Before creating our project, let us first add the ESP32 camera driver with ESP-IDF. Open the following link:(https://github.com/espressif/esp32-camera) which opens the GitHub page where the repository is provided. Go to Code > Download ZIP and download the zip file. This ESP32 series Soc compatible driver is built for image sensors which also allows the captured framed data to be converted to JPEG/BMP files.
After the folder is downloaded, extract it and paste it in the Components folder of ESP-IDF.
Create Example Project
Open your VS Code and head over to View > Command Palette. Type ESP-IDF: New Project in the search bar and press enter.
Specify the project name and directory. We have named our project ‘ESPCAM.’ For the ESP-IDF board, we have chosen the custom board option. For ESP-IDF target, we have chosen ESP32 module. Click ‘Choose Template’ button to proceed forward.
In the Extension, select ESP-IDF option:
We will click the ‘sample_project’ under the get-started tab. Now click ‘Create project using template sample_project.’
You will get a notification that the project has been created. To open the project in a new window, click ‘Yes.’
This opens the project that we created inside the EXPLORER tab. There are several folders inside our project folder. This is the same for every project which you will create through ESP-IDF Explorer.
Enable PSRAM
To use the ESP32 camera driver we will first have to enable PSRAM. You can enable it through menuconfig or open sdkconfig and add the following line in that file and save it.
CONFIG_ESP32_SPIRAM_SUPPORT=y
ESP32-CAM ESP-IDF Take a Photo and Save it to SD Card Code
Head over to the main.c file. The main folder contains the source code meaning the main.c file will be found here. Go to main > main.c and open it. Copy the code given below in that file and save it.
#include <esp_system.h>
#include <nvs_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/sdmmc_host.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "esp_vfs_fat.h"
#include "esp_camera.h"
#define BUTTON_PIN 3
static void button_handler(void *arg);
static void take_photo(void *arg);
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#define CONFIG_XCLK_FREQ 20000000
#define CONFIG_OV2640_SUPPORT 1
#define CONFIG_OV7725_SUPPORT 1
#define CONFIG_OV3660_SUPPORT 1
#define CONFIG_OV5640_SUPPORT 1
static esp_err_t init_camera(void)
{
camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sccb_sda = CAM_PIN_SIOD,
.pin_sccb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
.xclk_freq_hz = CONFIG_XCLK_FREQ,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_UXGA,
.jpeg_quality = 12,
.fb_count = 1,
.grab_mode = CAMERA_GRAB_WHEN_EMPTY};//CAMERA_GRAB_LATEST. Sets when buffers should be filled
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK)
{
return err;
}
return ESP_OK;
}
static esp_err_t initi_sd_card(void)
{
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 3,
};
sdmmc_card_t *card;
esp_err_t err = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
if (err != ESP_OK)
{
return err;
}
return ESP_OK;
}
static esp_err_t init_button_isr(void)
{
gpio_config_t io_conf;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << BUTTON_PIN);
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.pull_up_en = 1;
esp_err_t err = gpio_config(&io_conf);
if (err != ESP_OK)
{
return err;
}
return gpio_isr_handler_add(BUTTON_PIN, button_handler, NULL);
}
static TickType_t next = 0;
const TickType_t period = 2000 / portTICK_PERIOD_MS;
static void IRAM_ATTR button_handler(void *arg)
{
TickType_t now = xTaskGetTickCountFromISR();
if (now > next)
{
xTaskCreate(take_photo, "pic", configMINIMAL_STACK_SIZE * 5, NULL, 5, NULL);
}
next = now + period;
}
static void take_photo(void *arg)
{
printf("Starting Taking Picture!\n");
camera_fb_t *pic = esp_camera_fb_get();
char photo_name[50];
sprintf(photo_name, "/sdcard/pic_%li.jpg", pic->timestamp.tv_sec);
FILE *file = fopen(photo_name, "w");
if (file == NULL)
{
printf("err: fopen failed\n");
}
else
{
fwrite(pic->buf, 1, pic->len, file);
fclose(file);
}
esp_camera_fb_return(pic);
vTaskDelete(NULL);
printf("Finished Taking Picture!\n");
}
void app_main()
{
esp_err_t err;
err = init_camera();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
err = initi_sd_card();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
err = init_button_isr();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
printf("Everything is initialized successfully - Press Push button to take Picture\n");
}
How does the Code Work?
Firstly, we will start by including the necessary libraries that includes the FreeRTOS libraries to generate delays and create tasks. The driver/gpio.h as we have to use a GPIO pin of ESP32-CAM to connect with the pushbutton, microSD card libraries, and esp_camera.h for OV2640 camera.
#include <esp_system.h>
#include <nvs_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/sdmmc_host.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "esp_vfs_fat.h"
#include "esp_camera.h"
We define the ESP32-CAM GPIO that we have connected with the push button. It is GPIO3.
#define BUTTON_PIN 3
Next, we have definitions for OV2640 camera module pins. We are using CAMERA_MODEL_AI_THINKER.
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#define CONFIG_XCLK_FREQ 20000000
#define CONFIG_OV2640_SUPPORT 1
#define CONFIG_OV7725_SUPPORT 1
#define CONFIG_OV3660_SUPPORT 1
#define CONFIG_OV5640_SUPPORT 1
init_camera()
This init_camera() function is initializing a camera using the ESP-EYE, an ESP32-based development board with a built-in camera. The function init_camera takes in no arguments and returns an esp_err_t value indicating the status of the initialization.
The function starts by defining a camera_config variable of type camera_config_t. This variable is initialized with a number of fields that specify the configuration for the camera. These fields include:
- pin_pwdn: the pin number for the power-down pin of the camera.
- pin_reset: the pin number for the reset pin of the camera.
- pin_xclk: the pin number for the clock pin of the camera.
- pin_sccb_sda and pin_sccb_scl: the pin numbers for the SCCB (I2C-like) data and clock pins of the camera, respectively.
- pin_d7 through pin_d0: the pin numbers for the data pins of the camera.
- pin_vsync, pin_href, and pin_pclk: the pin numbers for the vertical sync, horizontal reference, and pixel clock pins of the camera, respectively.
- xclk_freq_hz: the frequency of the clock signal, in Hz.
- ledc_timer and ledc_channel: the timer and channel numbers for the LEDC (LED PWM controller) of the ESP32.
- pixel_format: the pixel format of the camera, specified as PIXFORMAT_JPEG.
- frame_size: the frame size of the camera, specified as FRAMESIZE_UXGA.
- jpeg_quality: the JPEG quality of the camera, specified as 12.
- fb_count: the number of frame buffers, specified as 1.
- grab_mode: the grab mode of the camera, specified as CAMERA_GRAB_WHEN_EMPTY. This specifies that the camera should fill its buffers when they are empty.
After the camera_config variable is initialized, the function calls the esp_camera_init function, passing it the address of the camera_config variable as an argument. This function initializes the camera using the configuration specified in camera_config. If the initialization is successful, the function returns ESP_OK. If an error occurs, it returns an error code.
static esp_err_t init_camera(void)
{
camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sccb_sda = CAM_PIN_SIOD,
.pin_sccb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
.xclk_freq_hz = CONFIG_XCLK_FREQ,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_UXGA,
.jpeg_quality = 12,
.fb_count = 1,
.grab_mode = CAMERA_GRAB_WHEN_EMPTY};//CAMERA_GRAB_LATEST. Sets when buffers should be filled
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK)
{
return err;
}
return ESP_OK;
}
init_sd_card()
This code is initializing an SD card and mounting it as a filesystem on the ESP32. The function init_sd_card takes in no arguments and returns an esp_err_t value indicating the status of the initialization.
The function starts by defining a host variable of type sdmmc_host_t, and initializing it with the default SDMMC host configuration. It also defines a slot_config variable of type sdmmc_slot_config_t, and initializes it with the default SDMMC slot configuration.
The function then defines a mount_config
variable of type esp_vfs_fat_sdmmc_mount_config_t
, and initializes it with the following fields:
- format_if_mount_failed: a boolean value that specifies whether to format the SD card if the mount fails. In this case, it is set to false.
- max_files: the maximum number of files that can be open at the same time. In this case, it is set to 3.
The function then declares a pointer card to an sdmmc_card_t structure and calls the esp_vfs_fat_sdmmc_mount function, passing it the following arguments:
- “/sdcard”: the mount point for the filesystem.
- &host: the address of the host variable, which specifies the SDMMC host configuration.
- &slot_config: the address of the slot_config variable, which specifies the SDMMC slot configuration.
- &mount_config: the address of the mount_config variable, which specifies the filesystem mount configuration.
- &card: the address of the card variable, which will be filled with information about the SD card.
The esp_vfs_fat_sdmmc_mount function initializes the SD card and mounts it as a filesystem at the specified mount point. If the initialization and mount are successful, the function returns ESP_OK. If an error occurs, it returns an error code.
static esp_err_t initi_sd_card(void)
{
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 3,
};
sdmmc_card_t *card;
esp_err_t err = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
if (err != ESP_OK)
{
return err;
}
return ESP_OK;
}
First, we define the default initializers for sdmmc_host_t and sdmmc_slot_config_t which are SDMMC_HOST_DEFAULT and SDMMC_SLOT_CONFIG_DEFAULT respectively.
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
Next, we have the options to mount the filesystem. If format_if_mount_failed is set to true this means that the microSD card will be partitioned and formatted in case the mount fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 3,
};
We use esp_vfs_fat_sdmmc_mount() to mount the FAT filesystem. It takes in five parameters which is the base path, host configuration, slot configuration, mount configuration and out card respectively. If the FAT filesystem is successfully mounted, ESP_OK is returned otherwise error code is returned.
sdmmc_card_t *card;
esp_err_t err = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
if (err != ESP_OK)
{
return err;
}
return ESP_OK;
init_button_isr()
The init_button_isr() will be called inside the app_main() function to initialize the push button ISR. The BUTTON_PIN GPIO is configured as an input with pull up resistor. The interrupt type us set as positive edge which means whenever the state of the push button will go from LOW to HIGH an interrupt will be triggered.
static esp_err_t init_button_isr(void)
{
gpio_config_t io_conf;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << BUTTON_PIN);
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.pull_up_en = 1;
esp_err_t err = gpio_config(&io_conf);
if (err != ESP_OK)
{
return err;
}
return gpio_isr_handler_add(BUTTON_PIN, button_handler, NULL);
}
Inside the interrupt service routine we will create a task which captures a photo and saves it to the SD card. This function is called whenever the interrupt occurs. i.e. pushbutton is pressed.
static TickType_t next = 0;
const TickType_t period = 2000 / portTICK_PERIOD_MS;
static void IRAM_ATTR button_handler(void *arg)
{
TickType_t now = xTaskGetTickCountFromISR();
if (now > next)
{
xTaskCreate(take_photo, "pic", configMINIMAL_STACK_SIZE * 5, NULL, 5, NULL);
}
next = now + period;
}
take_photo()
The take_photo() function is responsible for capturing the photo and saving it to the SD card. The esp_camera_fb_get() function returns the pointer to the frame buffer which is saved ‘pic.’ Then we open the file in the SD card using fopen() in write mode and save the picture. The name of the file is held in the character array ‘photo_name.’ After writing to the file we close the file using fclose(). Then we call esp_camera_fb_return() which returns the frame buffer to be reused again. After that we delete the task and print ‘Finished Taking Picture!’ in the ESP-IDF terminal.
static void take_photo(void *arg)
{
printf("Starting Taking Picture!\n");
camera_fb_t *pic = esp_camera_fb_get();
char photo_name[50];
sprintf(photo_name, "/sdcard/pic_%li.jpg", pic->timestamp.tv_sec);
FILE *file = fopen(photo_name, "w");
if (file == NULL)
{
printf("err: fopen failed\n");
}
else
{
fwrite(pic->buf, 1, pic->len, file);
fclose(file);
}
esp_camera_fb_return(pic);
vTaskDelete(NULL);
printf("Finished Taking Picture!\n");
}
Prints “Starting Taking Picture!”
printf("Starting Taking Picture!\n");
Calls the esp_camera_fb_get() function to get the camera frame buffer. This frame buffer contains the image data captured by the camera.
camera_fb_t *pic = esp_camera_fb_get();
Creates a string photo_name which is the path and file name for the photo to be saved. The file name includes the current timestamp in seconds.
char photo_name[50];
sprintf(photo_name, "/sdcard/pic_%li.jpg", pic->timestamp.tv_sec);
Opens a file with the specified name in write mode. If the file could not be opened, it prints an error message.
If the file was successfully opened, the function writes the image data in the frame buffer to the file and then closes the file.
FILE *file = fopen(photo_name, "w");
if (file == NULL)
{
printf("err: fopen failed\n");
}
else
{
fwrite(pic->buf, 1, pic->len, file);
fclose(file);
}
Calls the esp_camera_fb_return(pic) function to return the camera frame buffer back to the camera module.
esp_camera_fb_return(pic);
Deletes the current task using vTaskDelete(NULL).
vTaskDelete(NULL);
Prints “Finished Taking Picture!”.
printf("Finished Taking Picture!\n");
app_main()
Inside the app_main() function, we will first initialize the camera, SD card, and push button interrupt service routine. If there is a failure in any of the initializations, the error code will be printed on the ESP-IDF terminal.
void app_main()
{
esp_err_t err;
err = init_camera();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
err = initi_sd_card();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
err = init_button_isr();
if (err != ESP_OK)
{
printf("err: %s\n", esp_err_to_name(err));
return;
}
printf("Everything is initialized successfully - Press Push button to take Picture\n");
}
ESP32-CAM ESP-IDF SD Card Demo
To flash your chip, type the following command in the serial terminal. Remember to replace the COM port with the one through which your board is connected.
idf.py -p COMX flash monitor
After you have successfully uploaded your code to the board, remove the connecting wire from GPIO0 and GND. Connect GPIO3 with the push button.
Press the RESET button of ESP32-CAM. The following message appears on the terminal if all the initializations are successful.
Now press the push button. The state of the push button changes from LOW to HIGH and the interrupt occurs. This causes the a photo to be captured which gets saved on the SD card. The ESP-IDF terminal prints the message ‘Starting Taking Picture!’
Continue pressing the button and more pictures will get captured and get saved on the SD card.
To view the photos, insert the microSD card in your system. Here you can view the photos that we captured via ESP32-CAM which were saved to our microSD card.
ESP32-CAM Applications
There are many possible applications for the ESP32-CAM module. Here are a few examples:
- Security camera: The ESP32-CAM can be used to build a low-cost, remote-controlled security camera. The camera can be set up to take photos or videos at regular intervals, and the images can be sent to a remote server or device for storage and viewing.
- Time-lapse camera: The ESP32-CAM can be used to create a time-lapse video by taking photos at regular intervals and stitching them together. This can be used to capture the progress of a construction project, for example.
- Surveillance system: The ESP32-CAM can be used as part of a surveillance system, for example to monitor a warehouse or factory. The camera can be set up to detect motion and send an alert when movement is detected.
- Photo booth: The ESP32-CAM can be used to build a photo booth that allows users to take pictures of themselves and print or share the photos.
- Monitoring system: The ESP32-CAM can be used to monitor the health of plants or animals, for example by taking photos of them at regular intervals and analyzing the images for signs of stress or disease.
We are a team of experienced Embedded Software Developers with skills in developing Embedded Linux, RTOS, and IoT products from scratch to deployment with a demonstrated history of working in the embedded software industry. Contact us for your projects: admin@esp32tutorials.com
I get this error E (1367) camera: Camera probe failed with error 0x105(ESP_ERR_NOT_FOUND)
err: ESP_ERR_NOT_FOUND
Do you know how to fix it???
Thank you
Starting Taking Picture!
[0;31mE (10740) sdmmc_cmd: sdmmc_read_sectors_dma: sdmmc_send_cmd returned 0xffffffff[0m
[0;31mE (10740) diskio_sdmmc: sdmmc_read_blocks failed (-1)[0m
err: fopen failed
then esp32_cam_cd_card_key