Go Down

Topic: [SOLVED] Problem with camera module OV7670 (Read 16901 times) previous topic - next topic

matanbright

Mar 17, 2018, 07:02 pm Last Edit: Apr 02, 2018, 11:09 am by matanbright
Hello,

I have Arduino MEGA 2560 and camera module OV7670.

The camera module doesn't work!

I have tried the following tutorials:
http://www.instructables.com/id/OV7670-Without-FIFO-Very-Simple-Framecapture-With-/
http://www.instructables.com/id/OV7670-Arduino-Camera-Sensor-Module-Framecapture-T/
https://forum.arduino.cc/index.php?topic=159557.0
https://create.arduino.cc/projecthub/tech-duino/visual-capturing-with-ov7670-on-arduino-069ebb
These tutorials are for the Arduino UNO and I have changed the DDRx, PORTx and PINx values so it will match the pins on the Arduino MEGA, but it is not working!

I think that the camera module is fake, because it doesn't look like in the pictures from the internet:


Please help me! Thank you.

falexandru

#1
Mar 20, 2018, 08:50 pm Last Edit: Mar 20, 2018, 08:52 pm by falexandru
I have one similar to the internet one.

I did not un-seal it by now (scheduled for a later stage of the project). But I brought it from a commercial reputable and reliable source in my country. So, from the appearance, the one in the image on the right is the same to the one that I have,

It does not mean that the left one is a fake, according to my knowledge.

Could be a basic/simplified version.

What do you mean by "does not work"? The code does not compile? The camera does not send anthing to the board?

I have no idea about the camera as such, but many times I wired incorrectly or the jumpers do not contact.

matanbright

Ok, finally it is working, so it is not a fake module  :) .
It was not working because I forgot to change some timer registers values that work on the Arduino UNO but not on the Arduino MEGA. Now the timer generates 8MHz PWM signal for the Master Clock of the OV7670 and I am able to capture frames.


But I still have a problem!
I can't modify the camera registers.
The camera is connected to the Arduino SCL and SDA pins, and the communications with the camera registers is done via I2C protocol.

As far as I know, the camera communicates via SCCB protocol, that can be implemented via the I2C protocol.
For writing value to a camera register:
1) The Arduino starts a I2C transmission to the camera.
2) The Arduino sends a byte representing the ID of the register that we want to modify its value.
3) The Arduino sends a byte representing the value to write to the register.
4) The Arduino ends the I2C transmission.
Here is my code for writing value to a register:
Code: [Select]
void writeCameraRegister(byte registerId, byte registerValue) {
  Wire.beginTransmission(0x42);
  Wire.write(registerId);
  Wire.write(registerValue);
  Wire.endTransmission();
}

For reading value from a camera register:
1) The Arduino starts a I2C transmission to the camera.
2) The Arduino sends a byte representing the ID of the register that we want to read its value.
3) The Arduino ends the I2C transmission.
4) The Camera sends to the Arduino the value of the register.
Here is my code for reading value from a register:
Code: [Select]
byte readCameraRegister(byte registerId) {
  Wire.beginTransmission(0x42);
  Wire.write(registerId);
  Wire.endTransmission();
  Wire.requestFrom(0x43, 1);
  return Wire.read();
}


According to the OV7670 datasheet, the slave addresses of the camera are: 0x42 for writing and 0x43 for reading. But when I try to read a value from a register, the camera doesn't respond to the request.
I send to the camera the ID of the register I want to read its value, but the camera doesn't send me back the value.

I tried to run a code that tries all the possible addresses for I2C devices and prints if an address starts a connection successfully, but none of the address started a connection, so it means that there is a problem with the camera's I2C connection with the Arduino.
The code is from here: https://playground.arduino.cc/Main/I2cScanner

Please help me! Thank you.

matanbright

#3
Mar 28, 2018, 05:13 pm Last Edit: Mar 31, 2018, 11:19 am by matanbright
Ok, finally after all my tries it works perfect!  :)
Now I can modify the camera registers and I can take pictures and videos from the camera with my Arduino MEGA without any problems!

