Project 2 – LCD TFT Screen + Camera Module (OV7670)

Brief: 

“Undertake a 5 week project of your choosing in the themes covered in this module: Arduino, Physical Computing or Interaction Design. This project should explore the capabilities of physical computing beyond that taught in the tutorials.”

Idea:

An image below shows a quick diagram of my proposed components and how I envisioned they would combine together to make my product.

Project Sketch

Bullet Points:

  • These servos would be connected to a pan/tilt bracket.
  • Mounted to the bracket head would be the camera module – OV7670.
  • A LCD TFT Display would be showing a live feed from the camera.

The project was inspired by many security systems, and how they work.

CCTV: Closed Circuit Television. This is the use of video camera to transmit a signal to a specific place, on a limited set of monitors. It differs from broadcast television in that the signal is not openly transmitted.”

I purchased a camera module from online and then went about gathering all information I found relevant on it:

OV7670 Camer Module:

I took many days to look online and in books available to me to find out information on the module. This information would then allow me to use it in my project.

  • “The OV7670 camera module is an inexpensive image sensor and DSP (Digital Signal Processing – This is the mathematical manipulation of an information signal to modify or improve it in some way.
  • It can operate at a max 30fps (frames per second) and 640x 480 (“VGA”) resolution, which is equivalent to 0.3 Megapixels.
  • (VGA stands for Video graphics Array. It refers specifically to the display hardware.
  • The captured image can be configured via the Serial Camera Control Bus (SCCB). This is a serial-working 3-wire bus system, comparable to the I2C Bus. About the SCCB bus, which was developed by OmniVision, camera sensors and its features such as coloursaturation, brightness , the contrast can be controlled, the white level, exposure time and other parameters. From the Configuration view, it is a master-slave configuration in which one or several slaves , these are the CCD or CMOS sensors are controlled by a SCCB master.”

I then got a diagram that showed the pins available on the module:

Screen Shot 2015-04-14 at 20.53.16

I took time to find and source data about the camera off the Internet, this information was worked through to better my understanding of the module and how it reads and uses data:

Structure Of An Image:

“Before going into the signalling, it’s necessary to understand how video and images are represented in digital format.

A video is a succession of frames, a frame is a still image taken at an instant of time. A frame is compromised of lines, and a line is compromised of pixels. A pixel is the smallest part of a digital image, and it looks like a coloured dot.

Screen Shot 2015-04-14 at 20.58.30

For example, the image above has 5 lines, and each line has 5 pixels. This means the image has a resolution of 5×5 pixels. This image is monochrome, there are also color image. This color can be encoded in various formats.”

RGB:

“Is a fact that any color can be decomposed in red, green and blue light at different intensities. This approach is known as the RGB color model. Using this model, each pixel must be stored as three intensities of these red, green and blue lights.

RGB_illumination

The most common format is RGB888, in this format each pixel is stored in 24 bits, the red, green and blue channels are stored in 8 bits each. This means that the intensity of each light can go from 0 to 255, where 0 is the absence of light, and 255 is the maximum intensity.

The formats used by the OV7670 are the RGB565, RGB555 and RGB444. The difference with the RGB888 format, is the number of bits assigned to each channel. For example, in the RGB565 format, the red channel is stored as 5 bits, the green channel as 6 bits and the blue channel as 5 bits. These formats take less memory when stored but in exchange sacrifice the number of colors available.”

More research into colours and pixels was done to get full understanding of what was happening.

OV7670 Signalling:

“The OV7670 sends the data in a parallel synchronous format. First of all, to get any data out of the OV7670, is necessary to supply a clock signal on the XCLK pin.

After a clock signal has been applied to the XCLK pin, the OV7670 will start driving its VSYNC, HREF and D0-D7 pins. Let’s take a look at these signals.

href

First thing to notice, the D0-D7 must be sampled at the rising edge of the PCLK signal. Number two, D0-D7 must be sampled only when HREF is high. Also, the rising edge of HREF signals the start of a line, and the falling edge of HREF signals the end of the line.”

I carried of the research into the OV7670 camera.

While doing this I purchased an LCD TFT Display.

2.2″ 18-bit color TFT LCD display with microSD card breakout – ILI9340

Specifications:

  • “2” diagonal LCD TFT display
  • 320×240 resolution, up to 18-bit (262,144) color
  • ILI9340 (datasheet) controller with built in pixel-addressable video RAM buffer
  • Display datasheet
  • 4 wire SPI digital interface – this display talks in ‘8-bit’ SPI check the Arduino library source for how to communicate
  • Built-in microSD slot – uses 2 more digital lines
  • 5V compatible! Use with 3.3V or 5V logic
  • Onboard 3.3V @ 150mA LDO regulator
  • 4 white LED backlight, transistor connected so you can PWM dim the backlight
  • 1″ spaced header for easy breadboarding
  • Max Dimensions: 40.63mm / 1.59″ x 66.35mm / 2.61″ x 6.05mm / 0.23″
  • LCD Dimensions: 55.23mm / 2.17″ x 40mm / 1.57″ x 2.46mm / 0.09″
  • Weight: 18.43g

Current draw is based mostly on the backlight: with full on backlight, current draw is approx 100mA”

1480-00

I felt that as the learning from initial research into components worked so well in my last project, I will do it again for these components.

I research and understood what a LCD TFT display was:

“TFT stands for ‘Thin Film Transistor’ and describes the control elements that actively control the individual pixels. For this reason, one speaks of so-called ‘active matrix TFTs’. How are images produced? The basic principle is quite simple: a panel with many pixels is used whereby each pixel can emit any color. To this purpose, a back light is used which is normally comprised of a number of flourescent tubes. In order to light a single pixel, all that needs to be done is for a small ‘door’ or ‘shutter’ to open to let the light pass through. The technology that makes this possible is of course more complicated and involved than the simple explanation above. LCD (Liquid Crystal Display) stands for monitors that are based on liquid crystals. Liquid crystals can change their molecular structure and therefore allow varying levels of light to pass through them (or they can block the light). Two polarizer filters, color filters and two alignment layers determine exactly how much light is allowed to pass and which colors are created. The layers are positioned between the two glass panels. A specific voltage is applied to the alignment layer, creating an electric field – which then aligns the liquid crystals. Each dot on the screen (pixel) therefore requires three components, one for red, green and blue – just as for the tubes within cathode ray tube devices.”

After spending a lot of time researching my components I felt I knew enough to try and make the components work!

11160284_10152924421064608_1567564890_n

11156920_10152924421249608_727453044_n

I was able to get test colours up onto the screen! I will now try to keep working at the camera module.

I have had many problems with the OV7670 camera module..

I found It very hard to work with the OV7670 camera module as the one I bought was basic, had little documentation, no example code, and didn’t had FIFO imbedded.

FIFO: FIFO is an acronym for First In, First Out, a method for organising and manipulating a data buffer, where the oldest (first) entry, or ‘head’ of the queue, is processed first.

Link: The link provided below is a discussion I set up on a website called Element14.com. I created this discussion as i was trying to find out information regarding my camera, to help me incorporate it in my project. It was the first thing I did when getting the camera as help me find out as much information as possible.

http://www.element14.com/community/thread/42369/l/trying-to-use-a-camera-module-to-show-footage-to-a-lcd-tft-screen

Update: I slowly ran out of time trying to get my camera module to work with the components I have available to me. A lot of information online was not well documented and often didn’t contain all of the components that were used.

The most documented forum on the OV7670 camera module was this one:

http://forum.arduino.cc/index.php?topic=159557.0

However, like I said before, the information is hard to read, and very confusing. The posts don’t flow and critical information is not given.

To conclude my research and investigations so far: I have done exstensive research into the area and my components, however I believe, to proceed with this project I would need to at least buy a OV7670 camera module with FIFO. This would then enable to me get some sample code from the internet and progress with my aim.

Trying to get something working:

I went back to working with my LCD Display, and decided I would try and create a circuit whereby the user clicking the push button would change a bitmap image on the screen.

This would involve me using the microSD card slot that is behind the LCD Display.

A well documented instrucables page was looked at when trying to do this:

http://www.instructables.com/id/Your-Image-on-an-Arduino-TFT-LCD-Screen-Guide/

I learnt quickly from this small tutorial and then went onto looking at Adafruits guide:

https://learn.adafruit.com/1-8-tft-display/displaying-bitmaps

However, my components once again decided to bring me bad luck! The microSD card slot didn’t recognise my  SD card, I understood the process of formatting a card to FAT32, as explained here in this detailed blog:

http://www.ehow.com/how_4923639_format-sd-card-fat.html

Display Working!:

Code:

#include “SPI.h”
#include “Adafruit_GFX.h”
#include “Adafruit_ILI9340.h”

#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

#define _sclk 13
#define _miso 12
#define _mosi 11
#define _cs 10
#define _dc 9
#define _rst 8
Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst);

void setup() {
Serial.begin(9600);
while (!Serial);

Serial.println(“Adafruit 2.2\” SPI TFT Test!”); 

tft.begin();

Serial.println(F(“Benchmark Time (microseconds)”));
Serial.print(F(“Screen fill “));
Serial.println(testFillScreen());
delay(500);

Serial.print(F(“Text “));
Serial.println(testText());
delay(3000);

Serial.print(F(“Lines “));
Serial.println(testLines(ILI9340_CYAN));
delay(500);

Serial.print(F(“Horiz/Vert Lines “));
Serial.println(testFastLines(ILI9340_RED, ILI9340_BLUE));
delay(500);

Serial.print(F(“Rectangles (outline) “));
Serial.println(testRects(ILI9340_GREEN));
delay(500);

Serial.print(F(“Rectangles (filled) “));
Serial.println(testFilledRects(ILI9340_YELLOW, ILI9340_MAGENTA));
delay(500);

Serial.print(F(“Circles (filled) “));
Serial.println(testFilledCircles(10, ILI9340_MAGENTA));

Serial.print(F(“Circles (outline) “));
Serial.println(testCircles(10, ILI9340_WHITE));
delay(500);

Serial.print(F(“Triangles (outline) “));
Serial.println(testTriangles());
delay(500);

Serial.print(F(“Triangles (filled) “));
Serial.println(testFilledTriangles());
delay(500);

Serial.print(F(“Rounded rects (outline) “));
Serial.println(testRoundRects());
delay(500);

Serial.print(F(“Rounded rects (filled) “));
Serial.println(testFilledRoundRects());
delay(500);

Serial.println(F(“Done!”));
}

void loop(void) {
for(uint8_t rotation=0; rotation<4; rotation++) {
tft.setRotation(rotation);
testText();
delay(2000);
}
}
unsigned long testFillScreen() {
unsigned long start = micros();
tft.fillScreen(ILI9340_BLACK);
tft.fillScreen(ILI9340_RED);
tft.fillScreen(ILI9340_GREEN);
tft.fillScreen(ILI9340_BLUE);
tft.fillScreen(ILI9340_BLACK);
return micros() – start;
}

unsigned long testText() {
tft.fillScreen(ILI9340_BLACK);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(ILI9340_WHITE); tft.setTextSize(1);
tft.println(“Hello World!”);
tft.setTextColor(ILI9340_YELLOW); tft.setTextSize(2);
tft.println(00000);
tft.setTextColor(ILI9340_RED); tft.setTextSize(3);

tft.println();
tft.setTextColor(ILI9340_GREEN);
tft.setTextSize(4);
tft.println(“Nate “);
tft.setTextSize(4);
tft.println(“Crosby”);
tft.setTextSize(2);
tft.println(“Physical Computing”);
tft.println(“PDT Second Year”);
return micros() – start;
}

unsigned long testLines(uint16_t color) {
unsigned long start, t;
int x1, y1, x2, y2,
w = tft.width(),
h = tft.height();

tft.fillScreen(ILI9340_BLACK);

x1 = y1 = 0;
y2 = h – 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w – 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t = micros() – start; // fillScreen doesn’t count against timing

tft.fillScreen(ILI9340_BLACK);

x1 = w – 1;
y1 = 0;
y2 = h – 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() – start;

tft.fillScreen(ILI9340_BLACK);

x1 = 0;
y1 = h – 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w – 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() – start;

tft.fillScreen(ILI9340_BLACK);

x1 = w – 1;
y1 = h – 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

return micros() – start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height();

tft.fillScreen(ILI9340_BLACK);
start = micros();
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

return micros() – start;
}

unsigned long testRects(uint16_t color) {
unsigned long start;
int n, i, i2,
cx = tft.width() / 2,
cy = tft.height() / 2;

tft.fillScreen(ILI9340_BLACK);
n = min(tft.width(), tft.height());
start = micros();
for(i=2; i<n; i+=6) {
i2 = i / 2;
tft.drawRect(cx-i2, cy-i2, i, i, color);
}

return micros() – start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
unsigned long start, t = 0;
int n, i, i2,
cx = tft.width() / 2 – 1,
cy = tft.height() / 2 – 1;

tft.fillScreen(ILI9340_BLACK);
n = min(tft.width(), tft.height());
for(i=n; i>0; i-=6) {
i2 = i / 2;
start = micros();
tft.fillRect(cx-i2, cy-i2, i, i, color1);
t += micros() – start;
// Outlines are not included in timing results
tft.drawRect(cx-i2, cy-i2, i, i, color2);
}

return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

tft.fillScreen(ILI9340_BLACK);
start = micros();
for(x=radius; x<w; x+=r2) {
for(y=radius; y<h; y+=r2) {
tft.fillCircle(x, y, radius, color);
}
}

return micros() – start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, r2 = radius * 2,
w = tft.width() + radius,
h = tft.height() + radius;

// Screen is not cleared for this one — this is
// intentional and does not affect the reported time.
start = micros();
for(x=0; x<w; x+=r2) {
for(y=0; y<h; y+=r2) {
tft.drawCircle(x, y, radius, color);
}
}

return micros() – start;
}

unsigned long testTriangles() {
unsigned long start;
int n, i, cx = tft.width() / 2 – 1,
cy = tft.height() / 2 – 1;

tft.fillScreen(ILI9340_BLACK);
n = min(cx, cy);
start = micros();
for(i=0; i<n; i+=5) {
tft.drawTriangle(
cx , cy – i, // peak
cx – i, cy + i, // bottom left
cx + i, cy + i, // bottom right
tft.Color565(0, 0, i));
}

return micros() – start;
}

unsigned long testFilledTriangles() {
unsigned long start, t = 0;
int i, cx = tft.width() / 2 – 1,
cy = tft.height() / 2 – 1;

tft.fillScreen(ILI9340_BLACK);
start = micros();
for(i=min(cx,cy); i>10; i-=5) {
start = micros();
tft.fillTriangle(cx, cy – i, cx – i, cy + i, cx + i, cy + i,
tft.Color565(0, i, i));
t += micros() – start;
tft.drawTriangle(cx, cy – i, cx – i, cy + i, cx + i, cy + i,
tft.Color565(i, i, 0));
}

return t;
}

unsigned long testRoundRects() {
unsigned long start;
int w, i, i2,
cx = tft.width() / 2 – 1,
cy = tft.height() / 2 – 1;

tft.fillScreen(ILI9340_BLACK);
w = min(tft.width(), tft.height());
start = micros();
for(i=0; i<w; i+=6) {
i2 = i / 2;
tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.Color565(i, 0, 0));
}

return micros() – start;
}

unsigned long testFilledRoundRects() {
unsigned long start;
int i, i2,
cx = tft.width() / 2 – 1,
cy = tft.height() / 2 – 1;

tft.fillScreen(ILI9340_BLACK);
start = micros();
for(i=min(tft.width(), tft.height()); i>20; i-=6) {
i2 = i / 2;
tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.Color565(0, i, 0));
}

return micros() – start;
}

First Video of trial: 

The screen wasn’t wired up correctly, as seen in this quick video

Images of LCD Display working:

11092732_10152924559254608_781799551_n11149222_10152924559169608_1245892299_n11139937_10152924559129608_1877359318_n

What I plan to carry on doing:

I plan to keep looking into the possibilities of the OV7670 camera and if im able to use it.

I will find the solution to the SD card slot and then have a go at putting bitmaps onto the LCD Display, and then make a button press that would allow me to click through photos.

A major lesson learnt!:

Something that I have learnt swell as everything else documented in this post.. is that if you are going to buy a component online.. Don’t buy cheaply from a site that doesn’t contain all relevant documentation!

I hope you’ve enjoyed reading and have learnt along the way!

Nate.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s