OV7670 with both arduino uno and now mega

I have made a library in order to save directly in bmp the picture in the SD CARD.

bmp.h

#ifndef bmp_h
#define bmp_h

#include "Arduino.h"

class Bmp
{
public:
 Bmp();
 void init(unsigned int px, unsigned int py);
 
 char bmpFileHeader[14];
 char bmpInfoHeader[40];
 unsigned int rowSize;        // How many bytes in the row (used to create padding)
 unsigned int fileSize;       // Headers (54 bytes) + pixel data
 int pad;                     // Max paddin needed will be 3 zeros
};

extern Bmp bmp;
#endif

bmp.cpp

#include "bmp.h"

Bmp::Bmp() {
  bmpFileHeader = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
  bmpInfoHeader = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
  }
  
void Bmp::init(unsigned int px, unsigned int py){
  rowSize = 4 * ((3*px + 3)/4);     
  fileSize = 54 + py*rowSize;
  
  pad = rowSize-3*px;         //Number of zeros needed;
  
  bmpFileHeader[ 2] = (byte)(fileSize      );
  bmpFileHeader[ 3] = (byte)(fileSize >>  8);
  bmpFileHeader[ 4] = (byte)(fileSize >> 16);
  bmpFileHeader[ 5] = (byte)(fileSize >> 24);

  bmpInfoHeader[ 4] = (byte)(       px      );
  bmpInfoHeader[ 5] = (byte)(       px >>  8);
  bmpInfoHeader[ 6] = (byte)(       px >> 16);
  bmpInfoHeader[ 7] = (byte)(       px >> 24);
  bmpInfoHeader[ 8] = (byte)(       py      );
  bmpInfoHeader[ 9] = (byte)(       py >>  8);
  bmpInfoHeader[10] = (byte)(       py >> 16);
  bmpInfoHeader[11] = (byte)(       py >> 24);
}

Bmp bmp;

Then for instance, if working with rgb444 would be:

if (!sd.begin(CHIP_SELECT, SPI_HALF_SPEED)) sd.initErrorHalt();
  if (!myFile.open(fileName, O_WRITE | O_CREAT )) 
    sd.errorHalt("opening file for write failed");
  Serial.print("Writing to ");
  Serial.print(fileName);
  Serial.print("... ");
  
  bmp.init(COLS,ROWS);
  myFile.write(bmp.bmpFileHeader, sizeof(bmp.bmpFileHeader));    // Write file header
  myFile.write(bmp.bmpInfoHeader, sizeof(bmp.bmpInfoHeader));    // Write info header
  
  byte tmp[COLS*3];                 //Row with RGB (3 bpp)
  byte padding[bmp.pad];
  for( int i=0; i< bmp.pad; i++)
    padding[i]=0;
  
  for (int y=0; y<ROWS; y++) {
     for (int x=0; x<(COLS); x++) {
       tmp[x*3+0] = (byte)((0x0F & buffer[2*y*COLS + 2*x])<<4);       // R
       tmp[x*3+1] = (byte)(0xF0 & buffer[2*y*COLS + 2*x+1]);          // G
       tmp[x*3+2] = (byte)((0x0F & buffer[2*y*COLS + 2*x+1]) <<4);    // B
     }
    myFile.write(tmp, sizeof(tmp));                // Write tmp data
    myFile.write(padding, sizeof(padding));        // Padding as needed
  }    
  Serial.println("Done");
  myFile.close();

I hope it would be helpfull for someone!

Nice!

Mr Arduino..can u please tell the pin configuration for the arduino mega 2560 ...

Hello, all & Mr_Arduino

I'm a Arduino beginner and i need some help understanding if my connections are correct.
I attached a fritzing file that shows my pin connections (FYI my ov7670 is a non buffer unit).

I'm sure my connections are wrong please advise
Thanks in advance

Sketch.fzz (21.1 KB)

Mr Arduino,,,, can u plz tel me , how the pin connection need to use in arduino mega?? i read ur post.. but i cant find out. and im new to arduino..can plz help?

Sorry everyone for my absence I have been busy lately real life can get in the way of fun things sometimes but now I am back and I hope that I will from now on keep up with this topic. What I will be doing is going trough this topic and addressing all unaddressed issues in separate post to keep things more organized. I will go in reverse order.

sakeear:
Mr Arduino,,,, can u plz tel me , how the pin connection need to use in arduino mega?? i read ur post.. but i cant find out. and im new to arduino..can plz help?