In the beginning it was not worked for me because I have tried a code that was for the Arduino UNO, so I forgot to change some of the registers names and values in order that they will be compatible with the Arduino MEGA (I mean to the DDRx, PORTx and PINx registers) and in addition, the Arduino MEGA has different pins associated with each PWM timer so I forgot to change the pin to be compatible with the timer used in the code (I mean to the OCRxA registers associated pins).

Then, I had problem with communicating with the camera registers. I could not communicate with the registers because I have used the write address (0x42) and the read address (0x43) of the camera in the "Wire.beginTransmitting" and "Wire.requestFrom" functions. These addresses contain the read/write bit for the I2C:
0x42 --> 1000010
0x43 --> 1000011
But the I2C functions need the address without the read/write bit because they handle the read/write adresses automatically.
So if we shift the bits of the read/write addresses to the right once (1000010 >> 1) we will get the address without the read/write bit: 0x21 (1000010 >> 1 = 0100001).
So when I write the address 0x21 in the I2C functions it works!
Code: [Select]
Wire.beginTransmission(0x21);
Wire.requestFrom(0x21, 1);

Please note that the camera needs a PWM signal at the master clock pin (MCLK or XCLK) even for the communication via the I2C with the Arduino. Without the master clock signal, the camera will not work at all! Because of that, when I tried the code that tries all the possible addresses for I2C devices, even when it tried the address 0x21, the communication didn't work!


So the problem has been solved!  :)

zoomx


matanbright

#5
Mar 29, 2018, 10:29 pm Last Edit: Mar 31, 2018, 09:35 pm by matanbright
Here is my sketch and the connections.
The sketch is for capturing grayscale images (because it is easier).
For receiving images you will need to install the software from one of the tutorials from the first post.



Code: [Select]
// Pins configurations:
// SDA/SIOD ---> pin A4 (for Arduino UNO) | pin 20/SDA (for Arduino MEGA)
// SCL/SIOC ---> pin A5 (for Arduino UNO) | pin 21/SCL (for Arduino MEGA)
// MCLK/XCLK --> pin 11 (for Arduino UNO) | pin 10 (for Arduino MEGA)
// PCLK -------> pin 2
// VS/VSYNC ---> pin 3
// HS/HREF ----> pin 8
// D0 ---------> pin A0
// D1 ---------> pin A1
// D2 ---------> pin A2
// D3 ---------> pin A3
// D4 ---------> pin 4
// D5 ---------> pin 5
// D6 ---------> pin 6
// D7 ---------> pin 7

#include <Wire.h>

#define CAMERA_ADDRESS 0x21

// Definitions of functions for manipulating the Arduino boards pins according to each Arduino board registers, so the code will work for both Arduino UNO and Arduino MEGA:
// The only change is the connections of the SDA/SIOD, SCL/SIOC and MCLK/XCLK pins to each board (see the pins configurations above).
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // If you are using Arduino MEGA the IDE will automatically define the "__AVR_ATmega1280__" or "__AVR_ATmega2560__" constants.
#define TIMER2_PWM_A_PIN_MODE_OUTPUT() ({ DDRB |= 0b00010000; })
#define PIN2_DIGITAL_READ() ({ (PINE & 0b00010000) == 0 ? LOW : HIGH; })
#define PIN3_DIGITAL_READ() ({ (PINE & 0b00100000) == 0 ? LOW : HIGH; })
#define PIN4_DIGITAL_READ() ({ (PING & 0b00100000) == 0 ? LOW : HIGH; })
#define PIN5_DIGITAL_READ() ({ (PINE & 0b00001000) == 0 ? LOW : HIGH; })
#define PIN6_DIGITAL_READ() ({ (PINH & 0b00001000) == 0 ? LOW : HIGH; })
#define PIN7_DIGITAL_READ() ({ (PINH & 0b00010000) == 0 ? LOW : HIGH; })
#define PIN8_DIGITAL_READ() ({ (PINH & 0b00100000) == 0 ? LOW : HIGH; })
#define PINA0_DIGITAL_READ() ({ (PINF & 0b00000001) == 0 ? LOW : HIGH; })
#define PINA1_DIGITAL_READ() ({ (PINF & 0b00000010) == 0 ? LOW : HIGH; })
#define PINA2_DIGITAL_READ() ({ (PINF & 0b00000100) == 0 ? LOW : HIGH; })
#define PINA3_DIGITAL_READ() ({ (PINF & 0b00001000) == 0 ? LOW : HIGH; })
#elif defined(__AVR_ATmega328P__) // If you are using Arduino UNO the IDE will automatically define the "__AVR_ATmega328P__" constant.
#define TIMER2_PWM_A_PIN_MODE_OUTPUT() ({ DDRB |= 0b00001000; })
#define PIN2_DIGITAL_READ() ({ (PIND & 0b00000100) == 0 ? LOW : HIGH; })
#define PIN3_DIGITAL_READ() ({ (PIND & 0b00001000) == 0 ? LOW : HIGH; })
#define PIN4_DIGITAL_READ() ({ (PIND & 0b00010000) == 0 ? LOW : HIGH; })
#define PIN5_DIGITAL_READ() ({ (PIND & 0b00100000) == 0 ? LOW : HIGH; })
#define PIN6_DIGITAL_READ() ({ (PIND & 0b01000000) == 0 ? LOW : HIGH; })
#define PIN7_DIGITAL_READ() ({ (PIND & 0b10000000) == 0 ? LOW : HIGH; })
#define PIN8_DIGITAL_READ() ({ (PINB & 0b00000001) == 0 ? LOW : HIGH; })
#define PINA0_DIGITAL_READ() ({ (PINC & 0b00000001) == 0 ? LOW : HIGH; })
#define PINA1_DIGITAL_READ() ({ (PINC & 0b00000010) == 0 ? LOW : HIGH; })
#define PINA2_DIGITAL_READ() ({ (PINC & 0b00000100) == 0 ? LOW : HIGH; })
#define PINA3_DIGITAL_READ() ({ (PINC & 0b00001000) == 0 ? LOW : HIGH; })
#endif


