Capturing corrupted images with OV2640 camera and ESP32S3 module

Hi everyone
I had designed a board for the ESP32-S3-WROOM-1-N16R8 module (this module has 8MB PSRAM memory and 16MB flash memory) . I wanted the camera OV2640 to capture an image frame with XGA resolution (768*1024) and save it on the SD card. SD Card is also set up with SDIO interface.
.
But the problem is that saved images are very bad. For example, the images are cropped, half of the image is green and the rest of the image is completely black, etc.
.
Camera OV2640 is correctly.
I thought that there might be a problem in saving the images on the SD card, so I also tested the example code camera_webserver in arduino. but still received images by Wifi was corrupted.
.
What could be the problem? For example, Should another option be selected for PSRAM memory? Or is there a problem with the coding?
.

#include "esp_camera.h"
#include "SD_MMC.h"

// Define Camera pins
#define PWDN_GPIO_NUM  -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM  10
#define SIOD_GPIO_NUM  4
#define SIOC_GPIO_NUM  5
#define Y9_GPIO_NUM    9
#define Y8_GPIO_NUM    11
#define Y7_GPIO_NUM    12
#define Y6_GPIO_NUM    14
#define Y5_GPIO_NUM    47
#define Y4_GPIO_NUM    45
#define Y3_GPIO_NUM    48
#define Y2_GPIO_NUM    21
#define VSYNC_GPIO_NUM 3
#define HREF_GPIO_NUM  46
#define PCLK_GPIO_NUM  13

// Define SDIO pins
#define MMCSCK 16
#define MMCCMD 17
#define MMCD0 15
#define MMCD1 7
#define MMCD2 8
#define MMCD3 18


// Frame settings
#define FRAME_RATE       10  // FPS
#define FRAME_DURATION   1000 / FRAME_RATE  // Duration of each frame in milliseconds

unsigned long now;
static unsigned long lastCapture = 0;

static int frameCount = 0;
static File file;


void setup() {
    Serial.begin(115200);

    // Camera configuration
    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_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;

    // Set the resolution frame image
    config.frame_size = FRAMESIZE_XGA; //1024x768
    config.jpeg_quality = 12;
    config.fb_count = 1;

    // Use PSRAM for the frame buffer
    config.fb_location = CAMERA_FB_IN_PSRAM;

    if (psramFound()) {
      Serial.println("PSRAM FOUND"); // when run code alwayse PSRAM FOUND.
    }

    // Initialize the camera
    if (esp_camera_init(&config) != ESP_OK) {
        Serial.println("Failed to initialize camera.");
        return;
    }

    // Initialize SD card
    SD_MMC.setPins(MMCSCK, MMCCMD, MMCD0, MMCD1, MMCD2, MMCD3);
    if (!SD_MMC.begin()) {
        Serial.println("SD card mount failed.");
        return;
    }

    Serial.println("SD card initialized.");
}

void loop() {

    now = millis();

    if (now - lastCapture>=FRAME_DURATION) {
        lastCapture = now;
                
        // Capture a frame
        camera_fb_t *fb = esp_camera_fb_get();
        if (!fb) {
            Serial.println("Failed to capture image.");
            return;
        }
        
        // Save frame to SD card
        String path = "/frame" + String(frameCount) + ".jpg";
        
        file = SD_MMC.open(path, FILE_WRITE);
        if (!file) {
            Serial.println("Failed to open file for writing.");
            esp_camera_fb_return(fb);
            return;
        }

        file.write(fb->buf, fb->len);
        file.close();
        
        esp_camera_fb_return(fb);

        frameCount++;
    }

    // Capture frames for 10 seconds
    if (millis() - start_capture >= 10000) {
        Serial.println("Capture complete.");
        while (true);  // Stop the loop
    }
}

.

Faulty circuit or PCB design? Bad connector? Bad camera? Poor solder joints?

but in low resolution like QVGA (320x240), image is good.

Sounds like a coding or memory problem. Test other resolutions.

I tested other resolutions like UXGA, XGA, ...
when reduced resolution of image is better capture and corrupted is less.
But I need better resolution like XGA.

Sorry, I have not tried doing any of this on ESP32... However I have played with 2640 and 5640 on Teensy 4.x and Arduino GIGA and found that with some of these devices and the like, that potentially the data was coming in faster than it could handle and data could be corrupted. With the Teensy 4.1 with PSRAM, I had some better luck when I updated the startup code to boost the speed that we were talking to the PSRAM.

Again sorry I don't know ESP32 well enough. Not sure if you can do similar?
Also don't know how or if it has memory cache and how it works with the PSRAM region of memory space. Or if for example there are calls you need or should call to flush out the cache.

Sorry just throwing darts.

1 Like

Bad camera or poorly mounted?

NO, Camera in low resolution good working.

Thank you so much KurtE. :pray:
Thanks for ideas, I will checking them.

Can you please send me the schematics of esp32 s3 wroom with ov2640 as I am not able to find any. I have tried several pcb iterations but still not working. Wasted alot of money on PCB. Please help. Mukulsunda70@gmail.com

NO, put in some effort yourself, I heard a rumour that if you type your question into a google screen you might get some help. When you are ready, hand drawn wiring diagram is ok, and post code in code tags.

1 Like

Your device is receiving data from the camera faster than it can handle. Proof is lower resolutions need to send less data, hence they have a better chance of the image data being stored before an error can occur.

There can be a number of reasons for this, I've seen that happen in quite a few instances:

  • first of all, the OV2640 can use native jpeg compression. I suggest using it, as the image data to transfer is less. This makes using high resolutions possible. If you instead use RGB565 or worse, RAW the amount of data process before an interrupt or the scheduler ruins your job is simply too much.

  • transferring the image data from the DMA buffer to the PSRAM is a job that takes the highest priority. If by any chance you do something else that can interfere with such job, the data will be corrupted. Remember the camera sensor is not going to wait for your other tasks to finish. Once it transfers a frame, it won't stop until the process is complete.

  • wrong clock frequencies... this is the least plausible reason. Yet, clock freuquencies too low or too high could be a source of problems: low speed means the framebuffer data takes too long to transfer. High speed means on the other hand you can hit some hardware bottleneck.

Honestly, I think the most plausible explanations might be the first or the second, or both.

The ESP32-CAM example shows, on the other hand, how to do the whole process correctly.