Pages: [1] 2 3 ... 20   Go Down
Author Topic: ov7670 with both arduino uno and now mega  (Read 42641 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Edit: I now recommend the fifo version over the non-fifo version.
If you have the fifo version lots of this is still relevant all except the external ram part.
The reason for using the fifo version is because of faster readout and you can capture a 640x480 images without breaking it up into pieces.
Also I have since figured out how to generate an 8mhz clock using PWM that way you don't have to set fuse bits you can read more about that in my later posts.
Using PWM to generate XCLK has several advantages including: You don't need a special programmer to set the fuse bits. You can change the output clock speed the fastest it goes is F_CPU/2 which results in 8mhz in the case of the arduino. Also I have since found out that bayer rgb is half the size of yuv422 which my old writing below recommends. Raw bayer appears to be about the same level of quality. I would recommend you use it instead of yuv422 I have posted new versions that use raw bayer data. Here is an FAQ of some questions that may come up:
Q: The arduino outputs a 5v clock but the arduino will only accept 3.3v what should I do
A: use a buffer of some sort it just needs to be fast enough to pass the 8mhz signal.
Q: Will the ov7670 accept twi/sccb/i2c (same thing different names) commands without the PCLK running
A: No
Q: Will I need to buffer any other pins besides the PCLK
A: No but be sure you have the i2c/twi/sccb lines pulled up to 3.3v instead of 5v or you risk damage to the ov7670
Also don't set any of the pins that go to the ov7670 as output.
Q: where can I get current registers and useful functions for the ov7670?
A: On my github page https://github.com/ComputerNerd/arduino-camera-tft
More specifically here is some stat-up registers here https://github.com/ComputerNerd/arduino-camera-tft/blob/master/ov7670_regs.h
And here are some useful functions here https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.c also don't forget the header file https://github.com/ComputerNerd/arduino-camera-tft/blob/master/twicam.h
And you will notice that I have vga qvga rgb565 yuv422 defined somewhere else that is here https://github.com/ComputerNerd/arduino-camera-tft/blob/master/config.h
Q: the code you posted runs on the arduino mega but I have an arduino uno what  can I do?
A; The functions that setup the camera will also work on the arduino uno and I have posted some code for the arduino uno see the pastebin links below
Q: The FAQ does not answer my question what should I do
A: try reading through this topic your question might be answered if not post a reply I'd rather that you not send a pm because someone else may have the same question that you do later on.
Here is the my old original post below kept for historical reasons:
I have recently been working with the ov7670 unfortunately I made the mistake of cheeping out and buying the cheaper one without the fifo. At first I though it would be a challenge to get this to work but it turns out not to be that hard at all. The problems: the arudino does not have enough ram and is slow additionally it runs on 5v when both the ov7670 and the sd card need 3.3v. The solutions. Break the image into smaller pieces and transfer the smaller pieces into spi ram in this case I have the 23LC1024 128kb of ram that means if I want a vga image 640*480*2 bytes per pixel. I must divide it into 5 equal parts. So I transfer part of the image and save that part into the sd card and do this for a total of 5 times each time skipping different regions and saving others. The sensor can output both rgb565 or yuv422 I found that yuv422 is better quality so I made a converter for that and you can get the source code here https://github.com/ComputerNerd/RawCamera-data-converter. Here is code for the capture program. http://pastebin.com/1nnRc5qL I used sdfatlib to write and based my code off of his fastlogger code. Note that by defining useLed using #define useLed will assume you have an led on pin 0 and a button on pin 1 to stop the capture hold down the button and wait for the led to blink very fast make sure that the button sinks the pin to grounnd. If you do not define useLed then it uses serial to start stop image send one letter to the arduino and it will  save 1 image you can send more for more images. Also Note that I found some registers online somewhere and I could not find documentation on those registers. The only ov7670 datasheet that I could find online does not explain all the registers it gives the name but the description is blank. If someone could explain with a reply or PM what these:
Code:
   wrReg(AWBC7,0x88);
    wrReg(AWBC8,0x88);
    wrReg(AWBC9,0x44);
    wrReg(AWBC10,0x67);
    wrReg(AWBC11,0x49);
    wrReg(AWBC12,0x0e);
wrReg(REG_GFIX,0x00);
//wrReg(GGAIN,0x40);
    wrReg(AWBCTR3,0x0a);
    wrReg(AWBCTR2,0x55);
    wrReg(AWBCTR1,0x11);
    wrReg(AWBCTR0,0x9f);
wrReg(0xb0,0x84);//not sure what this does
registers do that would be awesome.
To solve the 5v issue I use a buffer. To solve the fact that the arduino is slow I set the divider to 9 also I am getting the clock with the CLKOUT pin you will have to change your fuse settings for that. Also for twi communication the ov7670 is picky about what pullup resistor values you use I found 4.7k and 10k to work. I tried 1k and 2.2k and those do NOT work. You will need twi to write to the registers the image out is parallel. Here are some images taken with the ov7670.


Here is the arduino uno itself. Image is very large click here to view http://imageshack.com/a/img849/4632/zuvj.jpg
« Last Edit: January 19, 2014, 05:33:48 pm by Mr_arduino » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello, I would like to see your connection in detail. I want the camera to be used in image processing by arduino.

Thanks for answer and sorry for my English. Nice job.
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The connections are simple. Start by plugging in SIO_C to A5 and SIO_D to A4 since this is i2c/twi you must have a 4k7 resistor 10k also works. Make sure you have the resistor to pull up 3.3v not 5v. Also edit twi.c  in the arduino ide folder/libraries/Wire/utility search for these lines and comment them out or remove them
Code:
// activate internal pullups for twi.
  digitalWrite(SDA, 1);
  digitalWrite(SCL, 1);
This is to remove the internel pullup resistor by not removing these 2 lines you could cause damage to the sensor. Then plug d7 to digital pin 7 d6 to 6 d5 to 5 d4 to 4 d3 to A3 d2 to A2 d1 to A1 and d0 to A0 now plug in VSYNC to digital pin 3 and PCLK to pin 2. Now change the fuse bits to be exacly the same except enable the CLKOUT pin. This will output a clock run this through a buffer or level shifter to 3.3v if you do not get the 5v signal down to 3.3v it could damage the sensor. The sd card and spi ram is just standard spi wiring nothing special.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the answer, I will try.  smiley smiley
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I wish you the best of luck if anything does not work right just reply and I will help you.
Logged

Offline Offline
Edison Member
*
Karma: 27
Posts: 2033
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could you post a photo of your device sometime ?   I got one of these  and the connections were so tiny that
I could not see then with a magnifying glass  and certainly not actually connect anything to them.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I'm working on a project at university about computer vision and Arduino.
I'm trying to capture an image using Arduino Uno and OV7670 camera without FIFO. Other components like SD card, LCD, additional RAM, shields, etc. are unfortunately not available at this time (I've read some tutorials about this, but they were using special shields or some stuff I don't have or camera with FIFO...).
Is it possible to directly communicate with camera from Arduino and get some images? It doesn't have to be fast, the point is to get some results.

Since I'm just a beginner with Arduino, I'm a little bit confused about how to connect my camera to it, when I don't use RAM that was mentioned above. I really don't want to damage it...
Could you please describe it or provide some connection schema for a case like mine? Could you please also give me some advice how to change the code for the capture program?

Any help is appreciated.
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

michinyon I bought an ov7670 camera module that means some of the pins are routed to a 2.54mm pitch header I think you have bought just the sensor. I am busy right now I will take a picture soon.
Saren it is possible I will have to get back with you on this one though. I am busy right now and don't have any code written right now for using no ram. I do however have a program that is compiled with avr-gcc that sends the image to a frame grabber program that I wrote.
Here is the sender program it is in 3 files main.c ov7670.h ov7670.c
main.c:
http://pastebin.com/dF3pc23T
I will warn you that I made some changes to the code but forgot to change the comments like the captureImg function says it missed a byte but now it does not I posted it to paste bin before realising this.
ov7670.h
http://pastebin.com/CqYTwNqn
ov7670.c
http://pastebin.com/T1nN5Ni4
Here is the frame grabber source code
http://pastebin.com/dxMJhZTq
This one is only one file. If on Gnu/Linux you will need to install the development package of SDL or if gentoo just emerge sdl. If on windows get the development library from http://www.libsdl.org/download-1.2.php
Also I made an update to my program that captures an image to the sd card it nows saves raw bayer data.
http://pastebin.com/zV0ahzPv
The link is different than the previous code that I posted.
Here is a program to debayer/demosaic the data it is still in very beta needs work
It will also convert yuv422 to rgb (the old image to sd card program saved data in that format)
Code:
//to compile type gcc -Wall -Wextra -lm -lpng -o yuv main.c
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>
#include <zlib.h>
#include <sys/stat.h>
#define img_w 640
#define img_w_2 1280
#define img_h 480
#define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
#define C(Y) ( (Y) - 16  )
#define D(U) ( (U) - 128 )
#define E(V) ( (V) - 128 )
#define YUV2R(Y, U, V) CLIP(( 298 * C(Y)              + 409 * E(V) + 128) >> 8)
#define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8)
#define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U)              + 128) >> 8)
char buf[1024];
void showHelp()
{
puts("Yuv422 raw image data to png");
puts("-n x replace x with the image number you want to convert");
puts("-h shows this help file");
puts("-o x replace x with a real integer between 0 and 7 this sets the offset");
}
int savePNG(char * fileName,uint32_t width,uint32_t height,void * ptr)
{
//saves a 24bit png with rgb byte order
png_byte * dat=ptr;//convert to uint8_t
//png_byte **row_pointers = malloc(height*sizeof(png_byte));
//if (row_pointers==0)
// return 1;
FILE * fp=fopen(fileName,"wb");
if (fp==0)
return 1;
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)0,0,0);
if (!png_ptr)
return 1;
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
return 1;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return 1;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, width, height,8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);//must be called before other png_set_*() functions
//png_set_compression_level(png_ptr,Z_BEST_COMPRESSION);//since we are doing timelapses we may be dealing with many files it is good to keep disk space usage down
uint32_t y;
//for (y=0;y<height;y++)
// row_pointers[y]=&dat[(y*width*3)];//the rows are contiguous
png_set_user_limits(png_ptr, width, height);
png_write_info(png_ptr, info_ptr);
//puts("saving data 2");
//png_write_image(png_ptr, row_pointers);
for (y=0;y<height;y++)
png_write_row(png_ptr, &dat[(y*width*3)]);
//png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
//free(row_pointers);
fclose(fp);//done with file
return 0;//will return 0 on success non-zero in error
}
void yuv2rgb(uint8_t * yuvDat,uint8_t * out)
{
uint64_t xy;
for (xy=0;xy<(img_w/2)*img_h;xy++)
{
*out++=YUV2R(yuvDat[0],yuvDat[1],yuvDat[3]);
*out++=YUV2G(yuvDat[0],yuvDat[1],yuvDat[3]);
*out++=YUV2B(yuvDat[0],yuvDat[1],yuvDat[3]);
*out++=YUV2R(yuvDat[2],yuvDat[1],yuvDat[3]);
*out++=YUV2G(yuvDat[2],yuvDat[1],yuvDat[3]);
*out++=YUV2B(yuvDat[2],yuvDat[1],yuvDat[3]);
yuvDat+=4;
}
}
void deBayerN(uint8_t * in,uint8_t * out)
{
uint32_t x,y;
for (y=0;y<img_h;y+=2)
{
for (x=0;x<img_w;x+=2)
{
//this will do a 2x2 pixel rectangle
/*R G
 G B*/
out[(x*3)]=in[x];//copy red
out[(x*3)+1]=in[x+1];//green
out[(x*3)+2]=in[x+1+img_w];//blue

out[(x*3)+3]=in[x];//red
out[(x*3)+4]=in[x+1];//green
out[(x*3)+5]=in[x+1+img_w];//blue

out[((x+img_w)*3)]=in[x];//red
out[((x+img_w)*3)+1]=in[x+img_w];//green
out[((x+img_w)*3)+2]=in[x+1+img_w];//blue

out[((x+img_w)*3)+3]=in[x];//red
out[((x+img_w)*3)+4]=in[x+img_w];//green
out[((x+img_w)*3)+5]=in[x+img_w+1];//blue
}
out+=img_w*6;
in+=img_w*2;
}
}
void deBayerL (uint8_t * in,uint8_t * out)
{//this is an implementation of http://www.ipol.im/pub/art/2011/g_mhcd/
uint32_t x,y;
for (y=0;y<img_h;y+=2)
{
for (x=0;x<img_w;x+=2)
{
//this will do a 2x2 pixel rectangle
/* B Gb
  Gr R
*/
/*R G THIS IS WRONG BUT STANDARD The rows are reversed on omnivision sensors keep this in mind later just get alg working for now
 G B*/
//if (x>=2 && x<=img_w-2 && y>=2 && y<=img_h-2)//see if we are able to grab pixels from neighboors
//{
//printf("X %d Y %d x-img_w %d\n",x,y,x-img_w);
out[x*3]=in[x];//red just needs to be copied
//out[(x*3)+1]=((in[x]*4)+(in[x-1]*2)+(in[x+1]*2)+(*(in+x-img_w)*2)+(in[x+img_w]*2)-(in[x-2])-(in[x+2])-(*(in+x-img_w_2))-in[x+img_w_2])/8;//green at red locations
//out[(x*3)+2]=((in[x]*6)+(*(in+x-1-img_w)*2)+(*(in+x+1-img_w)*2)+(*(in+x-1+img_w)*2)+(in[x+1+img_w]*2)-(in[x-2]/3*2)-(in[x+2]/3*2)-(*(in+x-img_w_2)/3*2)-(in[x+img_w_2]/3*2))/8;//Blue at red

//out[(x*3)+4]=
out[(x*3)+4]=in[x+1];//copy green

out[((img_w+x)*3)+1]=in[x+img_w];//copy green

out[((img_w+x)*3)+5]=in[x+img_w+1];//copy blue
/*}
else//we are on the edge defualt to edge safe algorthim
{
out[(x*3)]=in[x];//copy red
out[(x*3)+1]=in[x+1];//green
out[(x*3)+2]=in[x+1+img_w];//blue

out[(x*3)+3]=in[x];//red
out[(x*3)+4]=in[x+1];//green
out[(x*3)+5]=in[x+1+img_w];//blue

out[((x+img_w)*3)]=in[x];//red
out[((x+img_w)*3)+1]=in[x+img_w];//green
out[((x+img_w)*3)+2]=in[x+1+img_w];//blue

out[((x+img_w)*3)+3]=in[x];//red
out[((x+img_w)*3)+4]=in[x+img_w];//green
out[((x+img_w)*3)+5]=in[x+img_w+1];//blue
}*/
}
out+=img_w*6;
in+=img_w*2;
}
}
uint8_t readImg(uint32_t num,uint8_t * dat)
{
sprintf(buf,"F%d.YUV",num);
FILE * myfile = fopen(buf,"rb");
if (myfile==0)
{
printf("Cannot open file %s\n",buf);
return 1;
}
fread(dat,2,img_w*img_h,myfile);
fclose(myfile);
return 0;
}
uint8_t processImg(uint8_t * in,uint8_t * out,uint32_t num,uint8_t alg,uint16_t offset)
{
if (readImg(num,in))
return 1;
uint32_t w,h;
switch (alg)
{
case 2:
deBayerL(in+offset,out);//linear
break;
case 1:
deBayerN(in+offset,out);//nearest neighboor low quality try to avoid using
break;
case 0:
yuv2rgb(in+offset,out);
break;
default:
puts("You must pick an algorithm to save the image as");
return 1;
}
sprintf(buf,"frame %d.png",num);
if (savePNG(buf,img_w,img_h,out))
{
return 1;
puts("Error while saving PNG");
}
return 0;
}
int main(int argc,char ** argv)
{
uint8_t useNum=0;
uint32_t useImg;
uint16_t offset=0;
uint8_t debayer=1;
if (argc>1)
{
//handle arguments
int arg;
for (arg=0;arg<argc;arg++)
{
if (strcmp(argv[arg],"-n") == 0)
{
arg++;
useImg=atoi(argv[arg]);
useNum=1;
continue;
}
if (strcmp(argv[arg],"-o") == 0)
{
arg++;
offset=atoi(argv[arg]);
if (offset>img_w)
{
printf("you must specify a number between 0 and %d for argument -o\n",img_w);
showHelp();
return 1;
}
continue;
}
if (strcmp(argv[arg],"-h") == 0)
{
showHelp();
continue;
}
}
}
uint8_t * Dat;//in case some of the file was not saved we use calloc instead of malloc to garentte that the unsaved pixels are set to 0
if (debayer!=0)
Dat = calloc(img_w*img_h+img_w,1);
else
Dat = calloc(img_w*img_h+img_w,2);
uint8_t * outImg = malloc(img_w*img_h*3);//all bytes in the array will be overwritten no need for calloc
if (useNum)
{
processImg(Dat,outImg,useImg,debayer,offset);
}
else
{
uint32_t imgC;
for (;;imgC++)
{
printf("Saving image %d\n",imgC);
if (processImg(Dat,outImg,imgC,debayer,offset))
return 1;
}
}
free(Dat);
free(outImg);
return 0;
}
« Last Edit: April 13, 2013, 09:05:33 pm by Mr_arduino » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I forget that. I bought the camera ov7670 fifo.
Sorry and thank you so much.
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I forget that. I bought the camera ov7670 fifo.
Sorry and thank you so much.
Smart choice the one with the fifo is much better I wish I would have bought it but I bought the one without the fifo.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mr_arduino: I didn't have much time lately, but now I'm going to try it. I have some questions about connection:
1. You mentioned that it's necessary to get the 5V signal down to 3.3V. Is it possible to do this without level shifter/buffer or do I have to get this stuff?
2. Are connections the same (as in one of your posts) even in my case (without RAM, etc)?