void initializePWMTimer() {
  cli();
  TIMER2_PWM_A_PIN_MODE_OUTPUT(); // Set the A PWM pin of TIMER2 to output
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
  TCCR2A = (1 << COM2A0) | (1 << WGM21) | (1 << WGM20);
  TCCR2B = (1 << WGM22) | (1 << CS20);
  OCR2A = 0;
  sei();
}

byte readCameraRegister(byte registerId) {
  Wire.beginTransmission(CAMERA_ADDRESS);
  Wire.write(registerId);
  Wire.endTransmission();
  Wire.requestFrom(CAMERA_ADDRESS, 1);
  while (Wire.available() <= 0);
  byte registerValue = Wire.read();
  delay(1);
  return registerValue;
}

void writeCameraRegister(byte registerId, byte registerValue) {
  Wire.beginTransmission(CAMERA_ADDRESS);
  Wire.write(registerId);
  Wire.write(registerValue);
  Wire.endTransmission();
  delay(1);
}

void captureFrame(unsigned int frameWidth, unsigned int frameHeight) {
  Serial.print("*RDY*"); // send to the frame capture software a "start of frame" message for beginning capturing

  delay(1000);

  cli(); // disable all interrupts during frame capture (because it needs to be as fast as possible)
  while (PIN3_DIGITAL_READ() == LOW); // wait until VS/VSYNC pin is high
  while (PIN3_DIGITAL_READ() == HIGH); // wait until VS/VSYNC pin is low
  unsigned int tempWidth = 0;
  while (frameHeight--) {
    tempWidth = frameWidth;
    while (tempWidth--) {
      while (PIN2_DIGITAL_READ() == LOW); // wait until PCLK pin is high
      while (PIN2_DIGITAL_READ() == HIGH); // wait until PCLK pin is low
      byte byteToWrite = 0b00000000;
      byteToWrite |= ((PIN7_DIGITAL_READ() == HIGH) << 7);
      byteToWrite |= ((PIN6_DIGITAL_READ() == HIGH) << 6);
      byteToWrite |= ((PIN5_DIGITAL_READ() == HIGH) << 5);
      byteToWrite |= ((PIN4_DIGITAL_READ() == HIGH) << 4);
      byteToWrite |= ((PINA3_DIGITAL_READ() == HIGH) << 3);
      byteToWrite |= ((PINA2_DIGITAL_READ() == HIGH) << 2);
      byteToWrite |= ((PINA1_DIGITAL_READ() == HIGH) << 1);
      byteToWrite |= ((PINA0_DIGITAL_READ() == HIGH));
      UDR0 = byteToWrite; // send data via serial connection with UART register (we need to use the serial register directly for fast transfer)
      while (PIN2_DIGITAL_READ() == LOW); // wait until PCLK pin is high
      while (PIN2_DIGITAL_READ() == HIGH); // wait until PCLK pin is low
      // ignore each second byte (for a grayscale image we only need each first byte, which represents luminescence)
    }
  }
  sei(); // enable all interrupts
  
  delay(1000);
}


