[ESP32 + OV7670 + ArduinoIDE] How to capture frame

Hello,

I hope so this is the right place for this topic.

I'm using ESP32 with Arduino IDE and OV7670 sensor and I'd like to capture the frame. From this article I know more or less how it's working.

However, I'd like to handle the I2C protocol using Wire.h library. I also know that I need to config my clock and some sensor registers but I have no idea how exactly can I receive one frame from sensor?

I wrote something like this:

#include "XClk.h"
#include <Wire.h>

#define CAMERA_ADDRESS 0x21
#define XCLK 18
#define SDA 22
#define SCL 21



bool ClockEnable(int pin, int Hz)
{
    periph_module_enable(PERIPH_LEDC_MODULE);

    ledc_timer_config_t timer_conf;
    timer_conf.bit_num = (ledc_timer_bit_t)1;
    timer_conf.freq_hz = Hz;
    timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
    timer_conf.timer_num = LEDC_TIMER_0;
    esp_err_t err = ledc_timer_config(&timer_conf);
    if (err != ESP_OK) {
        return false;
    }

    ledc_channel_config_t ch_conf;
    ch_conf.channel = LEDC_CHANNEL_0;
    ch_conf.timer_sel = LEDC_TIMER_0;
    ch_conf.intr_type = LEDC_INTR_DISABLE;
    ch_conf.duty = 1;
    ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
    ch_conf.gpio_num = pin;
    ch_conf.hpoint = 0;
    err = ledc_channel_config(&ch_conf);
    if (err != ESP_OK) {
        return false;
    }
    return true;
}


void setup() {
  Serial.begin(115200); 
  ClockEnable(XCLK, 20000000); // 20kHz 
  
  Wire.begin(SDA, SCL);  

  // I know I need some sensor registers configuration here 
  byte buff[10];

  Wire.requestFrom(CAMERA_ADDRESS, 10); 
  Wire.readBytes(buff, 10); 

  for(int i=0; i<10; i++){
    Serial.print(buff[i]); 
  }

}

void loop() {
  
}

I will be grateful for any advice, thank you so much!

I am using this as a start :

http://bitluni.net/esp32-i2s-camera-ov7670/

But, in testing it, it is displaying garbage on the LCD (I disbled the Http Server).

Looking at the Code, it uses RGB565 - 2bytes per pixel :

camera = new OV7670( OV7670::Mode::QQVGA_RGB565, SIOD, SIOC, VSYNC, HREF, XCLK, PCLK, D0, D1, D2, D3, D4, D5, D6, D7);

But it inputs by skipping half of the bytes.
This should mess up the Colors atleast, yes ? :

void IRAM_ATTR I2SCamera::i2sInterrupt(void* arg)
{
    I2S0.int_clr.val = I2S0.int_raw.val ;
    blocksReceived ++ ;
    /// buf as Bytes : ///
    unsigned char* buf = dmaBuffer[dmaBufferActive]->buffer ;
    dmaBufferActive = (dmaBufferActive + 1) % dmaBufferCount ;
    
    if( framePointer < frameBytes )
    {
      /// Read buf[] as Line of Inc X of 4 pixels (skipping 2 of Pixels) : ///
      /// - if this is RGB565 - then how can you skip bytes ? ///
      for(int i = 0; i < xres * 4; i += 4)
      {

        /// only Copy Buf[] of (3rd) Pixel / byte to Frame[] of (1st) Byte : ///
        frame[ framePointer ++ ] = buf[ i + 2 ];
        
        /// only Copy Buf[] of (1st) Pixel / byte to Frame[] of (2nd) Byte : ///
        frame[ framePointer ++ ] = buf[ i ];
        
      }
    }
    
    if (blocksReceived == yres)
    {
      framePointer = 0;
      blocksReceived = 0;
      framesReceived++;
      if(stopSignal)
      {
        i2sStop();
        stopSignal = false;
      }
    }
    //    i2sStop();
    
}

While copying these bytes into the LCD as 16byte :

/// RGB 565 = 2 byte Pixel : ///
void displayRGB565(unsigned char * frame, int xres, int yres)
{
  tft.setAddrWindow(0, 0, yres - 1, xres - 1);
  int i = 0;
  
  for(int x = 0; x < xres; x++)
  {
    for(int y = 0; y < yres; y++)
    {
      i = (((y * xres) + x) << 1);
      
      tft.pushColor(( frame[ i ] | ( frame[ i + 1 ] << 8 ) ));
    }  
  }
}

Below is first 2 rasters of one screen.
Notice the common dual bytes - not always the same ? :

* Display :
* Print 2 Lines :
00 00 4C 4C 80 80 92 92 00 00 12 12 00 00 03 03 7F 7F 7E 7E 78 78 87 87 80 80 10 10 00 00 3B 3B 89 89 0B 0B 3E 42 8A 8A 92 92 85 85 8F 8F 01 01 8E 8F 00 00 46 46 80 80 90 90 00 00 53 53 17 17 9D 9D 48 48 64 64 83 83 00 00 4C 4C 00 00 94 94 80 80 8D 8D 00 00 8F 8F 80 80 5B 5B 80 80 94 94 7B 7B 9A 9A 8F 8F 75 75 62 62 8A 9A 85 85 89 89 94 94 80 80 9C 9C 80 80 8F 8F 80 80 81 81 00 00 9B 9B 9D 9D 4D 4D 5C 5C 8C 8C 99 99 9B 9B 83 83 7E 7E 80 80 9D 9D 9F 9D 97 97 5D 5D 8E 89 6C 6C 00 00 8B 98 80 80 58 58 91 91 A5 A5 AB AB 6A 6A 8D 7B 95 95 00 00 94 94 8A 8A 59 59 83 83 8A 8A 3F 3F 28 28 64 64 3F 2E 6D 6D 33 33 7B 7B 00 00 35 35 84 84 F6 F6 96 96 9E 9E A3 A3 AF AF 00 00 4A 4A 9D A0 80 80 92 92 02 02 80 80 7A 7A FF FF 

