Go Down

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


I set the divider to 4 see this code    wrReg(0x11,4);//using pre-scaler for divider Also what you can do to verify communication is increment the divider and wait awhile and increment again in a loop  and see if the OUTPUT PCLK changes on an oscilopsoce. Also you MUST have this register
Code: [Select]

wrReg(0x15,32);//pclk does not toggle on HBLANK COM10 vsync falling

That may another reason why you are getting invalid data. If you don't have it just use all registers from my sample code would be best.


Ok, I have been working and I see some advances now. Yet I'm not done.

I've incremented the prescaler and I realized there is a point (as I incremente PCLK frequency) where I start missing bytes. So I'm using the slower PCLK possible now. I have got a 23LC1024 chip and removed the SD card. My test program reads 50 lines of 640 from the sensor and puts the in the chip. Then dumps it in base64 to the PC through the USB. I'm setting the sensor to output a color bar pattern.

Here is my YUV output for that image's portion. And what I see when I convert it using ffmpeg

Code: [Select]
$ ./ffmpeg -f rawvideo -s 640*50 -pix_fmt yuvj422p -i frame0.yuv -f image2 -vcodec png img.png

I think I may be getting valid data from the sensor, and my problem could be in the ffmpeg conversion. But I'm not sure how to check that.


Jun 17, 2013, 05:51 pm Last Edit: Jun 17, 2013, 07:04 pm by Mr_arduino Reason: 1
Good job the only thing is that you have the sensor configured for raw bayer data. I attached the image I got.
Here is the source code to the program that converts the image it does both yuv422 and raw bayer data and saves it to a png file. https://github.com/ComputerNerd/RawCamera-data-converter/blob/master/main.c
To compile it simply type
Code: [Select]

gcc -Wall -Wextra -lm -lpng -o yuv main.c

As you may have noticed you need libpng installed.
The only thing is that the file name must be called F(x).YUV replace (x) with a number this was because I made it for time lapses originally  and need to may pictures at once. If you don't specify which number x is when running the program it will start from 0 and count up until a file is not found note that if you have F0.YUV and F2.YUV it will stop at F0.YUV as F1.YUV does not exist so in this case if you wanted to convert F2.YUV you would need to use the -n x argument so in this case do ./yuv -n 2 to convert it. Also speaking of missing a byte glitch I found out that sometimes at the beginning of capture a byte would be missed I fixed this by waiting for PCLK to go low read the pixel then wait for it to go high and then loop. I previously had it backwards.


Wow... thank you.

I thought I was configuring the sensor for YUV output. After reading your reply I went to check that. I think I'm misreading the documentation or the document is wrong. Because I can't manage to change the output.

What I'm doing now:
Code: [Select]

  // Max prescaler divider
  ovcam.toggle(REG_DBLV, NONE, DBLV_PLL_BYPASS);

  // No PCLK during HBLANK
  ovcam.toggle(REG_COM10, NONE, COM10_PCLK_NO_TOGGLE);

  // Set up camera
  ovcam.write(REG_COM7, 0x00);  // YUV
  ovcam.write(REG_COM15, 0xC0);  // Set normal rgb with Full range
  ovcam.toggle(REG_ABLC1, NONE, ABLC_ENABLE); // Auto black level

  ovcam.write(REG_COM13, 0x88);
  ovcam.write(REG_TSLB, 0x05);

The problem is no matter what I put in COM7, COM13 and TSLB. I can't manage to change to YUV. I have a PDF dated "Version 1.3, April 5, 2006" but I see some registers do not act according to the configuration. Do you know where is the last document for this sensor?

Anyway, I guess I can live with  RAW Bayer data by now.

What is the clock frequency you are sending to the module?
What is the max PCLK frequency you are able to read from Ardunino UNO or Mega?
Is you conversion program discarding color information? Or is it me doing something wrong?

By the way: I just noticed I had a byte in zero at the start. I fixed it waiting for the high state of the HREF signal, before starting to read the line. But then, as I change from bar pattern to the image, I start getting zeroes again. :/

Thank you very much!


Here is a picture taken in three stages of 640x100 pixels:


Jun 18, 2013, 04:05 am Last Edit: Jun 18, 2013, 04:12 am by Mr_arduino Reason: 1
Ok I think you were configuring the output for yuv however here is what I use for yuv also I am having the same problem with raw bayer data it lacks color. Yuv is much more colorful Here is what I use for yuv422. Also the documentation for the ov7670 is very bad don't blame yourself. Although here is a newer version 1.4 that may help abit http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20datasheet%28V1.4%29.pdf
If you noticed in the changelog of the 1.4 from 1.3 they changed the TSLB and COM13 documentation.
Code: [Select]

wrReg(0xb0,0x84);//Undocumented but writing this fixes colors I do not know why
wrReg(REG_COM7, 0x00);           // YUV
wrReg(REG_COM15, 0xC0);          //Full range
wrReg(REG_TSLB,0x04);                // 0D = UYVY  04 = YUYV    
wrReg(REG_COM13,0xC8);               // connect to REG_TSLB