For the arduino mega you have some flexibility in the connections that you use. Just fine a port that has all pins broken out to the headers (D0-D7) this makes reading faster.
I will admit that your post is lacking in formality I would recommend you read How To Ask Questions The Smart Way and try again.
I would like more information before I am able to assist you.

lberezinski:
Hello, all & Mr_Arduino

I'm a Arduino beginner and i need some help understanding if my connections are correct.
I attached a fritzing file that shows my pin connections (FYI my ov7670 is a non buffer unit).

I'm sure my connections are wrong please advise
Thanks in advance

Thank you for the sketch. It made it much easier to identify what needs to be changed.
I have not of fritzing until now but I was able to correct your sketch. So with that said I have attached a corrected sketch. IMPORTANT NOTE: I could not find a part for the 74hca125 buffer that I used so I substituted it for the '4050 in the sketch. I have not tested a '4050 but it may work.

Sketch.fzz (30.8 KB)

aturcitu:
Before a long day working on my code and using the strucs with the regs....

taxan! But Your's photos have quite a lot quality that mine. I suppose that I can improve the focus and play with others registers?

Thanks ! :smiley: :smiley:

If you are concerned that you are getting lower quality compared to other people you really ought to post a 640x480 image. I cannot really tell with the 160x120 if that is normal or not. There is not enough resolution to analyze it.

aturcitu:
I have noticed one thing... My the order of the colors on my colorbar are incorrent. What could be the explanation?

I have attach the color bar raw data. YUV422 QCIF (176x144)

I got the colors to appear normal I had to use "Alternative" yuv422 conversion with my program you can run it as

./convert -f Cbar.RAW -w 174 -H 144  -c yalt

And you get the right colors
The source to my program is located at GitHub - ComputerNerd/RawCamera-data-converter: This program was made to convert raw data from the ov7670 to a png file. It may also work with other cameras.
The reason you are getting the wrong colors is because the first byte is swapped because a register was not set. The yuv422 alternative mode Also from what I have noticed it seems that yuv422 is higher quality than rgb565.

Cbar.RAW.png

drkblog:
Great!

Mr_arduino posted a github link to his converter in the first message in this thread (from YUV/BAYER to PNG). I use that program. Of course, you have to compile and run that over a PC with Linux or Cygwin.

Yes it is here GitHub - ComputerNerd/RawCamera-data-converter: This program was made to convert raw data from the ov7670 to a png file. It may also work with other cameras. one thing I was wondering should I release windows binaries with it or not? How many people here use windows here?

pgibbons66:
Finally a really amatuer question, when you pull up to A4 &A5 do you just add a 4.7k resistor between the line and the 3.3v pin on the arduino?

thanks in advance.

Yes you do in fact you won't be able to communicate with the ov7670 without the pull-up. Remember to disable the internal pull-up resistors if you use the arduino i2c library. I have instructions on the first page on how to do that.

xKoldFuzionx:

drkblog:
Don't forget to disable any Arduino buil-in pull up!

Out of sheer curiousity, what would happen if you didn't? If the built in are higher resistance, I could see that being a problem, but if they're lower, you could just use a lower PU?

I really know nothing about the pull-ups built into Arduino. I read about them once, but don't remember anything. Lol, I just found out what a PU resistor was yesterday.

The internal pull-ups are to 5v the ov7670 is made to handle only 3.3v.

Animat:
Hi, how to fix the image with the right edge?

You are missing data. It is important to keep your loop to read data as fast as possible.
Here is what I did arduino-camera-tft/captureimage.c at master · ComputerNerd/arduino-camera-tft · GitHub
Look at the function capImg(void)
it is designed to capture a 320x240 image with 2 bytes per pixel so 640x240 bytes of data
I will annotate what goes on

        cli();
        uint8_t w,ww;
        uint8_t h;
        w=160;//The reason this is 160 instead of 640 is because I have unrolled loop you will see later
        h=240;

Disable interrupts and set up variables notice that I use 8bit unsigned variables that is important.
Usually when coding on the PC using int is the fastest but that is not the same on the AVR it is an 8-bit processor.

        tft_setXY(0,0);
        CS_LOW;
        RS_HIGH;
        RD_HIGH;