Thanks for your effort to help. I really appreciate it smiley
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The connections will be mostly the same but it could be abit different as I do not own the one with the fifo I am not sure but I think instead of PCLK you use RCLK and and RCLK is output you strobe that to get data. Check you this for more info about the fifo version http://wiki.beyondlogic.org/index.php/OV7670_Camera_Module_with_AL422_FIFO_Theory_of_Operation Also you could try a resistor divider but I have heard that they are too slow you may need a buffer/level-shiftier. Also this would not require the ram as you have the fifo.
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A recent discovery that I made is you can get an F_CPU/2 (8mhz in the arduino's case) clock output with pwm this removes the need to edit fuse bits. Note that this is for the arduino mega 2560 I switched to from the uno to the mega recently. This will work with the arduino uno also just change the timer number.
Code:
DDRL|=8;
 ASSR &= ~(_BV(EXCLK) | _BV(AS2));
 //generate 8mhz clock
TCCR5A =67;
TCCR5B=17;
Also change DDRL to proper port and pin or be lazy and replace with pinMode();
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 44
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There's a good page on generating clock signals at http://hekilledmywire.wordpress.com/2011/05/28/introduction-to-timers-tutorial-part-6/#more-57

I too have the question about level shifting; what sort of buffers are needed, would a 74HC245 do?
Logged

Offline Offline
Full Member
***
Karma: 6
Posts: 225
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the 74HC245 would work just fine also a unidirectional one would work too. Pretty much any buffer that is fast enough to handle a 16mhz signal and can accept 3.3v as a supply voltage which the 74HC245 can. You do not need to shift the d7-d0 as those are always output from the sensor and never input. Only the clock signal needs to go though the buffer as that is an input and the sd card if you are using it.  From twi just disable internal pullup resistors and have them to 3.3v instead of 5v. Also I think I may have forgot to mention that RESET needs to be tided to 3.3v and PWDN to ground or you could use more GPIO pins if you need to use the PWDN and RESET features although a reset can also be triggered by writing to a register so driving that pin with the arduino has little purpose.
Logged

Pages: [1] 2 3 ... 20   Go Up
Jump to: