Go Down

Topic: OV7670 with both arduino uno and now mega (Read 449203 times) previous topic - next topic


In the first place you have to be sure your cam is working. If you have a problem with the clock you are feeding, you will waste a lot of time. In my case, I used the 16MHz clock from Arduino and I feed it right into the camera, because at 16MHz you don't have 5V signal. You should check with an oscilloscope to see what's the real amplitude of your 8MHz clock. To see if the camera is working you have to check the PCLK output.
If you don't have an oscilloscope, I would recommend you check PCLK using a frequency meter. You have to be sure the module is working. After that, capture covering the camera lens to get a frame of a black image. You should see these chain of bytes: 80 00 80 00 80....


Thanks for the response.
I do think the camera is working. I'm able to read and write to registers, and from my oscilloscope it seems like VSYNC is going high at a reasonable rate. I'm also able to see the PCLK output, which is 250khz when reg 0x11 is set to 0x03. Here is a picture of the oscilloscope when measuring the PCLK: http://imgur.com/YQhWI8d

Actually, I just noticed the peak to peak is ~5v, and the min/max are -1.8v/3.6v - is that bad?

Here is the signal going into the OV7670 XCLK: http://imgur.com/syTEAat

When I try to capture with the lens covered I get mostly 00 00 00... and sometimes some garbage.

Out of curiosity, how would I go about getting the 16Mhz arduino clock output? I've never burned a bootloader and I only have a usb connector, can I do it with just that?


Ok, if the module is working, and you are able to read/write registers you are almost done. The next hard-to-do thing is, configuring all the undocumented registers. If you fail to do that, you won't get the camera working. You can be sure about that.

You MUST write all the registers in ov7670_default_regs[] and then those in ov7670_fmt_yuv422[] :


