OV7670 Camera

The problem

I have been using the uCam from 4D systems to capture images and do a bit of image processing. The problem is that it is painfully slow at reading the images in - max baud rate of 1228800 bps. This means that it was taking around 0.4 seconds just to read a small 160*120 image into the mbed.

Unfortunately I could not find a quicker camera anywhere. Until that is I read the notebook page written by fuyuno sakura which introduces the OV7670.

The solution

The Ov7670 is a camera chip originally for mobile phones made by OmniVision. The version suggested by fuyuno sakura includes a buffer to buffer the image data and speed up data transfer. It is (or should be) quicker than the uCam because the data is transferred by a byte wide parallel port.

OK enough talk, put your money where your mouth is and buy one...

Where to get one?

I found one on ebay here that was pretty cheap (around £20), and ordered one. A few weeks later it got here. It comes with a 20-way header and I decided to use some ribbon cable to connect to the header. While probably not the best picture in the world the camera and cable can be seen below...

640

So the next thing to do is to connect it up to the mbed and try to get a picture from it.

Connections

There are quite a few connections to be made - 19 in total! I'm not sure that all of them are required at the minute but I'll connect them all up and see how I get on.

Looking at fuyuno sakura's hello world program I think the connection I need are as follows...

DescriptionNameOV7670 pinmbed pin
VCC+V1p40
GroundGND2p1
SCCB CLKSCL3p27
SCCB DataSDA4p28
Vertical synchronizationVSYNC5p21
Line synchronizationHREF6p22
FIFO Write EnableWEN7p20
XCKXCK8nc
FIFO read address resetRRST9p23
FIFO chip enableOE10p24
FIFO read clockRCLK11p25
GroundGND12p1
FIFO output dataD013p12
FIFO output dataD114p13
FIFO output dataD215p14
FIFO output dataD316p15
FIFO output dataD417p16
FIFO output dataD518p17
FIFO output dataD619p18
FIFO output dataD720p19

So I connect the camera up (what a mess with all those wires!) and compile and run the hello world program. Nothing. What could be wrong?!?

I soon realise that I forgot to put the pull-up resistor on the I2C SCL pin. After I put this resistor in (I have a 10k resistor laying around, a bit big but it should do the trick?) the program works and I get info from the camera printed to the screen.

To start with this is all 0s, but then I remove the lens cap and point it at something bright and then I get different values. So far so good...

What next?

I want to check that the output from the camera is OK. So I need to display the image somehow. Fuyuno sakura used a LCD screen to show an image - I don't have that exact one but I do have a SPI TFT screen (the cookbook page is here) so I'll mod the code and use that.

I change the code to display the pixel on the screen after it's read in from the camera. I know this is a slow way of doing it but I just want to check that it works at the minute. The program is shown below.

Import programOV7670_Testing

A program that records images from the OV7670 camera and displays them on a SPI TFT display. Working at 15fps

When run the screen does show something like a blurry picture but only just! I figured that the focus needs adjusting. So I twiddle it around a bit and take several pictures until I get it reasonably good. A photo of the screen is shown below.

640

So it works! Good.

I'm not blown away by the image quality but it is only 12-bit colour and 160*120 resolution and it's in strong artificial light, so I guess I can live with it for the time being. So the next thing to do is to try to speed things up and see if I can get to some kind of decent video speed (>15fps maybe?).

Video testing

Before I do any further testing I want to make a few changes to the code. First I wanted to improve the colour. RGB444 seems a bit of a waste as it still takes up 2 bytes of data and had reduced colour depth when compared to RGB565. Also the TFT screen I'm using requires RGB565 so I would have to take precious time to convert it. Secondly instead of reading in data and displaying it straight away I want to buffer it in the mbed memory and then display it onto the screen in one go. This will allow me to accurately measure how long it takes to capture and display separately and should speed things up as I will be able to display it as a bitmap (which has a speedy method already written). So I make these changes to the code and test the outcome.

I'm actually really pleased with the result. The video looks quite fluid (so the frame rate must be good?) and the colours look better with the improved RGB output from the camera.

When it come to timing the capture and display the results show that it takes around 125 ms to capture the image from the camera and a further 30 ms to display it on the screen. This is surprising as I thought the fps would be higher than 6 when I saw the video. But I have a few things up my sleeve to make things quicker.

Speeding it up

Referring back to Fuyuno sakura's notebook page I see that he has changed the BusIn constructor to the quicker PortIn in his latest code. This had the result of improving the capture time for him and hopefully for me as well (but it does mean a few wiring mods). The other thing I think I might be able to do is to dedicate a pin for the rclk line that acts as a trigger to read a byte in. This is toggling up and down like mad and I think I can speed it up by poking the mbed registers directly or by using Igor's FastIO class.

Before we go any further lets have a look at what we are doing right now. The code I am using is just basically running the ReadOneByte() method as quickly as possible. The code for this is shown below...

// Data Read
    int ReadOneByte(void)
    {
        int result;
        rclk = 1;
        result = data;
        rclk = 0;
        return result;
    }

So the rclk pin goes high to start the read, the data is then read, the pin goes high again and the data is returned. When looked at on a scope the trace looks like this...

640