void setup() {
  initializePWMTimer();
  Wire.begin();
  Serial.begin(1000000); // the frame capture software communicates with the Arduino at a baud rate of 1MHz
}

void loop() {
  captureFrame(320, 240); // capture a frame at QVGA resolution (320 x 240)
}

matanbright

#6
Mar 29, 2018, 10:36 pm Last Edit: Mar 31, 2018, 09:41 pm by matanbright
If you can't get a good image from the camera, you can try to set its registers to common values.
Put this method in the sketch and call it at the end of the "setup" function.

Code: [Select]
void initializeCamera() {
  // these are common registers values for initializing the camera to QVGA (320 x 240) mode at the maximum clock prescaler:
  writeCameraRegister(0x12, 0x80); // reset all camera registers to default value
  delay(1000); // wait for reset proccess to be done (because it is quite slow)
  writeCameraRegister(0x3A, 0x04);
  writeCameraRegister(0x12, 0x00);
  writeCameraRegister(0x17, 0x13);
  writeCameraRegister(0x18, 0x01);
  writeCameraRegister(0x32, 0xB6);
  writeCameraRegister(0x19, 0x02);
  writeCameraRegister(0x1A, 0x7A);
  writeCameraRegister(0x03, 0x0A);
  writeCameraRegister(0x0C, 0x00);
  writeCameraRegister(0x3E, 0x00);
  writeCameraRegister(0x70, 0x3A);
  writeCameraRegister(0x71, 0x35);
  writeCameraRegister(0x72, 0x11);
  writeCameraRegister(0x73, 0xF0);
  writeCameraRegister(0xA2, 0x01);
  writeCameraRegister(0x15, 0x00);
  writeCameraRegister(0x7A, 0x20);
  writeCameraRegister(0x7B, 0x10);
  writeCameraRegister(0x7C, 0x1E);
  writeCameraRegister(0x7D, 0x35);
  writeCameraRegister(0x7E, 0x5A);
  writeCameraRegister(0x7F, 0x69);
  writeCameraRegister(0x80, 0x76);
  writeCameraRegister(0x81, 0x80);
  writeCameraRegister(0x82, 0x88);
  writeCameraRegister(0x83, 0x8F);
  writeCameraRegister(0x84, 0x96);
  writeCameraRegister(0x85, 0xA3);
  writeCameraRegister(0x86, 0xAF);
  writeCameraRegister(0x87, 0xC4);
  writeCameraRegister(0x88, 0xD7);
  writeCameraRegister(0x89, 0xE8);
  writeCameraRegister(0x13, 0xC0);
  writeCameraRegister(0x00, 0x00);
  writeCameraRegister(0x10, 0x00);
  writeCameraRegister(0x0D, 0x40);
  writeCameraRegister(0x14, 0x18);
  writeCameraRegister(0xA5, 0x05);
  writeCameraRegister(0xAB, 0x07);
  writeCameraRegister(0x24, 0x95);
  writeCameraRegister(0x25, 0x33);
  writeCameraRegister(0x26, 0xE3);
  writeCameraRegister(0x9F, 0x78);
  writeCameraRegister(0xA0, 0x68);
  writeCameraRegister(0xA1, 0x03);
  writeCameraRegister(0xA6, 0xD8);
  writeCameraRegister(0xA7, 0xD8);
  writeCameraRegister(0xA8, 0xF0);
  writeCameraRegister(0xA9, 0x90);
  writeCameraRegister(0xAA, 0x94);
  writeCameraRegister(0x13, 0xC5);
  writeCameraRegister(0x30, 0x00);
  writeCameraRegister(0x31, 0x00);
  writeCameraRegister(0x0E, 0x61);
  writeCameraRegister(0x0F, 0x4B);
  writeCameraRegister(0x16, 0x02);
  writeCameraRegister(0x1E, 0x07);
  writeCameraRegister(0x21, 0x02);
  writeCameraRegister(0x22, 0x91);
  writeCameraRegister(0x29, 0x07);
  writeCameraRegister(0x33, 0x0B);
  writeCameraRegister(0x35, 0x0B);
  writeCameraRegister(0x37, 0x1D);
  writeCameraRegister(0x38, 0x71);
  writeCameraRegister(0x39, 0x2A);
  writeCameraRegister(0x3C, 0x78);
  writeCameraRegister(0x4D, 0x40);
  writeCameraRegister(0x4E, 0x20);
  writeCameraRegister(0x69, 0x00);
  writeCameraRegister(0x74, 0x10);
  writeCameraRegister(0x8D, 0x4F);
  writeCameraRegister(0x8E, 0x00);
  writeCameraRegister(0x8F, 0x00);
  writeCameraRegister(0x90, 0x00);
  writeCameraRegister(0x91, 0x00);
  writeCameraRegister(0x96, 0x00);
  writeCameraRegister(0x9A, 0x00);
  writeCameraRegister(0xB0, 0x84);
  writeCameraRegister(0xB1, 0x0C);
  writeCameraRegister(0xB2, 0x0E);
  writeCameraRegister(0xB3, 0x82);
  writeCameraRegister(0xB8, 0x0A);
  writeCameraRegister(0x43, 0x0A);
  writeCameraRegister(0x44, 0xF0);
  writeCameraRegister(0x45, 0x34);
  writeCameraRegister(0x46, 0x58);
  writeCameraRegister(0x47, 0x28);
  writeCameraRegister(0x48, 0x3A);
  writeCameraRegister(0x59, 0x88);
  writeCameraRegister(0x5A, 0x88);
  writeCameraRegister(0x5B, 0x44);
  writeCameraRegister(0x5C, 0x67);
  writeCameraRegister(0x5D, 0x49);
  writeCameraRegister(0x5E, 0x0E);
  writeCameraRegister(0x6C, 0x0A);
  writeCameraRegister(0x6D, 0x55);
  writeCameraRegister(0x6E, 0x11);
  writeCameraRegister(0x6F, 0x9E);
  writeCameraRegister(0x6A, 0x40);
  writeCameraRegister(0x01, 0x40);
  writeCameraRegister(0x02, 0x60);
  writeCameraRegister(0x13, 0xC7);
  writeCameraRegister(0x4F, 0x80);
  writeCameraRegister(0x50, 0x80);
  writeCameraRegister(0x51, 0x00);
  writeCameraRegister(0x52, 0x22);
  writeCameraRegister(0x53, 0x5E);
  writeCameraRegister(0x54, 0x80);
  writeCameraRegister(0x58, 0x9E);
  writeCameraRegister(0x41, 0x08);
  writeCameraRegister(0x3F, 0x00);
  writeCameraRegister(0x75, 0x05);
  writeCameraRegister(0x76, 0xE1);
  writeCameraRegister(0x4C, 0x00);
  writeCameraRegister(0x77, 0x01);
  writeCameraRegister(0x3D, 0x48);
  writeCameraRegister(0x4B, 0x09);
  writeCameraRegister(0xC9, 0x60);
  writeCameraRegister(0x56, 0x40);
  writeCameraRegister(0x34, 0x11);
  writeCameraRegister(0x3B, 0x12);
  writeCameraRegister(0xA4, 0x82);
  writeCameraRegister(0x96, 0x00);
  writeCameraRegister(0x97, 0x30);
  writeCameraRegister(0x98, 0x20);
  writeCameraRegister(0x99, 0x30);
  writeCameraRegister(0x9A, 0x84);
  writeCameraRegister(0x9B, 0x29);
  writeCameraRegister(0x9C, 0x03);
  writeCameraRegister(0x9D, 0x4C);
  writeCameraRegister(0x9E, 0x3F);
  writeCameraRegister(0x78, 0x04);
  writeCameraRegister(0x79, 0x01);
  writeCameraRegister(0xC8, 0xF0);
  writeCameraRegister(0x79, 0x0F);
  writeCameraRegister(0xC8, 0x00);
  writeCameraRegister(0x79, 0x10);
  writeCameraRegister(0xC8, 0x7E);
  writeCameraRegister(0x79, 0x0A);
  writeCameraRegister(0xC8, 0x80);
  writeCameraRegister(0x79, 0x0B);
  writeCameraRegister(0xC8, 0x01);
  writeCameraRegister(0x79, 0x0C);
  writeCameraRegister(0xC8, 0x0F);
  writeCameraRegister(0x79, 0x0D);
  writeCameraRegister(0xC8, 0x20);
  writeCameraRegister(0x79, 0x09);
  writeCameraRegister(0xC8, 0x80);
  writeCameraRegister(0x79, 0x02);
  writeCameraRegister(0xC8, 0xC0);
  writeCameraRegister(0x79, 0x03);
  writeCameraRegister(0xC8, 0x40);
  writeCameraRegister(0x79, 0x05);
  writeCameraRegister(0xC8, 0x30);
  writeCameraRegister(0x79, 0x26);
  writeCameraRegister(0xFF, 0xFF);
  writeCameraRegister(0x15, 0x20);
  writeCameraRegister(0x0C, 0x04);
  writeCameraRegister(0x3E, 0x19);
  writeCameraRegister(0x72, 0x11);
  writeCameraRegister(0x73, 0xF1);
  writeCameraRegister(0x17, 0x16);
  writeCameraRegister(0x18, 0x04);
  writeCameraRegister(0x32, 0xA4);
  writeCameraRegister(0x19, 0x02);
  writeCameraRegister(0x1A, 0x7A);
  writeCameraRegister(0x03, 0x0A);
  writeCameraRegister(0xFF, 0xFF);
  writeCameraRegister(0x12, 0x00);
  writeCameraRegister(0x8C, 0x00);
  writeCameraRegister(0x04, 0x00);
  writeCameraRegister(0x40, 0xC0);
  writeCameraRegister(0x14, 0x6A);
  writeCameraRegister(0x4F, 0x80);
  writeCameraRegister(0x50, 0x80);
  writeCameraRegister(0x51, 0x00);
  writeCameraRegister(0x52, 0x22);
  writeCameraRegister(0x53, 0x5E);
  writeCameraRegister(0x54, 0x80);
  writeCameraRegister(0x3D, 0x40);
  writeCameraRegister(0xFF, 0xFF);
  writeCameraRegister(0x11, 0x1F);
  writeCameraRegister(0x0C, 0x08);
  writeCameraRegister(0x3E, 0x19);
  writeCameraRegister(0x73, 0xF1);
  writeCameraRegister(0x12, 0x10);
  delay(1000); // wait for registers to be set (because it is quite slow)
}