I keep getting the RAW data. I will keep trying tomorrow morning (it's 11:40PM here). Thank you again.


Also did you look at the linux driver it has a complete register configuration which has parts based on official registers provided by omnivison http://dev.openaos.org/browser/trunk/buildroot/gen7/linux/drivers/media/video/ov7670.c
Also at the bottom of the page click download as plain text to copy paste without the line numbers. And with my program are you telling it to yuv422 conversion try passing the argument '-c y' without the quotes.


I'm going to check that link with the registers.

I tried your program with "-c y" and "-c d". I only get a reasonable image with D (debayer). But I don't like having something like this sensor, and not be able to configure it correctly.

As a mater of fact, RAW bayer could be the best choice for my project. I don't need color information and I see bayer format is one byte per pixel, which takes half space and time.

Have you tried the FIFO version of this module? I'm going to buy one, because I will save a lot of space if the RAM is on the sensor itself.


There are several advantages of the fifo version however it is the same exact sensor the ov7670 so you will still have the same register issues.Here are some advantages of the fifo version you control when pixels are read out and you have enough ram to read the entire pixel at once. What I would do is just use the linux driver registers copy paste the entire large struct
before the large struct add
Code: [Select]

struct regval_list {
uint8_t reg_num;
uint8_t value;

After that replace
Code: [Select]

static struct regval_list ov7670_default_regs[] = {

Code: [Select]

const struct regval_list ov7670_default_regs[] PROGMEM = {

Also make sure you #include <avr/pgmspace.h>
and use this function to write the registers
Code: [Select]

void wrSensorRegs8_8(const struct regval_list reglist[])
uint8_t reg_addr,reg_val;
const struct regval_list *next = reglist;
while ((reg_addr != 0xff) | (reg_val != 0xff)){
reg_addr = pgm_read_byte(&next->reg_num);
reg_val = pgm_read_byte(&next->value);
//wrReg(reg_addr, reg_val);

After writing all those registers configure PCLK and make sure the PCLK does not toggle during HBLANK.

Then in the file that you downloaded (the linux driver) look for
Code: [Select]

static struct regval_list ov7670_fmt_yuv422[] = {

And adapt it to your code
Also if you want change
Code: [Select]

{ REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */

Code: [Select]

{ REG_COM9, 0x6A }, /* 128x gain ceiling; 0x8 is reserved bit */

Note that it does not mean gain will always be 128x it just means it can go up there if needs to


I copied the configuration from the driver, pretty much in the way you suggested me. But I see voltage levels in the signaling change. And that messes up with my electrical interface, so the Arduino can't read the signals. I didn't connect the sensor to the arduino because I was afraid I could damage the sensor and it takes 25 days to arrive from Hong Kong. So I used a bidirectional 3.3V to 5V interface using FET. I made an article, it's in Spanish but you will be able to see the circuit and some waveforms. And there is a link to the application note in english too: http://blog.drk.com.ar/2013/interfaz-logica-bidireccional-entre-5v-y-3-3v

I guess I could make it work spending some time in it. But I have to go on with other parts of this project. I'm going to work in other stuff as I wait for the FIFO version I bought yesterday, to arrive. Then I will have to build the circuit again, and I could give it another try.

Do you have any document/information about the interface with the FIFO memory?

I hope that memory is going to let me read the bytes at any given speed. Because timing with this sensor is a pain.


Jun 20, 2013, 03:59 am Last Edit: Jun 20, 2013, 04:23 am by Mr_arduino Reason: 1
Sorry I forgot to mention that it changes CLCK speed. I have uploaded the registers I use here
They are pretty much the ones from the linux driver with some slight changes that may help what you described.
Note that init_cam() takes one parameter uint8_t useBayer what this means is if you pass 1 to it then it will set the camera to use raw bayer data Note that when useing bayer after this function add a 200 millosecond delay and rewrite the clock value (register 0x11).pass 0 to make it use something other than bayer data.  You can use setColor() to pick what you want. SetRes() sets what resolution you want. SetRes() changes the clock divider speed (register 0x11). You may need to change that.
Also for setRes() and setColor() you will some of the #defines here https://github.com/ComputerNerd/arduino-camera-tft/blob/master/config.h
or you could just add
Code: [Select]

#define vga 0
#define qvga 1
#define qqvga 2
#define yuv422 0
#define rgb565 1
#define bayerRGB 2

to your code.
Also here is documentation on the fifo version http://wiki.beyondlogic.org/index.php/OV7670_Camera_Module_with_AL422_FIFO_Theory_of_Operation



The default configuration was changing register 0x6B (DBLV) which has control over the PLL afecting the PCLK output. Which was causing all the problem with the clock. Now it seems to be working. And the output format has clearly changed. But now I can't convert the image using neither "-c d" nor "-c y" flags. Maybe I'm misreading the second byte. According to the datasheet, each byte is to be read during the high stage of PCLK. Which is what I am doing, as far as I know.

I'm attaching the frame read from the sensor (Just 640x200) and the PNG I get.


Update. I was missing a fix, in the reading logic... yet it isn't done...


Sorry for the repeated posting. But there are great news...  it's working now.

I'm getting just 640x200 portion of the frame for the sake of speed in the tests :)


Go Up