This sets up the memory device in my case a tft screen later in the loop you will notice that when I write to the tft screen it automatically increments to the next pixel.
Here is how you initialize the 23LC1024 on the arduino uno and this code can also be used on arduino mega if and only if you edit the platform dependent functions.

	spiCSt();
	spiWrB(2);//sequental write mode
	spiWrB(0);//24 bit address
	spiWrB(0);
	spiWrB(0);

You will need these platform dependent functions

static inline void spiWrB(uint8_t dat){
	SPDR = dat;
	while(!(SPSR & (1<<SPIF))) {}// Wait for transmission complete
}
static inline void spiCSt(void){//selects the RAM chip and resets it
	//toggles spi CS used for resting sram
	PORTB|=(1<<2);//cs high
	PORTB&=~(1<<2);//cs low
}

Change the 2 and maybe PORTB to what pin is on that port. NOT PIN NUMBER ON ARDUINO.
You will also need to put this at the beginning of your program

spiCSt();
	spiWrB(1);
	spiWrB(64);//sequential mode

The next part of void capImg(void) is this

        DDRA=0xFF;

This sets the tft data pins to output the only reason that is there is because other parts of my code may change it to input
This code waits for the image to actually start

#ifdef MT9D111
                while (PINE&32){}//wait for low
                while (!(PINE&32)){}//wait for high
        #else
                while (!(PINE&32)){}//wait for high
                while (PINE&32){}//wait for low
        #endif

You can ignore from the #ifdef MT9D111 part to the #else and ignore the #endif that is so my program can be compile for either mt9d111 or ov7670 depending on what is defined.
The code (below) is the start of my loops

 while (h--){
                ww=w;
                while (ww--){

Notice how I am counting down instead of up it is faster to count down that it is to count up.
The next part of my code does 8 bytes per loop iteration
This:

                        WR_LOW;
                        while (PINE&16){}//wait for low
                        PORTA=PINC;
                        WR_HIGH;

Is repeated 8 times
Here is what you would do for SPI ram on the arduino mega (The above inner loop code was for the arduino mega with tft screen)

			while ((PIND&4)) {}//wait for low
			SPDR=(PINC&15)|(PIND&240);
			while (!(PIND&4)) {}//wait for high

I close the loop with

                }

        }
        CS_HIGH;
        sei();

This sets the tft's CS pin to high and re-enables interrupts.
Also your converter ignores the color information as I have told you before here are some of your images that you posted the raw data for converted with my converter.

2013.11.26_16.39.10.raw.png

Bayer_RAW_VGA.raw.png

Chocobot:
So far I'm thinking this:
The schematic, is this ok? http://i167.photobucket.com/albums/u157/cookiebal/OV7670ArduinoUno.jpg

The schematic looks good to me.

As for the code, I've been looking at ov7670 arduino uno example code - Pastebin.com , I'm not very familiar with the language so I don't really understand everything. But so far I'm thinking that I'd need to add this (from page 4, reply 57) somewhere at the start to get the clock working.

Try looking at GitHub - ComputerNerd/ov7670-simple: This is a simple sample code of the ov7670 on the arduino uno sends data over serial. I will warn you that it was the first code that I have ever written for the ov7670.

  DDRB|=(1<<3);//pin 11
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
  TCCR2A=(1<<COM2A0)|(1<<WGM21)|(1<<WGM20);//this also results in 67 but I wanted to clean up magic numbers
  TCCR2B=(1<<WGM22)|(1<<CS20);
  OCR2A=0;

Yes do add that at the beginning
The simple sample should make it easier for you to understand the operation of the ov7670.

drkblog:
Well. Having a sensor which outputs JPEG saves you the cost of processing the encoding. But, as far as I know, you won't get a frame free of compression from such a sensor. And if you have to process the image in the Arduino, you have to decode JPEG first. Which is why OV7670 is better in such cases.

The OV5642 can output raw data in addition to the jpeg compressed mode.

Mr_arduino:

drkblog:
Well. Having a sensor which outputs JPEG saves you the cost of processing the encoding. But, as far as I know, you won't get a frame free of compression from such a sensor. And if you have to process the image in the Arduino, you have to decode JPEG first. Which is why OV7670 is better in such cases.

The OV5642 can output raw data in addition to the jpeg compressed mode.

I was aware of that, but the main reasons I purchased it was the 5MP and the JPEG output. Just saves me the hassle of having a separate program convert the data. I'd much rather pull the card, put it in the PC and be able to read the data directly from the card, rather than have to start up another program and convert it all to view it. Plus, with MicroSD cards, it's easier to view the image in the field with a cellphone by just swapping out the card.