ieee488

What can you do with this camera module?


Seems very interesting!



matanbright

You can take pictures and videos in various resolutions and fps (frames per second).
You can change the camera's settings (resolution, format, clock speed, brightness, contrast and more...) via the I2C connection.

ieee488

Thank you.

What you using this camera for ?


I am trying to decide whether I should buy one.

zoomx

Thanks matanbright!
Can you modify the topic title adding [Solved]?
This way many other users can find this topic.

matanbright

Thanks matanbright!
Can you modify the topic title adding [Solved]?
This way many other users can find this topic.
Yes, I did. Thank you!

matanbright

Thank you.

What you using this camera for ?


I am trying to decide whether I should buy one.
I am using it for taking small pictures and streaming small videos.

Please note that the Arduino is not intended for capturing frames because it doesn't have enough proccessing power for capturing all the pixels of the frames because it is quite slow and the frame capture proccess needs to be fast.
So with the Arduino you can capture images at low resolution and videos at low FPS (frames per second) rate, so the Arduino will be able to proccess it faster. So don't expect it to take pictures at high resolution and video at high FPS rate.

Please note that the camera has a version with a thing called FIFO. It is a hardware stack that keeps the frames data from the camera in FIFO order (first in first out), so the Arduino will be able to take them out from the stack at its own time.
I have the version without the FIFO, so I don't have experience with it.

I will recommend the camera if you want to try it and learn about it, and if you want to take small images and videos.

ieee488

Thank you.

Seems very interesting device to try and learn.    :)




.

falexandru


Go Up