Also, start by getting PCLK as low as possible first. As far as I remember I wasn't able to get a good reading with REG_CLKRC under 20 (decimal). But, I'm feeding 16MHz clock and you have half this clock, which makes you PCLK half mine when using the same divider in REG_CLKRC. So (I'm totally guessing here), you should be able to make it work with REG_CLKRC set at 10. The reading code has to be as quick as possible and you have to use cli() before start reading. Please post the portion of code you are using to read from the camera.

For burning fuses I needed a second Ardunio, with a program called ISP http://arduino.cc/en/Tutorial/ArduinoISP but I wouldn't recommend that approach for this project. Using 8MHz clock is simpler and better. Yet, it's the limit for OV7670, you won't be able to make it work with less than that. As the datasheet says the minimum clock should be 10MHz.


Jul 16, 2013, 06:48 pm Last Edit: Jul 16, 2013, 06:51 pm by Mr_arduino Reason: 1
About the 10mhz limit. I don't think that is true I have left the ov7670 on with an 8mhz clock for hours and nothing bad has happened. Also I have looked at other new sensors from omnivision datasheets to see if I can figure out what the undocumented registers mean and most of the newer datasheets say 6mhz is the lower limit for the clock. Usually overclocking is more dangerous than under-clocking.
Actually I made some corrections to the linux driver registers. Also the code I have on my github page uses divider settings is for people with the 8mhz clock. I have posted about the registers on my github page before but I have sense made some changes. Here are the files you need.
https://github.com/ComputerNerd/arduino-camera-tft/blob/master/config.h  change #define MT9D111 to #define ov7670
https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.c  update the function void errorD(uint8_t err) for your hardware for example send the string error over serial instead of displaying it on the lcd screen or you can just remove that function. Also remove the code that hflips the image. That is specific to the tft screen I am using if you are not sending it to the seeedstudio v1 lcd screen you don't want the image hfliped.
https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.h can be used as is but must be used if you use twicam.c
https://github.com/ComputerNerd/arduino-camera-tft/blob/master/captureimage.c Here is an example of how to capture an image there are many different functions for different resolutions. change PINE&32 to where ever your VSYNC pin is also change PINE&16 to where ever the PCLK output is also change the code that sends the data to the tft screen to were ever you are sending it. Once you have adapted those files to your system you can call the function setRes(); and use the defines in config.h for example setRes(qvga); sets the resolution to 320x240. When calling initCam() You also have a choice of 3 different register presets (0 1 and 2). I would recommend doing initCam(0); that seems to work best. Also you have setColor() I would recommend yuv422 for qvga and qqvga by calling it with setColor(yuv422);. For vga I would recomend bayer call it with setColor(bayerRGB). rgb565 is very low quality only use it if you are sending to a tft screen that uses rgb565 data.



Ok, I'm going to spend some time making sure my register setup is correct. I saw a few tutorials that didn't seem to bother with the defaults (such as this http://embeddedprogrammer.blogspot.com/2012/07/hacking-ov7670-camera-module-sccb-cheat.html ), which is why I didn't spend too much time on it before.

Here is the code I'm using to capture very small chunks from the camera (small enough to fit in arduino SRAM, so ~4 QCIF lines at a time).

Code: [Select]

void captureChunk(unsigned long wait, unsigned long chunk, uint8_t *pixels) {
 unsigned int n = 0;
 while(!(PIND & 8)) {} // Wait for VSYNC high
 while(PIND & 8) {} // Wait for VSYNC low

 while(wait--) {
   while(!(PIND & 4)) {};
   while(PIND & 4) {};
 while(chunk--) {
   while(!(PIND & 4)) {};
   pixels[n++] = (uint8_t)((PINC & 0x0F) | (PIND & 0xF0));
   while(PIND & 4) {};
//.... write to serial

I'll look through that, thanks for the link. Is there any particular reason to use custom twi functions instead of the built in Wire library? I'm able to read and write registers using that at the moment. Also, would you happen to have a link for a newer version of the datasheet? I'm using this one right now: http://www.eleparts.co.kr/data/design/product_file/Board/OV7670_CMOS.pdf


^^^ I made my own twi functions because I am not using the arduion ide. I don't like the arduion ide. Note that I am not forcing you to avoid using the arduino ide. Most likely the code that I posted will work just fine with the arduino ide. Here is a newer version of the datasheet
Also looking at your code using an unsigned long is bad. The avr is an 8bit processor but it does have some 16bit math support. Try to use the typedefs from stdint.h
for example uint16_t is a 16bit unsigned variable. In C an int could be either 16bit or 32bit depending on the compiler. int16_t will always be 16bit so that is better to use.
What I do is have two loops one that reads a line and another that tells how many lines to read.


Jul 17, 2013, 07:09 pm Last Edit: Jul 17, 2013, 07:42 pm by technonewb Reason: 1
Hello Mr_arduino, drkblog, and sampullman!

I am working on a project for one of my university proffesors and I am ran into a problem with the OV7670 camera. I have been trying to read some registers on the module but without luck. It appears that all three of you are able to use the Wire library but I had no luck with it.

When I try using the Wire commands, the endTransmission returns 2 meaning the camera could not be addressed properly.
Code: [Select]
 Wire.beginTransmission(sensor_addr >> 1);
 Wire.write(0x01 & 0x00FF);    

Also, the following code (which sampullman provided) returns the address of the register instead of the actual value stored inside the register:
Code: [Select]
#include <Wire.h>

uint8_t sensor_addr = 0x42;

void setup(){

void loop(){
  uint8_t* dat;
  readReg8(0x01, dat);

/* Write 2 byte value regDat to the camera register addressed by regID */
byte writeReg(int regID, int regDat) {
    Wire.beginTransmission(sensor_addr >> 1);
    Wire.write(regID & 0x00FF);   
    Wire.write(regDat & 0x00FF);   
    byte result = Wire.endTransmission();
    return result;

/* Read a 2 byte value from the camera addressed at regID, and store it at
* memory location pointed to by regDat. Return 1 on success, 0 on failure. */
byte readReg8(uint8_t regID, uint8_t* regDat) {
    Wire.beginTransmission(sensor_addr >> 1);
    Wire.write(regID & 0x00FF);   
    Wire.requestFrom((sensor_addr >> 1),1);
    if(Wire.available()) {
        *regDat = Wire.read();
        return 1;
    } else {
        return 0;

Could you please give me a hand?


Actully my latest code does not use the wire library see https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.c or if you feel the need to use the Wire library my very old code uses it see http://pastebin.com/1nnRc5qL
Also the ov7670 is picky about which pullup resitors you use. I found that 4.7k and 10k work but 1k and 2.2k do NOT work. And make sure that you are using the pullup resistor to 3.3v and if you use the Wire library you must edit twi.c which is located in (arduino ide folder)/libraries/Wire/Utility
And remove these lines:
Code: [Select]

  // activate internal pullups for twi.
  digitalWrite(SDA, 1);
  digitalWrite(SCL, 1);

By not doing that you could damage the ov7670 although when I first got the ov7670 I made the mistake of not removing those lines and nothing happened however your millage may vary. After removing those lines be sure to recompile your program.


Jul 18, 2013, 04:40 pm Last Edit: Jul 18, 2013, 05:27 pm by giantsfan3 Reason: 1
@Mr_Arduino, Terrific effort by you on this code, as well as answering people's questions! I see you are also adding support for the MT9D111. I'm definitely going to try the Omnivision module with this code.

Here is a suggestion: Perhaps you could take a few minutes and turn this into a standard structured Arduino-importable library (along with an example usage sketch of .INO filetype).
Along with that, you could make a few lines of tutorial out of your build including the hardware connections, and put it on the first post of the thread, so that others can reproduce your setup (there will also be fewer code-troubleshooting questions that way).

Also, here's a cool video by someone in Japan who made a TFT-camera out of it (this is where I first learned about the OV7670):
Not sure how they got this kind of almost real-time video from it using just the Atmega:

Actully my latest code does not use the wire library see https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.c or if you feel the need to use the Wire library my very old code uses it see http://pastebin.com/1nnRc5qL


^^^ About creating an *.ino file Everyone has different needs I like to keep my files organized so that if someone has trouble with something for example communicating with the camera I can point them to the right file and they don't have to look through lots of code to find what they need. I try to keep the filename related to what the functions in it do see https://github.com/ComputerNerd/arduino-camera-tft  Also I don't use the arduino ide anymore. I have deleted it a long time ago and never looked back(I know I can always re-download it but I don't ever want to use it again) My code should just be copy pastable into the arduino ide. It is just standard C. I do have older code that does use the arduino ide you can find that on the first page. I think I did already explain the hardware connections in the first few posts or do you mean make a video? Also what that person from Japan did was have the arduino configure the ov7670 but instead of plugging the video signals into the arduino they plugged it into the tft screen. What I had to do for my tft project was read the data with the arduino and send it to the tft screen or send it external ram. Speaking of which I now recommend the fifo version version over the non-fifo version. I would have done it with my tft screen but it needs to be configured with the arduino uno as well. The tft they have just needs to be powered on and it starts working. A disadvantage of directly plugging in the ov7670 into the tft screen is that you can't have a menu that allows you to configure the camera. My program includes a menu to configure the ov7670.



I'm not sure if you posted all of your code, but you need to add something like this after the Wire.begin() call in order to set up TWI communication so that it works with the OV7670:
Code: [Select]

 TWSR &= ~3; // Disable TWI prescaler
 TWBR = 72; // CLOCK / (16 + 2*TWBR*Prescaler)

This should set up the wire library to transmit at ~100Khz.

Other than that, it's important to follow Mr_arduino's advice for disabling the internal pull up resistors for twi. You need to add your own (4.7Kohm or 10k should work like he said) to pull up to 3.3v instead of 5v.

I still haven't pulled a reasonable image off the module, but hopefully with some external spi ram coming in today and switching from QCIF to QQVGA I'll have better luck.


I have the same values here that sampullman posted. https://github.com/ComputerNerd/arduino-camera-tft/blob/master/main.c
Also if you are using my register read and write code you don't want to use Wire.begin() if you are using the wire library you don't need to use the code that sampullman posted (I think).


I am sorry for the double post but I would like add that if you have a question about the ov7670 please don't PM me post it in this topic instead that way everyone will benefit.


Hi guys!

I'm new in Arduino and electronics but with 10 years of PHP programing experience. Not long ago I bought Arduino UNO with different modules and started to play with it as a hobby.

Unfortunately, I bought OV7670 camera without FIFO and now try to get an image to SD card. Furthermore, my camera module has only 8*2 pins (I think without RESET and PWDN pins. Also there are no marks of pins so I'm not sure from where I have to start counting pins.)
Here is my cam - http://dx.com/p/ov7670-30fps-vga-camera-module-for-arduino-blue-147415

It was not easy to find this thread in order to get some information how to connect the camera. But even read all 6 pages of your discussions I don't realize finally how to get the image to SD.

What I have now is:
1) Arduino UNO
2) my OV7670 camera module
3) SD card module (I know how it have to be connected to Arduino. No problems with it)
4) some miscellaneous resistors, wires, prototype board
5) using Arduino IDE

That is all.

I would like to ask someone for your help/suggestions which parts I have to buy additionally in order to save image to SD.
Also, I would like to propose to create straightforward instructions with circuit schema, some TODOs list, list of necessary parts or video how to catch image from OV7670 module by Arduino UNO and save to SD card. I can create this report as soon as I will finish with my little project.

Is there any who can spend some time for me to help with it? Please send me PM. I think it will be better to help me privately and I will create an detailed report after that in order to share knowledge with other.

Thanks, Victor


Well it appears that we just need to figure out which pin is what then you should be up and running. I looked up their website and did not find the pinout http://www.lctech-inc.com/Hardware/Detail.aspx?id=7c378661-0fd6-475e-8b63-a874aa6eb4df I guess you are going to have to email them asking for the pinout http://www.lctech-inc.com/About.aspx

Go Up