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...
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...
Description | Name | OV7670 pin | mbed pin |
---|---|---|---|
VCC | +V | 1 | p40 |
Ground | GND | 2 | p1 |
SCCB CLK | SCL | 3 | p27 |
SCCB Data | SDA | 4 | p28 |
Vertical synchronization | VSYNC | 5 | p21 |
Line synchronization | HREF | 6 | p22 |
FIFO Write Enable | WEN | 7 | p20 |
XCK | XCK | 8 | nc |
FIFO read address reset | RRST | 9 | p23 |
FIFO chip enable | OE | 10 | p24 |
FIFO read clock | RCLK | 11 | p25 |
Ground | GND | 12 | p1 |
FIFO output data | D0 | 13 | p12 |
FIFO output data | D1 | 14 | p13 |
FIFO output data | D2 | 15 | p14 |
FIFO output data | D3 | 16 | p15 |
FIFO output data | D4 | 17 | p16 |
FIFO output data | D5 | 18 | p17 |
FIFO output data | D6 | 19 | p18 |
FIFO output data | D7 | 20 | p19 |
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.
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...
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
10 comments on OV7670 Camera:
Please log in to post comments.
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!