So it can be seen that the process of reading in one byte takes 3.1us. As a sanity check there are 38400 bytes to read in giving a total time of 119ms which is pretty close to the measured time of 125ms. So we can say that this read cycle is contributing to the vast majority of the total capture time of the camera. Furthermore the toggling of the rclk pin is taking around 100ns while the reading of the data is taking 30X longer than that! So it's pretty easy to see where to target!

Using PortIn

One good way to speed things up will be to use PortIn. It is said on the fourm that this is quicker but not really by how much. Anyway the first thing to do id to rewire the camera and rewrite the code...

After this is done initial performance look awesome the scope is showing the time that rclk is high has reduced by about 95% down to an impressive 175ns! The bad news is that the picture, while distinguishably, has its colours all wrong appearing mainly blue. This is because I forgot to bit shift the PortIn data down and organise it correctly! Doh. When this is fixed I'm getting capture times of around 16ms.

Bringing it together

The next problem that I find is that there appears to be big gaps in the data. Upon a bit of further investigation it appears that the camera has a recovery time between capturing images. This is no big deal as I will re-jig the mbed code to use this dead time to display the image. Bringing it all together I also have to add in a horz flip and display the images from the memory banks in the reverse order (for some reason the camera reads the image in right to left!?!).

When this is all done I find that I achieve a quite respectable 15fps for the video. I'm pretty pleased with this think I will call it a day here. The final program is published below.

Import programOV7670_Testing

A program that records images from the OV7670 camera and displays them on a SPI TFT display. Working at 15fps


Report

7 comments on OV7670 Camera:

23 May 2012

Martin, Thank you very much for taking the time to write the OV7670 notebook page! I'm starting to work with some OV cameras now and this will certainly help me a lot!

I owe you a beer!

28 Sep 2013

Can anybody tell whether input of XCLK in ov7670 is square or sinusoidal wave in nature???

Waiting for your answers eagerly !!!!!!!!!!!!

30 Sep 2013

shubham garg wrote:

Can anybody tell whether input of XCLK in ov7670 is square or sinusoidal wave in nature???

Waiting for your answers eagerly !!!!!!!!!!!!

The XCK input is not connect, so it doesn't matter in this instance. However if you were to connect it the input would almost certainly use voltages <0.8V as logic 0 and those >2V as logic 1 so it would accept either square wave or sine wave inputs.

Martin

11 Mar 2014

Hi

When i have test with ov7670 camera without AL422 FIFO, The output is something wrong work. The strange is what i have color bar register set to ov7670 camera then the camera's output image is corrupt. The output image is seem like that test pattern color bar mixed with current view in camera. When i have moving camera viewpoint, the ov7670 camera test pattern color bar output image is activated on outside. like this/media/uploads/b49651/afa.jpg

By the way, when i have stuff up ov7670's camera lens, then the ov7670 camera test pattern color bar output image is good. like this /media/uploads/b49651/afa2.jpg

I don't understand why this happen ?

here's register setting..(also this is from yours)

write_i2c(0x12,0x80) ; RESET CAMERA Sleep(200);

write_i2c(REG_CLKRC,0x80); write_i2c(REG_COM11,0x0A) ; write_i2c(REG_TSLB,0x04); write_i2c(REG_COM7,(0x04| 0x02) ) ; write_i2c(REG_RGB444, 0x02); write_i2c(REG_COM15, 0xd0); write_i2c(REG_HSTART,0x16) ; write_i2c(REG_HSTOP,0x04) ; write_i2c(REG_HREF,0x24) ; write_i2c(REG_VSTART,0x02) ; write_i2c(REG_VSTOP,0x7a) ; write_i2c(REG_VREF,0x0a) ; write_i2c(REG_COM10,0x02) ; write_i2c(REG_COM10,0x00) ; write_i2c(REG_COM3, 0x04); write_i2c(REG_COM14, 0x1a); write_i2c(0x72, 0x22); write_i2c(0x73, 0xf2);

COLOR SETTING write_i2c(0x4f,0x80); write_i2c(0x50,0x80); write_i2c(0x51,0x00); write_i2c(0x52,0x22); write_i2c(0x53,0x5e); write_i2c(0x54,0x80); write_i2c(0x56,0x40); write_i2c(0x58,0x9e); write_i2c(0x59,0x88); write_i2c(0x5a,0x88); write_i2c(0x5b,0x44); write_i2c(0x5c,0x67); write_i2c(0x5d,0x49); write_i2c(0x5e,0x0e); write_i2c(0x69,0x00); write_i2c(0x6a,0x40); write_i2c(0x6b,0x0a); write_i2c(0x6c,0x0a); write_i2c(0x6d,0x55); write_i2c(0x6e,0x11); write_i2c(0x6f,0x9f);

write_i2c(0xb0,0x84);

02 Apr 2014

I could not be in your program. It was possible to compile the program. But it is impossible to make an image. Wiring was also referring to the site here. What causes this? Please tell me.

02 Apr 2014

Hi,

Lee, you will need the camera with the AL422 for this code to work.

Gifutech, I can say with certainty that this set-up and code worked for me when I wrote it 2 years ago. It is possible that the manufacturer has updated the firmware on the camera meaning my set-up no longer works, or the latest mbed build doesn't work with my code. Can you check that you are using the LPC1768 mbed (M3) and double check the wiring and that you are using the camera with teh AL422. Failing that try to revert back to the old mbed build.

Hope this helps Martin

03 Apr 2014

Thank you. I try to trial and error the camera to move.

Please login to post comments.