00 00 4C 4C 80 80 80 80 00 00 0F 0F 00 00 04 04 84 84 82 82 84 84 73 73 80 80 10 10 00 00 3B 3B 86 86 0A 0A 47 47 8B 8B 98 98 82 82 92 92 00 00 57 57 00 00 4E 4E 80 80 8C 8C 00 00 52 52 19 19 94 94 42 42 5F 5F 88 88 00 00 4A 4A 01 01 87 87 80 80 9C 9C 00 00 48 48 80 80 6C 6C 80 80 99 99 8E 8E A0 A0 59 59 6B 6B 6C 6C 7F 7F 99 99 99 99 92 92 80 80 A4 A4 80 80 7E 7E 80 80 80 80 00 00 77 77 9D 9D 4A 4A 5E 5E 80 80 9A 9A 5F 5F 81 81 7E 7E 80 80 97 97 A6 A6 97 97 5B 5B 8E 8E 63 63 00 00 97 97 80 80 59 59 9C 9C A8 A8 AF AF 87 87 1C 1C 9F 9F 00 00 99 99 7B 7B 51 51 6B 6B 8F 8C 3D 3E 27 27 8F 94 36 36 71 71 8D 8D 9B 9B 00 00 32 32 3E 37 FF FF AA A1 74 74 8D 8D 92 92 00 00 7F 8C A6 A6 80 80 A8 A8 00 00 80 80 1E 21 FF FF

Has anybody tried this project ?

Actually in testing,

The LCD is tested as clearing the screen.
But the camera is giving the wrong format, looking like noise garbage.
Although, blocking the lens gives a generally black screen,
bright light returns a white screen,
and Waving my hand returns shifting patterns repeating 10 stripes in say 16 pixels,
the format seems to be giving clearly misaligned pixels and bytes.

It seems that the I2C is not configuring the Camera.

I disconnected the SIOD line - giving the same nonsense screen result.
So it seems that the Camera is defaulting to the VGA YUV 640x480 mode.

The SIOC and SIOD test as connected with the MultiMeter and both have 2.4K pullups to the +3.3V

Why would the I2C not be talking to the Camera ?

Maybe its a normal problem with the I2C on the Esp32 Boards ?

I am not sure howto re-wire the I2C,

  • p23 is already used for LCD MOSI.

Instead of p22,p21
I tried p25,p19 - same result - not working

I also tried reducing the I2C routine Delay from 1us to 10us - same result.

This project uses I2C Bitbanging - so its not the Wire Driver.

I tried a few of the I2C Device Scanner software - nothing back on the I2C Port.

Hardware maybe - bad ov7670 Camera ?

  • I tried replacing the camera with another ov7670 - still same result - just scrambled pic.

I put together a second copy of this setup of new Esp32 + ov7670 + St7735(128x160).
Results are better, Colors match the Camera view, but still misaligned striped screen about 10 stripes (16 pixels?). The Stripes count across the 160 res - and dynamically shift across the LCD screen in half stripe Increments. (I would guess Cam is still in 640x480 mode.) So one Cam 640 Raster stretching across multiple 120 LCD Rasters.

I put together a second copy of this setup of new Esp32 + ov7670 + St7735(128x160).

Results are better, Colors match the Camera view,
but still misaligned striped screen about 10 stripes (16 pixels?).
The Stripes count across the 160 res - and dynamically shift across the LCD screen in half stripe Increments. (I would guess Cam is still in 640x480 mode.) So one Cam 640 Raster stretching across multiple 120 LCD Rasters.
I count 16 Raster shifts Vertically - following any Stripe - counting the 'Pixel Steps' down.

Below Images :

White Paper Snapshot :

Blue + Green + Yellow Markers Snapshot :

Rainbow Cable Snapshot :

Did a lot with the OV7670 years ago... crappy low frame rates that in the end were restricted because of the time it took to get ready and if read too fast it would "get angry".

Setting up all the pins is also a nightmare which is why I have a cloned Due sitting perm attached to one.

One advantage is that it's possible to interleave reading 8 bit parallel with SPI output.

Your "jaggies" look like a data problem.

Looks like the mode you're expecting is NOT what you're getting back. Seems each row has 2 rows.

Have a sift through my code and library... not been touched for ages but was working and has a lot of options built in.

Was a lot of conflicting information. A lot forgot to mention need pullups usually on SDA/SCL line. Ended up using a small S/W library for it.

Many weeks effort going to waste ATM.

My code at one stage compared 2 frames and looked for large differences for "detecting movement".

I have only just started looking at the ESP8266 and ESP32 modules and will eventually want to set up a web server with web cam attached. Just a modified version of SPI working well last night that allows processing between reading or writing SPI data.

OV7670.cpp (29.7 KB)

OV7670.h (10.1 KB)

example1.ino (121 KB)

sccb.h (624 Bytes)

sccb.cpp (2.99 KB)