I just wish the coding and the documentation was easier for me to figure out. I'm really quite slow with understanding all of this and don't have the experience. I had been using a VC0706 until it just crapped out on me yesterday(I put it to sleep and now it won't respond). Now all the work I put into it is garbage and I'm stuck scrapping all the work I did and starting with something different. Wire confuses me, though I think I have a fairly decent grasp of it. The ov5642 just has so much more going on but is a lot less inexpensive so if I scrap a few, I'm not gonna be as pissed about it as with the other. The worst part was, I was litterally one step away from having the project completed.

I guess I'm just going to have to go back through all your code on the 7670 and see what I can figure out. I can't thank you enough for all the work you've done on these camera modules.

Mr_arduino:

aturcitu:
I have noticed one thing... My the order of the colors on my colorbar are incorrent. What could be the explanation?

I have attach the color bar raw data. YUV422 QCIF (176x144)

I got the colors to appear normal I had to use "Alternative" yuv422 conversion with my program you can run it as

./convert -f Cbar.RAW -w 174 -H 144  -c yalt

And you get the right colors
The source to my program is located at GitHub - ComputerNerd/RawCamera-data-converter: This program was made to convert raw data from the ov7670 to a png file. It may also work with other cameras.
The reason you are getting the wrong colors is because the first byte is swapped because a register was not set. The yuv422 alternative mode Also from what I have noticed it seems that yuv422 is higher quality than rgb565.

Yes I have noticed this, It seems that I am missing the first byte of every row, But I don't understand why, do you know with register could it be? It happens to me either in YUV or RGB.

PD: Here you can see the project I am working with ov7670 and Arduino DUE :
http://forum.arduino.cc/index.php?topic=206660.0

Thanks in advance

aturcitu I am not sure if you are actually missing bytes look at register 0x3A here is a quote from the datasheet

Bit[3]: Output sequence
(use with register
COM13
[1] (0x3D))
TSLB[3],
COM13
[1]):
00: Y U Y V
01: Y V Y U
10: U Y V Y
11: V Y U Y

Here is register another quote found at register 0x3D

Bit[0]: UV swap (use with register
TSLB
[3] (0x3A))
TSLB
[3], COM13[1]:
00: Y U Y V
01: Y V Y U
10: U Y V Y
11: V Y U Y

You see the ov7670 can output the color bytes in different orders.
Also your project is very cool I wish I could help you with PID but I have not experience with it.

xKoldFuzionx:
I just wish the coding and the documentation was easier for me to figure out. I'm really quite slow with understanding all of this and don't have the experience.

Don't feel bad it took me a long time to get the ov7670 to work most of this was my silly errors I was a beginner at one point. When I started working with the ov7670 I could not even communicate with it using i2c it would not work. I did not relize that for i2c (sccb) communication to work you needed to feed a clock to it. I remember getting it working and the colors I got out of the ov7670 were purple and green. I found out that there was some register that fixes this (it appears aturcitu is currently experiencing this issue) Yes it does affect rgb565 mode too. Working with these camera sensors have significantly advanced my skill both at a hardware level and a software level. I hope you keep going with your project seeing it finally work feels great and that is part of the reason why I made this topic so that other people interested in camera sensors can get to see their project work.

I had been using a VC0706 until it just crapped out on me yesterday(I put it to sleep and now it won't respond). Now all the work I put into it is garbage and I'm stuck scrapping all the work I did and starting with something different. Wire confuses me, though I think I have a fairly decent grasp of it.

What do you mean "Put it to sleep"? Maybe there is a way to fix it. I can't imagine software causing damage to the sensor unless you disable the internal regulator or something which is unlikely that you did.
The ov5642 just has so much more going on but is a lot less inexpensive so if I scrap a few, I'm not gonna be as pissed about it as with the other. The worst part was, I was litterally one step away from having the project completed.
[/quote]
Could you please tell us where you are getting ov5642 sensor modules for the cost lest than an ov7670 module the cheapest ov5642 module I could find was $25.99 on ebay. The ov7670 can be purchased for $5.99 on ebay and includes free shipping just like the ov5642. I would like an ov5642 module myself.

I guess I'm just going to have to go back through all your code on the 7670 and see what I can figure out. I can't thank you enough for all the work you've done on these camera modules.

Well the ov5642 is quite a bit different I am not sure if much of my code will help you with that unfortunately.