Beginning Arduino Ov7670 Camera Development - Robert Chin PDF
Beginning Arduino Ov7670 Camera Development - Robert Chin PDF
Beginning Arduino Ov7670 Camera Development - Robert Chin PDF
Figure 1-
6. Comparison of CIF with VGA, QVGA, and QQVGA resolutions
YUV YUV is an image encoding method and is discussed in more detail later in this
book. The pixels that make up a digital image must be represented internally in an image
format and YUV is one of the available image formats used to represent these pixels. The
YUV format incorporates luminance or brightness values and color values.
YCbCr YCbCr is an image encoding method and is discussed in more detail later in
this book. The pixels that make up a digital image must be represented internally in an
image format and YCbCr is one of the available image formats used to represent these
pixels. In the YCbCr image format a pixel incorporates luminance or brightness values,
blue intensity values, and red intensity values.
RGB RGB is an image encoding method and is discussed in more detail later in this
book. The pixels that make up a digital image must be represented internally in an image
format and RGB is one of the available image formats used to represent these pixels. In
the RGB image format each pixel contains a red, green, and blue component. The red,
green, and blue components are added to get a final color. The red, green, and blue
components set at the highest setting add up to white light. The red, green, and blue
components set to the lowest setting represent the color black. See Figure 1-7.
Figure 1-7.
RGB image format
Raw Bayer RGB Raw Bayer RGB is an image format where each pixel consists of raw
sensor data of either red, green, or blue depending on the color filter at that pixel location.
Raw Bayer is the format the photo is initially captured in before further processing. Raw
Bayer is discussed more in depth later in this book.
Demosaicing Demosaicing is the process by which a raw bayer RGB image can be
transformed into a full color image.
Exposure Exposure is the amount of light per unit area and can be increased by
capturing a photo over a longer period of time or decreased by capturing a photo over a
shorter period of time. The end result is that the longer the exposure the brighter the
captured image will be. The shorter the exposure the darker the captured image will be.
AEC AEC stands for Automatic Exposure Control and means that the camera will
adjust the exposure setting according to certain parameters.
AGC AGC stands for Automatic Gain Control and controls the luminance or
brightness of the photo that is taken.
White Balancing White Balancing is the adjustment of the colors in an image generally
the colors red, green, and blue for correcting neutral colors such as gray or white so that
they appear grey or white in the photo.
AWB AWB stands for Automatic White Balancing which means that the camera will
automatically adjust the colors of the image so that neutral colors such as grey or white
will appear grey or white in the captured photo.
BLC BLC stands for Black Level Calibration which adjusts the level of black in the
image with the objective of matching true black (zero brightness) in the environment to
true black in the corresponding captured image.
ABLC ABLC stands for Automatic Black Level Calibration that automatically adjusts
the black level in the captured image according to certain parameters.
OV7670 Camera with AL422B FIFO Memory Overview
This section gives an in depth description of the ov7670 camera. First, the general
capabilities of the camera are summarized. Then each functional component of the camera
is described in detail. This is followed by a step by step description of how an image is
captured by the camera and then transferred to the Arduino.
This section discusses the individual components of the Omnivision ov7670 camera. Each
component is labeled with an alphabet enclosed in a circle. Each of these components is
then discussed in detail. See Figure 1-8 for the full camera functional block diagram.
Figure 1-8. OV7670 Camera Functional Block Diagram
A. Camera Lens
The ov7670 has a lens that can be adjusted by screwing it in or out to adjust the focus of
the image to be captured. Light first comes through this lens before hitting the cameras
image array. See Figure 1-9.
B. Image Array
The cameras image array captures the incoming image and is 656 pixels wide and 488
pixels high. See Figure 1-10.
Figure 1-10. Cameras Image Array
The image array is covered with color filters arranged in a blue-green/green-red pattern.
That is one row would contain color filters alternating between blue and green covering
the sensor pixel one row would contain color filters alternating between blue and green
covering the sensor pixel 11.
C. Analog Processing
The ov7670s analog processing includes exposure control, gain control, and black level
calibration control. Gain controls can be set to manual or automatic. The term gain refers
to the luminance or brightness of the image. Setting the gain to automatic tells the camera
to control the images brightness automatically without any other control inputs supplied
by the user. Black level calibration can be set to manual or automatic and adjusts the black
color in the captured image as close to the actual image as possible. The exposure control
can be set to manual or automatic. The (AEC) automatic exposure control methods used
can be average based or histogram based. (AEC) Automatic exposure control and (AGC)
automatic gain control share the same algorithms and are used together to adjust the
overall luminance or brightness of the image. See Figure 1-13.
D. Camera Registers
The registers in the ov7670 camera are memory cells that are 1 byte or 8 bits in length and
hold values that are used to control the cameras functions such as resolution, image
output format, exposure, gain, frame rate, etc. If you are new to digital design I discuss
bytes and bits later in this book so dont worry if you are unfamiliar with these terms. You
can set and read the values of these registers through the cameras SCCB interface using
the Arduino. See Figure 1-15.
E. SCCB Interface
This interface is used to read data from the cameras registers and to write data to the
cameras registers. The SCCB interface on the camera is compatible with the Arduinos
I2C interface and code used to activate and use the I2C interface will work with the
cameras SCCB interface without any modifications. There are two pins which are the
clock which is labeled the SIO_C and the data which is labeled SIO_D. The SIO_C is the
same as the SCL on the I2C interface and the SIO_D is the same as the SDA on the I2C
interface.
The SIO_C is connected to the Arduino UNO through analog pin 5 and is connected to the
Arduino MEGA through digital pin 21. The SIO_D is connected to the Arduino UNO
through analog pin 4 and connected to the Arduino MEGA through digital pin 20. See
Figure 1-16.
The test pattern generator is used to display a standard set of vertical colored bars that are
used to determine if the camera is working properly. Not only should a vertical group of
colored bars be displayed clearly but the colors must also be in the right order. We get into
more detail regarding the test pattern generator later in this book. See Figure 1-17.
The analog to digital converter converts the raw bayer image from the image array to a
digital format using a 10 bit converter. See Figure 1-18.
The 50/60 Hz auto detect can automatically detect the frequency of artificial light such as
florescent light used in an office or home. This feature can be used with the cameras band
filter features to remove any light banding that may occur in an image. See Figure 1-19.
Figure 1-19. 50/60 Hz Auto Detect
K. Image Scaler
The image scaler reduces the size of the VGA image (if desired) that is output by the
cameras digital signal processor. All other resolutions are produced by scaling down the
VGA image. See Figure 1-25.
M. Video Port
The image from the FIFO memory can be output through the cameras video port. The
video port is 1 byte or 8 bits in length. Thus, we will need to read the image data from the
cameras video is 1 byte or 8 bits in length. Thus, we will need to read the image data from
the cameras video 27.
This section gives a general overview of what steps occur when an image is captured,
processed and transferred to the Arduino using the Omnivision ov7670 digital camera. See
Figure 1-28.
Figure 1-28. Steps in taking a photo
A preliminary step before capturing the image is to set the camera resolution, set the
image output format, and set other image processing parameters that the user desires. This
is done by the Arduino using the ov7670 cameras SCCB interface to write the required
values to the cameras registers.
The image that is to be captured by the camera must first go through the cameras lens. It
is here that the focus can be adjusted by the user by screwing the lens clockwise or
counterclockwise to get a clear image.
The image array receives the incoming image after it goes through the cameras lens. Here
the cameras pixel cell sensors detect the red, green, and blue components of the incoming
light. These pixel cell sensors are arranged in a raw bayer image format of alternating
rows of bluegreen/green-red pattern.
Next, the analog image is sent through the analog to digital converter that converts the
image into its digital form of bytes consisting of 0s and 1s.
Next, the digitally processed image is sent to the image scaler where it is reduced in size
according to the values in the camera registers that control the size of the final image that
is output. Remember that all images are first captured in VGA resolution but can be scaled
down using the image scaler.
Step #7 FIFO
Then, the final scaled image is sent to the FIFO frame buffer memory which holds the
image so that it can be read and output to the Arduino.
Step #9 Arduino
Finally, the wires from the video port on the camera are connected to pins on the Arduino
designated as input pins. From there the image data is read in one byte at a time until the
entire image is processed. For example, the image can be saved to a SD card or
transmitted via bluetooth to an Android device to be displayed.
Summary
In this chapter I covered the Omnivision ov7670 camera. I started with a discussion of key
terms and concepts relating to digital cameras that were essential in understanding the rest
of the book. Then I went into a detailed discussion of the camera involving key functions
and then I discussed the steps an image went through when being captured, processed and
then sent from the camera to the Arduino.
Chapter 2
Microcontroller: ATmega2560
Operating Voltage: 5V
Input Voltage (recommended): 7-12V
Input Voltage (limits): 6-20V
Digital I/O Pins: 54 (of which 15 provide PWM output)
Analog Input Pins: 16
DC Current per I/O Pin: 40 mA
DC Current for 3.3V Pin: 50 mA
Flash Memory: 256 KB for storing code of which 8 KB used by the bootloader
SRAM: 8 KB
EEPROM: 4 KB
Clock Speed: 16 MHz
This section covers the functional components of the Arduino Mega 2560.
The Arduino Mega 2560 has a USB connector that is used to connect the Arduino to the
main computer development system via standard USB A male to B male cable so it can be
programmed and debugged. See Figure 2-5.
Figure 2-5. USB Connector
9V Battery Connector
The Arduino Mega 2560 has a 9 volt battery connector where you can attach a 9 volt
battery to power the Arduino. See Figure 2-6.
Reset Button
There is a reset button on the Arduino Mega 2560 where you can press the button down to
reset the board. This restarts the program contained in the Arduinos memory. See Figure
2-7. Figure 2-7. Reset Button
The Arduino Mega has many digital pins capable of simulating analog output through the
process of pulse width modulation. For example, an L.E.D. light generally has only two
modes which is on (full brightness) or off (no light emitted). However, with digital pulse
width modulation the L.E.D. light can appear to have a brightness in between on and off.
For instance, with PWM (Pulse Width Modulation) an L.E.D. can start from an off state
and slowly brighten until it is at its highest brightness level and then slowly dim until back
to the off state. I discuss pulse width modulation later in this book. The digital pins on the
Arduino Mega 2560 that support PWM are pins 2 through pin 13. These PWM capable
digital pins are circled in Figure 2-8.
Figure 2-8. Digital pulse width modulation
Communication
The communication section of the Arduino Mega 2560 contains pins for serial
communication between the Arduino and another device such as a bluetooth adapter or
your personal computer. The Tx0 and the Rx0 pins are connected to the USB port and
serve as communication from your Arduino to your computer through your USB cable.
The Serial Monitor that can be used for sending data to the Arduino and reading data from
the Arduino uses the Tx0 and Rx0 pins. Thus, you should not connect anything to these
pins if you want to use the Serial Monitor to debug your Arduino programs or to receive
user input. I will talk more about the Serial Monitor later in this book. In addition, the
Arduino Mega 2560 has three more sets of serial communication pins that are labeled
Tx1/Rx1, Tx2/Rx2, and Tx3/Rx3. See Figure 2-9.
Figure 2-9. Serial Communication
The ov7670 camera will communicate with the Arduino though the I2C interface. The I2C
interface consists of an SDA pin which is pin 20 and is used for data and an SCL pin
which is pin 21 and is used for clocking or driving the device or devices attached to the
I2C interface. The SDA and SCL pins are circled in Figure 2-10.
Digital Output/Input
The Arduino Mega 2560 has many more digital output/input pins then the Arduino Uno
which is a popular Arduino model for beginners with a limited number of digital and
analog output/input pins. The camera will need many digital pins. The sd card that will be
used to save the photos will also need digital pins. Pins 22 through 53 are digital pins on
the Arduino Mega 2560. Pins discussed earlier that are capable of PWM (Pulse Width
Modulation) are also capable of normal digital output/input. See Figure 2-11.
Analog Input
The Arduino Mega 2560 has 16 analog input pins that can read in a range of values
instead of just digital values of 0 or 1. The analog input pin uses a 10 bit analog to digital
converter to transform voltage input in the range of 0 volts to 5 volts into a number in the
range between 0 to 1023. See Figure 2-12.
Figure 2-12. Analog Input
Power
The Arduino Mega 2560 has outputs for 3.3 volts and 5 volts. One section that provides
power is located on the side of the Arduino. You can also provide your own power source
by connecting the positive terminal of the power source to the Vin pin and the ground of
the power source to the Arduinos ground. Make sure the voltage being supplied is within
the Arduino boards voltage range. See Figure 2-13.
Figure 2-13. 3.3 volt and 5 volt Power outputs and Vin voltage input
Another place on the Arduino Mega 2560 that provides power is on the side of the board
near the digital output pin 22 and pin 23 that provide 5 volt outputs. See Figure 2-14.
Ground
The ground connections on the Arduino Mega 2560 are shown circled in Figure 2-15. We
will explain more about the importance of ground connections later in this book.
Figure 2-15. Arduino Mega 2560 Ground Connections
Arduino Development System Requirements
Developing projects for the Arduino can be done on the Windows, Mac, and Linux
operating systems. The software needed to develop programs that run on the Arduino can
be downloaded from the main web site at:
http://www.arduino.cc/en/Main/Software
The following is a summary of the different types of Arduino IDE distributions that are
available for download. You will only need to download and install one of these files. The
file you choose will depend on the operating system your computer is using.
Windows
Windows Installer This is a .exe file that must be run to install the Arduino Integrated
Development Environment.
Windows ZIP file for non admin install This is a zip file that must be
uncompressed in order to install the Arduino Integrated Development
Environment. 7-zip is a free file compression and uncompression program available at
http://www.7-zip.org
Mac
Mac OS X 10.7 Lion or newer This is a zip file that must be uncompressed and
installed for users of the Mac operating system
Linux
Linux 32 bits Installation file for the Linux 32 bit operating system.
Linux 64 bits Installation file for the Linux 64 bit operating system.
The easiest and cheapest way to start Arduino development is probably through using the
Windows version on an older operating system such as Windows XP. In fact, the examples
in this book were created by using the Windows version of the Arduino IDE running on
Windows XP. There are in fact many sellers on Ebay where you can purchase a used
Windows XP computer for around $50-$100. So if you are starting from scratch and are
looking for a inexpensive development system for the Arduino then consider buying a
used Windows XP based computer. The only caution is that support for the Windows XP
has ended in the United States and some other parts of the world. In China Windows XP
may still be supported with software updates such as security patches.
Arduino Software IDE
As of this writing the latest Arduino IDE is version 1.6.3. This is the program that is used
to develop the program code that runs on and controls the Arduino. For example, in order
for you to have the Arduino control the lighting state of an L.E.D. (Light Emitting Diode)
you will need to write a computer program in C/C++ using the Arduino IDE. Then, you
will need to compile this program into a form that the Arduino is able to execute and then
transfer the final compiled program using the Arduino IDE. From there the program
automatically executes and controls the L.E.D. that is connected to the Arduino.
New versions of the IDE are compiled daily or hourly and are available for download.
Older versions of the IDE are also available for downloading at:
http://www.arduino.cc/en/Main/OldSoftwareReleases
In this section we will go over the key features of the Arduino Software IDE. The IDE you
are using may be slightly different then the version discussed in this section but the
general functions we cover here should still be the same. We wont go in depth into every
detail of the IDE since this book is meant as a quick start guide and not a reference
manual. We will cover the critical features of the Arduino IDE that you will need to get
started on the main camera project in this book. See Figure 2-16.
You can purchase an official Arduino Mega 2560 board from a distributor listed on
http://www.arduino.cc/en/Main/Buy or http://www.Arduino.org. The first web site is still
generally considered the main web site for Arduino. However, the second web site is run
by the people actually making Arduino boards. The split among the founders of the
Arduino mentioned earlier can be seen here in terms of who is designated as a distributor
of an official Arduino board.
A second option is to buy an unofficial Arduino Mega 2560 made by a seller not listed as
an official distributor by either arduino.cc or arduino.org. These boards are generally a
lot cheaper than an official Arduino board. However, the quality may vary widely
between manufacturers or even between production runs between the same manufacturer.
In terms of the USB cable that is used to connect the Arduino to your development
computer the official Arduino board generally does not come with a cable but many
unofficial boards come with short USB cables. Arduino compatible USB cables of a
longer length such as 6 foot or 10 foot can be bought on Amazon.com or Ebay.com. I
purchased the Mediabridge USB 2.0 - A Male to B Male Cable (10 Feet) - High-Speed
with Gold-Plated Connectors Black from Amazon.com for my unofficial Arduino
Mega 2560 and its seems to work well. Make sure you get the right kind of USB cable
with the right connectors on either end. The rectangular end of the USB cable kind of USB
cable with the right connectors on either end. The rectangular end of the USB cable 24.
Figure 2-24. Arduino USB
Cable
The Arduino IDE has versions that can run on the Windows, Mac, and Linux operating
systems. The Arduino IDE can be downloaded from:
http://www.arduino.cc/en/Main/Software
I recommend installing the Windows executable version if you have a windows based
computer. Follow the directions in the pop windows.
Note: The Arduino web site also contains links to instructions for installing the Arduino
IDE for Windows, Mac, and Linux on http://www.arduino.cc/en/Guide/HomePage. The
installation for Linux depends on the exact version of Linux being used.
26.
Figure 2-26. Verifying the
blink sketch
Before uploading the sketch to your Arduino make sure the type of Arduino under the
Tools>Board menu item is correct. In our case the board type should be set to be
Arduino Mega 2560 or Mega ADK. See Figure 2-27.
Figure 2-27.
Set Arduino type to Arduino Mega 2560
Next, make sure the serial port is set correctly to the one that is being used by your
Arduino. Generally Com1, and Com2 are reserved and the serial port that the Arduino will
be connected to is Com3 or higher. See Figure 2-28.
Comments
// - This is a single line comment that is used by the programmer to document the code.
These comments are not executed by the Arduino.
/* */ - These enclose a multi line comment that is used by the programmer to document
the code. These comments are not executed by the Arduino.
Data Types
void This return type is only applicable to functions and indicates that the function will
not return any value to the function caller. For example, the setup() function that is part of
the standard Arduino code framework has a return type of void.
void setup()
{
// Initialize the Arduino, camera, and SD card here
}
boolean A boolean variable can hold either the value of true or false and is 1 byte in
length. For example, in the following code the variable result is declared of type boolean
and is initialized to false.
boolean result = false;
char The char variable type can store character values and is 1 byte in length. The
following code declares that tempchar is of type char and is an array with 50 elements.
char tempchar[50];
unsigned char The unsigned char data type holds 1 byte of information in the range of
0 through 255.
byte The byte data type is the same as the unsigned char data type. The following code
declares a variable called data of type byte that is initialized to 0.
byte data = 0;
int The int data type holds a 2 byte number in the range of -32,768 to 32,767. The
following code declares a variable of type integer that holds the error status after writing
to the camera.
int result = OV7670WriteReg(COM7, COM7_VALUE_RESET );
unsigned int This data type is 2 bytes in length and holds a value from 0 to 65,535.
word - This data type is the same as the unsigned int type.
long This data type is 4 bytes in length and holds a value from 2,147,483,648 to
2,147,483,647.
unsigned long This data type is 4 bytes in length and holds a value between 0 to
4,294,967,295.
Float This is a floating point number that is 4 bytes in length and holds a value
between -3.4028235E+38 to 3.4028235E+38.
double - On the current Arduino implementation the double is the same as float with no
gain in precision.
String This is a class object that allows the user to easily manipulate groups of
characters. In the following code a new variable called Command of type String is
declared and initialized to the QQVGA resolution.
String Command = QQVGA;
array An array is a continuous collection of data that can be accessed by an index
number. Arrays are 0 based so that the first element in the array has an index of 0.
Common types of arrays are character arrays, and integer arrays. The following code
declares the variable Entries as an array of type String that contains 10 elements. The
function ProcessRawCommandElement() is then called with element number 2 in the
Entries array which is the third element in the array. Remember 0 is the first element in the
array.
String Entries[10];
boolean success = ProcessRawCommandElement(Entries[2]);
Constants
INPUT This is an Arduino pin configuration that sets the pin as an input pin that
allows you to easily read in the voltage value at that pin with respect to ground on the
Arduino. For example, the following code sets the pin VSYNC on the Arduino as an
INPUT pin which allows you to read in the voltage value of the pin to determine if a new
frame is being captured by the camera. The function pinMode() is an Arduino function
included in the built in library.
pinMode(VSYNC, INPUT);
OUTPUT This is an Arduino pin configuration that sets the pin as an output pin that
allows you to drive other electronics components such as an L.E.D. or to provide digital
input to other devices in terms of HIGH or LOW voltages. In the following code the pin
WEN is set to OUTPUT using the built in pinMode() function.
pinMode(WEN , OUTPUT);
HIGH (pin declared as INPUT) - If a pin on the Arduino is declared as an INPUT then
when the digitalRead() function is called to read the value at that pin then a HIGH value
would indicate a value of 3 volts or more at that pin.
HIGH (pin declared as OUTPUT) If a pin on the Arduino is declared as an OUTPUT
then when the pin is set to HIGH with the digitalWrite() function then the pins value is 5
volts.
LOW (pin declared as INPUT)- If a pin on the Arduino is declared as an INPUT then
when the digitalRead() function is called to read the value at that pin then a LOW value
would indicate a value of 2 volts or less.
LOW (pin declared as OUTPUT) - If a pin on the Arduino is declared as an OUTPUT
then when the digitalWrite() function is called to set the pin to LOW the voltage value at
that pin would be set to 0 volts.
true true is defined as any non zero number such as 1, -1, 200, 5, etc.
false false is defined as 0.
The #include statement brings in code from outside files and includes them into your
Arduino sketch. Generally a header or .h file is included which allows access to the
functions and classes inside that file.
For example, in our image capture program we include the Wire.h file which lets us use
the Wire library. The Wire library has functions to initialize, to read data from and to write
data to a device connected to the I2C interface. We need the Wire library to use the
ov7670 camera that uses the I2C bus.
#include <Wire.h>
Also, we need to include the SD card reader library in order to use the SD card
reader/writer. #include <SD.h>
The Semicolon
Each statement in C/C++ needs to end in a semicolon. For example, when declaring and
initializing a variable you will need a semicolon.
const int chipSelect = 48;
When you use a library that you included with the #include statement you will need a
semicolon at the end when you call a function.
Wire.begin();
Curly Braces
The curly braces such as { and } specify blocks of code and must match in pairs. That is,
for every opening brace { there must be a closing brace } to match.
A function requires curly braces to denote the beginning and end of the function.
void Function1()
{
// Body of Function
}
Program loops such as the for statement may also need the curly braces
for (int I = 0; I < 9; I++)
{
// Body of loop
}
It is also good practice to use braces in control structures such as the if statement.
if (I < 0)
{
// Body of If statement }
Arithmetic Operators
= - The equals sign is the assignment operator used to set a variable to a value. For
example, the following sets the value of the variable Data to the result from the function
CreatePhotoInfo():
String Data = CreatePhotoInfo();
+ - The plus sign performs addition. For example, the following adds the Strings
Command, PhotoTakenCount and Ext together to get a final string called Filename.
String Filename = Command + PhotoTakenCount + Ext;
- - The minus sign performs subtraction. For example, the following calculates the time
it takes to capture a photo using the camera by measuring the difference between the
starting time before the image is captured and the ending time just after the image is
captured.
ElapsedTime = TimeForCaptureEnd - TimeForCaptureStart;
* - The asterisk sign performs multiplication. For example, the total bytes of an image is
calculated by multiplying the width of the image by the height of the image by the bytes
per pixel in the image.
int TotalBytes = ImageWidth * ImageHeight * BytesPerPixel;
/ - The back slash sign performs division. For example, the speed in miles per hour of an
object is calculated by dividing the number of miles the object has traveled by the number
of hours that it took to travel that distance.
float Speed = NumberMiles / NumberHours;
% - The percent sign is the modulo operator that returns the remainder from a division
between two integers. For example,
int remainder = dividend % divisor;
Comparison Operators
== - The double equal is a comparison operator to test if the argument on the left side of
the double equal sign is equal to the argument on the right side. If the arguments are equal
then it evaluates to true. Otherwise it evaluates to false. For example, if the automatic
black level correction parameter is set to off then the code block is executed.
if (ABLCParam == AblcOFF)
{
// Execute code
}
!= - The exclamation point followed by an equal sign is the not equal to operator that
evaluates to true if the argument on the left is not equal to the argument on the right side.
Otherwise, it evaluates to false. For example, in the following code if the current camera
resolution is not set to VGA then the code block is executed.
if (Resolution != VGA)
{
// If current resolution is not VGA then set camera for VGA
< - The less than operator evaluates to true if the argument on the left is less than the
argument on the right. For example, in the code that follows the for loop will execute the
code block while the height is less than the height of the photo. When the height counter
becomes equal or greater than the photos height then the loop exits.
for (int height = 0; height < PHOTO_HEIGHT; height++)
{
// Process every row of the photo
}
> - The greater than operator evaluates to true if the argument on the left side is greater
than the argument on the right side. For example, in the following code if there are
available characters to read in from the Serial Monitor then execute the code block. That is
the number of available characters to read in must be greater than 0.
if (Serial.available() > 0)
{
// Process available characters from Serial port
}
<= The less than sign followed by the equal sign returns true if the argument on the left
hand side is less than or equal to the argument on the right hand side. It returns false
otherwise.
>= The greater than sign followed by the equal sign returns true if the argument on the
left is greater than or equal to the argument on the right. It returns false otherwise.
Boolean Operators
&& - This is the and boolean operator that only returns true if both the arguments on
the left and right side evaluate to true. It returns false otherwise. For example, in the
following code only if the user selects both denoise and edge enhancement will the code
block be executed. Otherwise it will not be executed.
if ((DenoiseParam == DenoiseYes) &&
(EdgeParam == EdgeYes))
{
// Set camera for both denoise and edge enhancement of images.
|| - This is the or operator and returns true if either the left argument or the right
argument evaluates to true. Otherwise, it returns false. For example, in the following code
if either the cameras command is set to QQVGA or QVGA then the code block is
executed. Otherwise it is not executed.
if ((Command == QQVGA) || (Command == QVGA))
{
// Code
}
! The not operator returns the opposite boolean value. The not value of true is false
which is 0 and the not value of false is true which is non zero. In the following code a file
is opened on the SD card and a pointer to the file is returned. If the pointer to the file is
NULL which has a 0 value then not NULL would be 1 which is true. The if statement is
executed when the argument is evaluated to true which means that the file pointer is
NULL. This means that the open operation has failed and an error message needs to be
displayed.
// Open File
InfoFile = SD.open(Filename.c_str(), FILE_WRITE);
// Test if file actually open
if (!InfoFile)
{
Serial.println(F(\nCritical ERROR Can not open Photo Info File for output ));
return; }
Bitwise Operators
& - This is the bitwise and operator between two numbers where each bit of each
number has the and operation performed on it to produce the result in the final number.
The resulting bit is 1 only if both bits in each number is 1. Otherwise the resulting bit is 0.
| - This is the bitwise or operator between two numbers where each bit of each number
has the or operation performed on it to produce the result in the final number. The
resulting bit is 1 if the bit in either number is 1. Otherwise the resulting bit is 0.
^ - This is the bitwise xor operator between two numbers where each bit of each
number has the xor operation performed on it to produce the result in the final number.
The resulting bit is 1 if the bits in each number are different and 0 otherwise.
~ - This is the bitwise not operator where each bit in the number following the not
symbol is inverted. The resulting bit is 1 if the initial bit was 0 and the bit is 0 if the initial
bit was 1.
<< - This is the bitshift left operator where each bit in the left operand is shifted to the
left by the number of positions indicated by the right operand. For example, in the code
below a 1 is shifted left PinPosition times and the final value is assigned to the variable
ByteValue.
ByteValue = 1 << PinPosition;
>> - This is the bitshift right operator where each bit in the left operand is shifted to the
right by the number of positions indicated by the right operand. For example, in the code
below bits in the number 255 are shifted to the right PinPosition times and the final value
is assigned to the variable ByteValue.
ByteValue = 255 >> PinPosition;
Compound Operators
++ - This is the increment operator. The exact behavior of this operator also depends if it
is placed before the variable being incremented or after the variable being incremented. In
the following code the variable PhotoTakenCount is incremented by 1.
PhotoTakenCount++;
If the increment operator is placed after the variable being incremented then the variable is
used first in the expression it is in before being incremented. For example, in the code
below the height variable is used first in the for loop expression before it is incremented.
So the first iteration of the for loop below would use height = 0. The height variable would
be incremented after being used in the expression.
for (int height = 0; height < PHOTO_HEIGHT; height++)
{
// Process row of image
}
If the increment operator is placed before variable being incremented then the variable is
incremented first then it is used in the expression that it is in. For example, in the code
below the height variable is incremented first before it is used in the for loop. This means
that in the first iteration of the loop the height variable is 1 instead of 0.
for (int height = 0; height < PHOTO_HEIGHT; ++height)
{
// Process row of image
- The decrement operator decrements a variable by 1 and its exact behavior depends
on the placement of the operator either before or after the variable being decremented. If
the operator is placed before the variable then the variable is decremented before being
used in an expression. If the operator is placed after the variable then the variable is used
in an expression before it is decremented. This follows the same pattern as the increment
operator discussed previously.
+= - The compound addition operator adds the right operand to the left operand. This is
actually a short hand version of
operand1 = operand1 + operand2;
Which is the same as the version that uses the compound addition operator.
operand1 += operand2;
-= - The compound subtraction operator subtracts the operand on the right from the
operand on the left. For example, the code for a compound subtraction would be:
operand1 -= operand2;
This is the same as the following:
operand1 = operand1 - operand2;
*= - The compound multiplication operator multiplies the operand on the right by the
operand on the left. The code for this is as follows.
operand1 *= operand2;
This is also equivalent to:
operand1 = operand1 * operand2;
/= - The compound division operator divides the operand on the left by the operand on
the right. For example,
operand1 /= operand2;
This is equivalent to:
operand1 = operand1 / operand2;
&= - The compound bitwise and operator is equivalent to:
x = x & y;
!= - The compound bitwise or operator is equivalent to: x = x | y;
* - The Dereference Operator allows you to access the contents that a pointer points to.
For example, the code that follows declares a variable called pdata as a pointer to a byte
and creates storage for the data using the new command. The pointer variable called pdata
is then dereferenced to allow the actual data that the pointer points to be set to 1.
byte *pdata = new byte;
*pdata = 1;
& - The Address Operator creates a pointer to a variable. For example, the following
code declares a variable called data of type byte and assigns the value of 1 to it. A function
called FunctionPointer() is defined that accepts as a parameter a pointer to a byte. In order
to use this function with the variable data we need to call that function with a pointer to
the variable data.
byte data = 1;
void FunctionPointer(byte *data)
{
// body of function
} FunctionPointer(&data);
Variable Scope
Global variables In the Arduino programming environment global variables are
variables that are declared outside any function and before they are used. For example in
the following code below taken from the image capture program I wrote for this book the
following are global variables that are declared at the beginning of the program.
// VGA Default
int PHOTO_WIDTH = 640;
int PHOTO_HEIGHT = 480;
int PHOTO_BYTES_PER_PIXEL = 2;
Local variables Local variables are declared inside functions or code blocks and are
only valid inside that function or code block. For example, in the following function the
variable localnumber is only visible inside the Function1() function.
void Function1() int localnumber = 0; }
Conversion
char(x) This function converts a value x into a char data type and then returns it.
byte(x) This function converts a value x into a byte data type and then returns
it.
int(x) This function converts a value x into a integer data type and then returns it.
word(x) This function converts a value x into a word data type and then returns it.
word(highbyte,lowbyte) This function combines two bytes, the high order byte and the
low order byte into a single word and then returns it.
long(x) This function converts a value x into a long and then returns it.
float(x) This function converts a value x into a float and then returns it.
Control Structures
if (comparison operator) The if statement is a control statement that tests if the result of
the comparison operator or argument is true. If it is true then execute the code block. For
example, in the following code the if statement tests to see if the YUV matrix parameter is
set to activate the YUV color matrix. If it is set then the SetCameraColorMatrixYUV()
function is called.
// Set Color Matrix for YUV
if (YUVMatrixParam == YUVMatrixOn)
{
SetCameraColorMatrixYUV();
}
if (comparison operator) else The if else control statement is similar to the if statement
except with the addition of the else section which is executed if the previous if statement
evaluates to false and is not executed. For example, in the following code if the frames per
second parameter is set for 30 frames per second then the SetupCameraFor30FPS()
function is called. Otherwise, if the frames per second parameter is set to night mode then
the
SetupCameraNightMode() function is called.
// Set FPS for Camera if (FPSParam == ThirtyFPS)
{
SetupCameraFor30FPS();
}
else
if (FPSParam == NightMode)
{
SetupCameraNightMode();
}
for (initialization; condition; increment) The for statement is used to execute a code
block usually initializing a counter then performing actions on a group of objects indexed
by that incremented value. See the code example below.
for (int i = 0 ; i < NumberElements; i++)
{
// Process Element i Here
}
while (expression) The while statement executes a code block repeatedly until the
expression evaluates to false. In the following code the while code block is executed as
long as data is available for reading from the file.
// read from the file until theres nothing else in it:
while (TempFile.available())
{
Serial.write(TempFile.read());
}
break A break statement is used to exit from a loop such as a while or for loop. In the
following code the while loop causes the code block to be executed forever. If there is data
available from the Serial Monitor then it is processed and then the while loop is exited.
while (1)
{
if (Serial.available() > 0) // Process the data
break;
}
}
return (value) The return statement exits a function. It also may return a value to the
calling function.
return; return false;
Summary
In this chapter I covered the basics of the Arduino programming language. I covered a
broad range of basic topics such as data types, constants, built in functions, and control
loops. In addition, this chapter was not meant to be a reference manual but a quick start
guide to the basics of the Arduino programming language. Please refer to the official
Arduino language reference for more information.
Chapter 4
Figure 4-
4. Base 10 decimal number
Binary Numbers (Base 2 Representation)
Base 2 numbers or binary numbers have digits consisting of 0 and 1. The decimal (base
10) value for a binary number is calculated by a method similar to that in the previous
section. For example, to calculate the decimal value of the binary number 1111 multiply
each component of the number by the base 2 raised to the power of the position of that
component then sum all the components together. Positions are zero based such that the
first position is 0.
1000 => (1 * 2^3) => 8
100 => (1 * 2^2) => 4
10 => (1 * 2^1) => 2
1 => (1 * 2^0) => 1
The individual components of the binary number are then added together to get 8 + 4 + 2
+ 1 = 15 in base 10 decimal. See Figure 4-5.
Figure 4-
5. Base 2 binary number
Hexadecimal Numbers (Base 16 Representation)
Base 16 numbers or hex numbers consist of digits 0 through 9 and letters A through F. The
hex digits 0 through 9 are the same as the decimal digits of 0 though 9. However, the hex
digits of A through F correspond in value to 10 through 15 in base 10 or decimal. See
Figure 4-6.
The hex number B65F can be converted to decimal using the same method as discussed
previously for binary numbers. Each component of the hex number is multiplied by 16 to
the power of the components position in the number and then all these components are
added together to get the final base 10 value. The first position being considered 0. Thus,
to convert B65F to a decimal number we can do the following:
B000 => B * 16^3 => 11 * 4096 => 45056
600 => 6 * 16^2 => 6 * 256 => 1536
50 => 5 * 16^1 => 5 * 16 => 80
F => F * 16^0 => 15 * 1 => 15
So adding all these components 45056 + 1536 + 80 + 15 = 46,687 (Base 10). See Figure
4-7 for a more detailed graphic of the above.
Figure 4-8.
Binary number 11010101
Next, we need to break the binary number into 4 bit groups such as 1101 and 0101. Each
of these groups will be converted to a hex number. See Figure 4-9.
Figure 4-
9. Binary to hex conversion
Next, we convert the 4 bit group consisting of 1101 into a single hex digit. To do this we
take the components of the binary number and multiply them by 2 raised to the power of
their zero based positions and then add these results together and use the table in Figure 4-
6 to convert the decimal value into a hex value. For the binary number 1101 the
corresponding hex digital is D. See Figure 4-10.
Figure 4-10. Converting
the first group of 4 bits of the binary number to the first component of the hex number
Then we convert the other group of 4 bits which is 0101 into a hex number which is 5. We
use the same method as for the first group of digits. The key to remember here is that each
group of 4 bits from the original binary number is treated like a separate number so that
the leftmost digits value is 2^3 followed by 2^2, 2^1, and 2^0. These translate into the
decimal values 8, 4, 2, 1 which are indicated on Figure 4-11.
Figure 4-11. Converting
the second component of the binary number to the second component of the hex number
The final step is to combine the hex values from each of the 4 bit groups into one single
group of digits which is D5. See Figure 4-12 for a summary of the conversion process.
The COM17 ov7670 camera register controls the camera automatic exposure controller
window size, and the Digital Signal Processors color bar test enabled status used for
testing the cameras output. Bit 7 and bit 6 control the AEC window size. The default
setting is 00 which is fine so we do not need to change these bits. Bit 5 and bit 4 are
reserved so we can ignore these and leave them at their default settings of 00. Bit 3 is a
key bit that enables the color bar test mode of the Digital Signal Processor or DSP. Set this
bit to 1 to enable the color test and 0 to disable it. Bits 2, 1, and 0 are reserved so we can
leave these at their default values of 000. See Figure 4-14.
Figure 4-14. Com17 Register
The color bar test is a series of vertical color bars consisting of white, yellow, light blue,
green, purple, red, blue, and black as seen from left to right. When the color bar test is
enabled normal camera image capturing is disabled and the only output is the color bar
test image. This test is useful in determining if the camera is set up correctly and
producing the correct color image. See Figure 4-15.
Important Note: An extremely important thing to note here is that in order to get the
correct colors from the ov7670 camera you will need to set a camera register that in the
official documentation is listed as being reserved but actually is needed to correctly
display colors. For example, red colors will appear green in the photo that is taken by the
camera. We will discuss this more in depth later in the book and show you exactly how to
do it in a hands on example.
Figure 4-15. The
color bar test
In order to enable the color bar test you need to set the COM17 register to the hex values
of 08. In order to disable the color bar test you can set the COM17 register to the hex
value of 00. Remember that each hex number represents 4 binary bits and thus you can
easily get the hex value you need from Figure 4-14.
In terms of implementing these values into Arduino C/C++ source code we can declare
defines that represent a value for disabling the color bar test while keeping the AEC
window setting set to normal such as:
#define COM17_VALUE_AEC_NORMAL_NO_COLOR_BAR 0x00
We can also declare a define to represent the value for enabling the color bar test while
keeping the AEC window setting set to normal such as:
#define COM17_VALUE_AEC_NORMAL_COLOR_BAR 0x08 // Activate Color Bar
for DSP
The 0x in front of the number identifies this number as a hexadecimal number value. We
will go into further detail on how to actually set the register value in code in a later hands
on example in this book. Here, we just are showing you how you change the values in a
cameras registers in order to change a certain property in this case it was displaying the
color bar test.
Boolean Variables, Logic and Truth Tables
A boolean variable is a variable that can take on one of two values such as 0 or 1. The
digital output pins of the Arduino can output electrical signals that represent boolean
variables. You can use the built in Arduino function digitalWrite() to output a HIGH or
LOW value representing a boolean variable.
For example, to output a HIGH value which represents 1 or true to the pin RRST you
would write code such as:
digitalWrite(RRST, HIGH);
To output a LOW value which represents 0 or false to pin RRST you would write code
such as:
digitalWrite(RRST, LOW);
Boolean logic applies to boolean variables and can be used in digital circuits to control a
boolean output based on two or more boolean inputs. The basic boolean logic operations
are AND, OR, and NOT. In order for the output of the AND operator to be true or 1 all of
the inputs must be true or 1. See Figure 4-16 for the boolean truth table for AND which
lists all the possible inputs and output combinations for the AND operator using two
boolean input variables.
Figure 4-
21. RCLK clock pulse output from Arduino to camera
The way I generate a clock pulse to drive the RCLK input is by:
1. Calling the digitalWrite() function to set the desired output pin HIGH
2. Calling the delayMicroseconds() function to wait a specified number microseconds. All
this time the output pin that is connected to the RCLK input on the camera is HIGH.
3. Calling the digitalWrite() function and setting the output pin connected to RCLK to
LOW.
4. Calling the delayMicroseconds() function and pausing program execution for a
specified time. This generates the LOW part of the clock pulse.
See Listing 4-1 for the Arduino code
Listing 4-1. The PulsePin() function
void PulsePin(int PinNumber, int DurationMicroSecs)
{
digitalWrite(PinNumber, HIGH); // Sets the pin on
delayMicroseconds(DurationMicroSecs); // Pauses for DurationMicroSecs microseconds
digitalWrite(PinNumber, LOW); // Sets the pin off
delayMicroseconds(DurationMicroSecs); // Pauses for DurationMicroSecs microseconds
}
RCLK is defined as pin 26 using a #define statement
#define RCLK 26 // Output FIFO buffer output clock
Pulsing the actual RCLK pin is done calling the PulsePin() function such as:
PulsePin(RCLK, 1);
Reading Schematics
In order to understand the schematics for the ov7670 camera or digital devices in general
you should know the standard symbols for logic gates that implement the boolean logic
discussed previously. In this section we will discuss the schematic symbols for the AND,
OR and NOT gates. In addition we will discuss the NAND, and NOR gates which are a
combination of the AND, and OR gates with a NOT gate.
And Gates
The schematic symbol for an AND gate that implements the AND boolean function is
shown in Figure 4-22.
Or Gates
The schematic symbol for the OR gate that implements the OR boolean logic is shown in
Figure 4-23.
The schematic symbol for the NOT gate that implements the NOT boolean logic is shown
in Figure 4-24.
NAND Gates
The schematic symbol for the NAND gate that performs the boolean AND function
followed by the boolean NOT function is shown in Figure 4-25. The Texas Instruments
SN74LVC1G00 NAND gate is the actual type of gate used in the ov7670 camera
according to the publicly available schematics.
Figure 4-25. NOT AND gate
NOR Gates
The schematic symbol for the NOR gate that performs the boolean OR function followed
by the boolean NOT function is shown in Figure 4-26.
This section describes the publicly available documentation relating to the ov7670 camera
including the official documentation from Omnivision, the maker of the ov7670 camera. I
recommend that you download the following pdf files which can be read using the Adobe
Acrobat Reader which is free and can be downloaded from Adobes web site. You can also
do a google search for these documents. This book is not meant to be a reference manual
but a quick start guide that is designed for you to get quickly started developing camera
based applications using the Arduino and ov7670. However, the information you learn in
this book will also help you develop camera applications for cameras other than the
ov7670 as well.
Omnivision ov7670/ov7171 Advanced Information Preliminary Datasheet (Version 1.4
August 21, 2006)
http://www.electronicaestudio.com/docs/sht001.pdf
ov7670/ov7171 Implementation Guide (Version 1.0 September 2,2005)
https://github.com/dalmirdasilva/ArduinoCamera/blob/master/CameraAL422B/d
atasheet/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf
ov7670 Software Application Note
https://github.com/luckasfb/Development_Documents/blob/master/MTKMediatek-Alps-
Documents/OV7670%20software%20application%20note.pdf
AverLogic AL422B Data Sheets (Revision V1.01)
http://www.frc.ri.cmu.edu/projects/buzzard/mve/HWSpecs1/Documentation/AL422B_Data_Shee
Omnivision ov7670 FIFO camera schematic
http://www.beyondlogic.org/pdf/OV7670_FIFO_SCH_V1.pdf
The camera input and output pins on the ov7670 are shown below in Figure 4-27.
Figure 4-27. Camera pin inputs and outputs
3.3v Input for the 3.3v output pin on the Aruduino
Ground Ground connection for the camera to be connected to ground on Arduino
SIOC I2C interface connection to the Arduinos SCL clock line.
SIOD I2C interface connection to the Arduinos SDA data line.
VSYNC Output from camera that marks the start or stop of an output of a single image
frame.
HREF True if a row of an image is being output to the video port.
D7 D0 Video output port, 1 byte or 8 bits wide. Image data is read from these pins
one byte at a time.
RST Input that can be used to reset the camera.
PWDN Input that can be used to put the camera into power down mode.
STR Camera strobe output that can be used to turn on an L.E.D. light while the camera
takes an image.
RCK Input for a clock pulse that is used to read in data from the video port one byte at
a time. One clock cycle corresponding to one byte.
WR Write enable input for enabling the writing of data to the cameras frame buffer
memory. True if you want image data from the camera to be written to the FIFO frame
buffer memory. False if the image data is not to be written to the cameras memory.
OE Input pin that controls the cameras output enable for the video port that is used to
determine if the data on the pins D7 D0 are valid.
WRST Input pin that is used to reset the frame buffer memorys write pointer so that
image data will be written at the start of the image or frame.
RRST Input pin that is used to reset the frame buffer memorys read pointer so that
image data is read and sent to the video output port starting at the beginning of the image
or frame.
This section discusses the main camera chip that captures, processes the image, and sends
it out to the frame buffer memory where it can then be read by the Arduino. See Figure 4-
28.
This section discusses the cameras frame buffer memory chip. See Figure 4-29.
Figure 4-29. AverLogic AL422B FIFO frame buffer memory chip
DI0 - DI7 Data input. Data is input on the rising edge of the cycle of WCK when /WE
is pulled low (enabled).
DO0 DO7 Data output. Data output is synchronized with the RCK clock. Data is
obtained at the rising edge of the RCK clock when /RE is pulled low. The access time is
defined from the rising edge of the RCK cycle.
/WE Write enable that is active low. /WE controls the enabling/disabling of the data
input. When /WE is pulled low, input data is acquired at the rising edge of the WCK cycle.
When /WE is pulled high, the memory does not accept data input. The write address
pointer is stopped at the current position. /WE signal is fetched at the rising edge of the
WCK cycle.
GND Ground.
TST Test pin. For testing purpose only. It should be pulled low for normal applications.
/WRST Write reset that is active low. This reset signal initializes the write address to 0,
and is fetched at the rising edge of the WCK input cycle.
WCK Write clock. The write data input is synchronized with this clock. Write data is
input at the rising edge of the WCK cycle when /WE is pulled low (enabled). The internal
write address pointer is incremented automatically with this clock input.
VDD 5 volts or 3.3 volts.
/RE Read enable that is active low. /RE controls the operation of the data output. When
/RE is pulled low,output data is provided at the rising edge of the RCK cycle and the
internal read address is incremented automatically. /RE signal is fetched at the rising edge
of the RCK cycle.
/OE Output enable that is active low. /OE controls the enabling/disabling of the data
output. When /OE is pulled low, output data is provided at the rising edge of the RCK
cycle. When /OE is pulled high, data output is disabled and the output pins remain at high
impedance status. /OE signal is fetched at the rising edge of RCK cycle.
/RRST Read reset that is active low. This reset signal initializes the read address to 0,
and is fetched at the rising edge of the RCK input cycle.
RCK Read clock. The read data output is synchronized with this clock. Read data
output at the rising edge of the RCK cycle when /OE is pulled low (enabled). The internal
read address pointer is incremented with this clock input.
DEC Decoupling cap input. Decoupling cap pin, should be connected to a 1mF or
2.2mF capacitor to ground for 5V application. For 3.3V application, the DEC pin can be
simply connected to the 3.3V power with regular 0.1mF bypass capacitor.
This section covers the overall camera schematic and shows how the main parts of the
camera interact with one another. See Figure 4-30.
Important things to note are:
The camera clock generator creates a clock pulse that drives the XCLK input of the main
camera chip.
The video port output of the main camera chip pins D0-D7 are connected with the video
frame buffer FIFO memorys input data pins which are DI0-DI7.
The PCLK on the main camera chip that is synced with the output of bytes that represent
the pixels of the image is connected to the FIFO memorys WCK that is synced with the
writing of this pixel data to the memory.
The HREF output pin on the main camera chip is connected to a NAND gate with a user
input write enable signal that will activate writing data to the FIFO memory when the
write enable signal is HIGH and the HREF is HIGH. This results in a HIGH value from
the AND operation and a LOW value from the NOT operation which activates the /WE
input to the FIFO memory which is active LOW. See Figure 4-31 for a closer view of the
NAND gate.
Basic Operation
The main camera chip outputs a single video frame image through the 8-bit video port by:
1. Pulsing VSYNC high to indicate the start of a new video frame for output.
2. The HREF goes high when a valid row of pixels from the video frame is put on the
output video port pins of D0-D7. This continues for each row from row 0 to the last row
for the image size which is row 479 for a VGA screen resolution (640 by 480). In addition,
when the HREF is high the PCLK syncs with the output of the bytes for each row in the
image. See Figure 4-33.
3. VSYNC pulses high again to indicate the end of the video frame output.
See Figure 4-32 for the timing diagram.
Figure 4-32. Main camera chip VGA image output simplified timing diagram
Figure 4-33. The pixel clock
The image output from the main camera chip is then fed into the FIFO video frame buffer
memory. From there it is read by the Arduino. The general operation of the frame buffer is
given in the functional block diagram in Figure 4-34.
The SD card reader input and output pins are shown in Figure 5-1. The input and output
pin layouts are from a SD card reader I purchased from Amazon.com. The exact listing
was SD Card Reader Module Slot Socket For Arduino ARM MCU (2pcs) by Exciting
$5.50 and you get 2 SD card readers for that price. This SD card reader is for a normal
full size SD card.
The input/outputs pins of the SD card reader are:
GND Ground connection.
3.3 3.3 volt input
5V 5 volt input
SDCS SD cards Chip Select Pin. This is the pin that the master can use to enable and
disable specific devices. When a devices Chip Select (also called the Slave Select) pin is
low, it communicates with the master. When its high, it ignores the master. This allows
you to have multiple devices sharing the same MISO, MOSI, and CLK lines.
MOSI Master Out Slave In. The master line for sending data to the peripherals.
SCK Serial Clock. The clock pulses which synchronize data transmission generated by
the master.
MISO Master In Slave Out. The slave line for sending data to the master.
Figure 5-1. SD card reader input/output pins
In terms of the connecting the SD card to the Arduino Mega, this is done by:
Connecting Pin 50 on the Arduino to the (MISO) pin on the SD card
Connecting Pin 51 on the Arduino to the (MOSI) pin on the SD card
Connecting Pin 52 on the Arduino to the (SCK) pin on the SD card.
Connecting Pin X (User Defined) on the Arduino to the (SDCS) pin on the SD card or
connecting Pin 53 on the Arduino (Hardware SS or Slave Select) to the (SDCS) pin on the
SD card.
Connecting the GND pin on the card reader to the GND pin on the Arduino.
Connecting the 3.3 V pin on the card reader to the 3.3v output on the Arduino. Important
Note: There are two pins for each input/output item for the SD card. I recommend using
the pin closest to the pin label since I have seen comments that on some cards the pin that
is farthest from the pin label does not work. See Figure 5-2 to see how I set up my SD
card.
Figure 5-2. SD card
reader connections
The SD card
The SD card itself goes into the metal holder face up and oriented as shown in Figure 5-3.
You will need to push the card in until you hear a click. This indicates that the card is fully
in and is ready for use. To remove the card press down until you hear another click and
then remove the card.
The Arduino comes with a built in library of functions that allow access to the SD card.
There are functions that allow the user to write data to the SD card, read data from the SD
card, check if a file on the SD card exists, and delete a file from the SD card.
In order to use the SD library functions you need to include the SD library header in your
source code such as:
#include <SD.h>
The hardware slave select pin is pin 53 on the Arduino Mega
const int HardwareSSPin = 53; // For Arduino Mega
The hardware slave select pin also must be set to be of an output type in order for the SD
card library to work. We call the built in pinMode() function to set the hardware slave
select pin to be of an output type. This is needed even if it is not used. For example, the
actual chip select pin is other than 53.
pinMode(HardwareSSPin, OUTPUT); // change this to 53 on a mega
Next, we define a chip select pin as pin 48. We could have easily defined the chip select
pin as another digital pin if we wished.
const int chipSelect = 48;
Then, we need to initialize the SD card and SD card library by calling the SD.begin()
function. Here we have the option of changing the default chip select pin of 53 (on the
Mega) which is called the hardware SS pin to a pin specified in the number to sent the
begin() function.
For example, we can initialize the SD card with the chip select pin being set to 48 by the
following code. If the initialization succeeds then a true value is returned otherwise a false
value is returned.
if (!SD.begin(chipSelect))
{
// SD card initialization failed.
return;
}
else
{
// SD card initialization successful }
You can read files that you have saved from the SD card.
To read data from a file that has been saved to a SD card and print it to the screen from the
Serial Monitor you must:
1. Declare a variable of type File that represents the file to be read in.
2. Call SD.open() with the filename that is to read in. Set the return value of the function
to the File variable created in Step 1.
3. If the File variable is null or 0 then the opening of the file failed.
4. If the File variable is valid then you can read in the contents. The File objects
available() function can be called to determine if there are any more bytes to read from the
file. Use the read() function to actually read in the bytes and print them to screen. You can
put the read() function into a while loop and the test part of the loop can test to see if there
are more bytes available for reading.
5. After reading all the bytes from the file and processing them call the close() function to
close the file.
See Listing 5-2 for an example of how to read in a file from a SD card and print the
contents to the screen using the Serial Monitor.
Listing 5-2. Reading files from the SD card.
File TempFile; // Reads in file and prints it to screen via Serial
TempFile = SD.open(testfile.txt);
if (TempFile)
{
// read from the file until theres nothing else in it:
while (TempFile.available())
{
Serial.write(TempFile.read());
}
// close the file:
TempFile.close();
}
else
{
// Error opening file
Serial.print(Error opening ); }
When writing files to the SD card you may need to save over an existing file. However,
the open() command only allows you to open a file for writing starting at the end of the
file. There is no option to open a file for writing and start at the beginning of the file. So
we need to test for the existence of the file we want to write and remove it if it exists.
In order to write over an existing file we need to:
1. Check to see if that file already exists using the SD.exists() function with the input
parameter of the filename we want to write.
2. If the SD.exists() function returns true then you need to call the SD.remove() function
with the filename as a parameter to remove the file from the SD card.
3. Now you are able to write the new file using the code in Listing 5-1.
See Listing 5-3 for an example of how to test for the existence of a file and then remove it
if it does exist.
Listing 5-3. Removing existing files from the SD card
// Check if file already exists and remove it if it does
if (SD.exists(testfile.txt))
{
SD.remove(testfile.txt); }
Overview of Arduinos I2C Interface
This section covers the Arudinos I2C interface. I first cover the input/output pins for the
I2C on the Arduino and the ov7670 camera. Then, I show you how to initialize, write to,
and read from a I2C device using the Arduino.
The I2C interface consists of two pins the SDA pin which handles data and the SCL pin
which provides the clock.
On the Arduino Mega, SDA is digital pin 20 and SCL is 21. See Figure 5-5 where the
SDA and SCL pins are circled.
Figure 5-5. Arduino Mega 2560 with SDA and SCL pins circled
On the ov7670 camera the SIOC is hooked to the Arduinos SCL pin. The SIOD is
connected to the Arduinos SDA pin. See Figure 5-6 for the location of these pins on the
In order to use an I2C device you need to first initialize the I2C bus. You do this by first
including the Wire library into your source code. Such as:
#include <Wire.h>
Then you need to call the Wire.begin() function in the setup() function to initialize the
Arduinos Wire library such as:
void setup()
{
Wire.begin(); }
1. Connect the Arduino Mega 2560s SDA digital pin 20 to the SIOD pin on the camera.
2. Connect the Arduino Mega 2560s SCL digital pin 21 to the SIOC pin on the camera.
3. Connect the 3.3 volt pin on the Arduino to the 3.3 volt pin on the camera.
4. Connect the GND pin on the Arduino to the GND pin on the camera.
5. Upload the I2C Scanner code to your Arduino.
6. Hit the Serial Monitor button and wait for the test to run.
7. The program should eventually detect the camera that is attached to the I2C bus and
report that the address of the camera is 0x21. You will need to use this address to read and
write data using the camera.
Overview of the Omnivision ov7670 FIFO Camera Image
Capture Software
In this section I discuss in detail the software that I created to capture images from the
camera. I first discuss initializing the program and I then cover the main program loop.
The initialization involves initializing the camera and SD card. The main program loop
consists of processing various user inputs from the Serial Monitor and performing certain
actions based on these user inputs.
The first thing that is run in an Arduino program is the user defined code located in the
setup() function.
In this setup() function the following actions are taken:
1. The serial monitor is initialized so that you will be able to give the camera and SD card
commands.
2. The ov7670 camera is initialized and set up for use in taking photos.
3. The SD card is initialized.
The Serial Monitor is initialized by:
1. Calling the Serial.begin() function with 9600 as the rate of communication. Also, make
sure you have the Serial Monitor set to 9600 as well which also should be the default.
2. Printing out a text message to the Serial Monitor indicating that the program has started.
See Listing 5-7.
Listing 5-7. Initializing the Serial Monitor
// Initialize Serial
Serial.begin(9600);
Serial.println(F(Arduino SERIAL_MONITOR_CONTROLLED CAMERA Using
ov7670 Camera)); Serial.println();
Camera Initialization
SD Card Initialization
We are done now initializing the camera. The next thing we need to initialize is the SD
card.
In order to initialize the SD card we need to:
1. Call the pinMode(HardwareSSPin, OUTPUT) function setting pin 53 which is the
hardware slave select pin to OUTPUT. This must be done even though we are not using it
because the SD library requires it.
2. Call the SD.begin(chipSelect) function with the chipSelect pin that can be used to
enable or disable the SD card reader.
3. If the return value is false then the SD card was not successfully initialized. Otherwise,
the card has been successfully initialized for use.
See Listing 5-16.
Listing 5-16. Initializing the SD card
// Initialize SD Card
Serial.print(F(\nInitializing SD card));
pinMode(HardwareSSPin, OUTPUT); // change this to 53 on a mega
if (!SD.begin(chipSelect))
{
Serial.println(F(Initialization failed /nThings to check:));
Serial.println(F(- Is a card is inserted?));
Serial.println(F(- Is your wiring correct?));
Serial.println(F(- Did you change the chipSelect pin to match your shield or module?));
return;
} else {
Serial.println(F(Wiring is correct and a card is present )); }
After the setup() function is called the loop() function is called repeatedly until the
Arduino is reset or the Arduino is powered off.
The loop() function does the following:
1. Reads in user input from the Serial Monitor.
2. Execute various camera or SD card functions based on the user input
Official Website
According to the readme.txt file in the version of ffmpeg I used for this book, the ffmpeg
version is the Win32 static build by Kyle Schwarz.
The FFmpeg version is 2015-03-12 git-3bedc99
This is the version I used to test the output of the ov7670 camera with both the YUV and
the Bayer RAW picture files. If you are having problems converting your YUV or RAW
image files to a viewable format then try to use this version of ffmpeg. They should have
an archive with older versions of the program available.
FFMPEG CONVERSION
This section describes the ffmpeg command line options that are required to convert the
images into an easily viewable format. The images from the camera that are recorded in
YUV and Raw Bayer format are converted to PNG files. PNG stands for portable network
graphics file which is a common image file type that can be viewed in windows explorer
or though a paint program like Paint Shop Pro.
For each of the following commands replace INPUTFILE.YUV or INPUTFILE.RAW
with the actual filename of the YUV file or Bayer RAW file you want to covert. Change
the OUTPUTFILE.PNG filename to the filename you want to save the new image as.
QQVGA
QVGA
ffmpeg -f rawvideo -s 320x240 -pix_fmt yuyv422 -i INPUTFILE.YUV -f image2 -vcodec
png OUTPUTFILE.PNG
VGA
The first thing you need to do is create a 3.3 volt node on a breadboard that will provide
power to the camera and to the SD card reader. To do this you need to connect two male to
female jumper wires and 1 wire with male connections on both ends into holes in the
breadboard that are connected together. The two male to female wires will be used to
connect the 3.3 volt input pins on the SD card reader and camera to the 3.3 volt node on
the breadboard. The wire with the male connections on both ends will be used to connect
the 3.3 volt node on the breadboard to the 3.3 volt output from the Arduino.
Some breadboards have a power line and a ground line where all the pins in the column
are connected. They also have rows of 5 pins that are connected together. See Figure 6-1.
Figure 6-1.
Breadboard with power rails and ground line
There are also smaller breadboards available that just have two columns of rows of nodes.
Each node consists of 5 pins. I used one of these for the power node for the hands on
example in this book. See Figure 6-2. The figure shows the 3.3 volt power node. You can
buy both kinds of breadboards on Amazon.com.
Next, you need to connect the SD card reader to the Arduino. Make sure the power is off
to the Arduino before you perform the following steps. You will need to use the female to
male jumper wires for connecting the SD card to the Arduino.
You will need to:
Connect the 3.3 volt pin on the SD card reader to the breadboards 3.3 volt node.
Connect the SDCS pin to pin 48 on the Arduino.
Connect the MOSI pin to pin 51 on the Arduino.
Connect the SCK pin to pin 52 on the Arduino.
Connect the MISO pin to pin 50 on the Arduino.
Connect the GND pin to a GND pin on the Arduino.
See Figure 6-3.
Figure 6-3. Connecting
the SD card to the Arduino Mega 2560
The user definable pin assignments for a SD card is just the SDCS or chip select pin which
is defined in our image capture program as pin 48. This means that the wire from the
cameras SDCS pin is connected to the Arduinos pin 48.
const int chipSelect = 48;
Next, we need to connect the ov7670 camera to the Arduino. You will need to use the
female to male jumper wires for connecting the camera to the Arduino.
To connect the camera to the Arduino you need to:
Connect the 3.3 volt pin on the camera to the 3.3 volt node on the breadboard.
Connect the Ground pin on the camera to one of the Ground pins on the Arduino
Connect the SIOC pin on the camera to the SCL or pin 21 on the Arduino.
Connect the SIOD pin on the camera to the SDA or pin 20 on the Arduino.
Connect the WRST pin on the camera to pin 22 on the Arduino.
Connect the RRST pin on the camera to pin 23 on the Arduino.
Connect the WR pin on the camera to pin 24 on the Arduino.
Connect the VSYNC pin on the camera to pin 25 on the Arduino.
Connect the RCLK pin on the camera to pin 26 on the Arduino.
Connect the OE pin on the camera to one of the GND (Ground) pins on the Arduino.
Connect the D7 pin on the camera to pin 28 on the Arduino.
Connect the D6 pin on the camera to pin 29 on the Arduino.
Connect the D5 pin on the camera to pin 30 on the Arduino.
Connect the D4 pin on the camera to pin 31 on the Arduino.
Connect the D3 pin on the camera to pin 32 on the Arduino.
Connect the D2 pin on the camera to pin 33 on the Arduino.
Connect the D1 pin on the camera to pin 34 on the Arduino.
Connect the D0 pin on the camera to pin 35 on the Arduino.
See Figures 6-4 and 6-5 for a visual description of the connections required.
Figure 6-4.
Connecting the camera to the Arduino
The user definable pins on the Arduino side for the camera are in Listing 6-1. For
example, the WRST pin is defined on the Arduino as pin 22 and is connected to the
WRST pin on the camera. The RRST pin is defined on the Arduino as pin 23 and is
connected to the RRST pin on the camera.
Listing 6-1. User definable pins in our image capture code
// Camera input/output pin connection to Arduino
#define WRST 22 // Output Write Pointer Reset
#define RRST 23 // Output Read Pointer Reset
#define WEN 24 // Output Write Enable
#define VSYNC 25 // Input Vertical Sync marking frame capture
#define RCLK 26 // Output FIFO buffer output clock
// FIFO Ram input pins
#define DO7 28
#define DO6 29
#define DO5 30
#define DO4 31
#define DO3 32
#define DO2 33
#define DO1 34 #define DO0 35
This section discusses the image capture software. The official web site is listed followed
by a listing of the various software commands.
testread - Tests reading files from the SD card by reading and printing the contents of
test.txt that was generated by the testwrite command. The text output of this command
should be something similar to:
TEST.TXT:
TEST CAMERA SDCARD HOOKUP At Time 25 Seconds
Photo Info Filename: QQVGA0.txt
Photo Info:QQVGA ThirtyFPS SAWB HistAEC YUVMatrixOn DenoiseNo EdgeNo
AblcON
testwrite - Tests writing files to the SD card under the filename test.txt. The text output
from this command is Writing to testfile Writing File Done
Help Commands
help Displays help menu
help camera - Displays Cameras Commands and Parameters
The purpose of this section is to demonstrate how to take photos with the ov7670 camera
using my image capture software.
The recommended setup of the camera is shown in Figure 6-6 with the camera hanging
over the edge of the table so that there is no strain placed on the cameras wires.
IMPORTANT: Take note of how the camera hangs over the side of the table so that there
is no strain on the wires going into the Arduino pins from the camera. I have noticed that
when I try to take pictures when I move the camera to a level position and thus put strain
on the wires, many times I get an incorrect garbled photo.
Figure 6-6. Recommended camera setup
1. First you will need to download and uncompress the image capture program using a
program like 7-zip.
Note: 7 zip is a free program that is available at: http://www.7-zip.org
2. Start the Arduino IDE and load in the image capture program you just downloaded and
uncompressed.
3. Connect your Arduino Mega 2560 to your computer. Also make sure the SD card is
pushed firmly into the SD card readers slot until there is a click. It is also a good idea to
check that the SD card reader is working properly by using the testread and testwrite
commands. You should first use testwrite to have the Arduino write out a file called
test.txt to the SD card. Then, use the testread command to read back the file and print
its contents out to the screen.
4. Click the Upload button on the Arduino IDE to upload the image capture program to
your Arduino.
5. Wait until the program has finished uploading.
6. Click the Serial Monitor button to bring up the serial monitor.
7. The program should begin to initialize and produce the following output on the Serial
Monitor window.
Arduino SERIAL_MONITOR_CONTROLLED CAMERA Using ov7670 Camera
Camera Registers
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
CLKRC = 80
COM7 = 0
COM3 = 0
COM14 = 0
SCALING_XSC = 3A
SCALING_YSC = 35
SCALING_DCWCTR = 11
SCALING_PCLK_DIV = 0
SCALING_PCLK_DELAY = 2
TSLB (YUV Order- Higher Bit, Bit[3]) = D
COM13 (YUV Order - Lower Bit, Bit[1]) = 88
COM17 (DSP Color Bar Selection) = 0
COM4 (works with COM 17) = 0
COM15 (COLOR FORMAT SELECTION) = C0
COM11 (Night Mode) = 0
COM8 (Color Control, AWB) = 8F
HAECC7 (AEC Algorithm Selection) = 14
GFIX = 0
HSTART = 11
HSTOP = 61
HREF = 80
VSTRT = 3 VSTOP = 7B
VREF = 0
In SetupCamera()
Initializing OV7670 Camera
FINISHED INITIALIZING CAMERA
Initializing SD cardWiring is correct and a card is present
Omnivision ov7670 Camera Image Capture Software Version 1.0
Copyright 2015 by Robert Chin. All Rights Reserved.
Type h or help for main help menu Ready to Accept new Command =>
8. Now lets take a photo by sending a t to the Arduino via the Serial Monitor. Since the
default is set to take pictures in QQVGA mode the picture that is taken will be of QQVGA
resolution. The following should appear in the output window. Figure 6-7 and Figure 6-8
shows you some photos that I took in QQVGA format.
Important Note: The default focus of the camera may need adjustment. After taking this
first picture transfer the image to your computer and then convert it into an easily
viewable image file using ffmpeg (please see the section on ffmpeg in this chapter). Look
at the image and see if it is in focus. If it is not then you will need to adjust the cameras
focus by turning the lens. Take another picture. If the new picture is clearer than the old
one then you are turning the lens in the right direction. If it is less focused then turn the
cameras lens in the opposite direction. Continue taking photos, checking the sharpness of
the picture, and then adjusting the camera lens until you get a clear picture.
Ready to Accept new Command =>
Raw Command from Serial Monitor: t Going to take photo with current command:
Current Command:
Command: QQVGA
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOn
DenoiseParam: DenoiseNo
EdgeParam: EdgeNo
ABLCParam: AblcON
Taking a QQVGA Photo
Setting Camera for QQVGA YUV
Photo Width = 160
Photo Height = 120
Bytes Per Pixel = 2
.. Setting Basic QQVGA Parameters ..
CLKRC: I2C Operation OK
COM7: I2C Operation OK
COM3: I2C Operation OK
COM14: I2C Operation OK
SCALING_XSC: I2C Operation OK
SCALING_YSC: I2C Operation OK
SCALING_DCWCTR: I2C Operation OK
SCALING_PCLK_DIV: I2C Operation OK
SCALING_PCLK_DELAY: I2C Operation OK
TSLB: I2C Operation OK COM13: I2C Operation OK
COM17: I2C Operation OK
.. Setting Camera to 30 FPS ..
CLKRC: I2C Operation OK
DBLV: I2C Operation OK
EXHCH: I2C Operation OK
EXHCL: I2C Operation OK
DM_LNL: I2C Operation OK
DM_LNH: I2C Operation OK
COM11: I2C Operation OK
Setting Camera Histogram Based AEC/AGC Registers
AEW: I2C Operation OK
AEB: I2C Operation OK
HAECC1: I2C Operation OK
HAECC2: I2C Operation OK
HAECC3: I2C Operation OK
HAECC4: I2C Operation OK
HAECC5: I2C Operation OK
HAECC6: I2C Operation OK
HAECC7: I2C Operation OK
.. Setting Camera to Simple AWB ..
COM8(0x13): I2C Operation OK
AWBCTR0 Control Register 0(0x6F): I2C Operation OK
.. Setting Camera Gain ..
COM9: I2C Operation OK
BLUE GAIN: I2C Operation OK
RED GAIN: I2C Operation OK
GREEN GAIN: I2C Operation OK COM16(ENABLE GAIN): I2C Operation OK
.. Setting Camera Undocumented Registers ..
Setting B0 UNDOCUMENTED register to 0x84:= I2C Operation OK
.. Setting Camera Color Matrix for YUV ..
MTX1: I2C Operation OK
MTX2: I2C Operation OK
MTX3: I2C Operation OK
MTX4: I2C Operation OK
MTX5: I2C Operation OK
MTX6: I2C Operation OK
CONTRAS: I2C Operation OK
MTXS: I2C Operation OK
.. Setting Camera Saturation Level ..
SATCTR: I2C Operation OK
.. Setting Camera Array Control ..
CHLF: I2C Operation OK
ARBLM: I2C Operation OK
.. Setting Camera ADC Control ..
ADCCTR1: I2C Operation OK
ADCCTR2: I2C Operation OK
ADC: I2C Operation OK
ACOM: I2C Operation OK
OFON: I2C Operation OK
.. Setting Camera ABLC .
ABLC1: I2C Operation OK
THL_ST: I2C Operation OK
.. Setting Camera Window Output Parameters ..
HSTART: I2C Operation OK HSTOP: I2C Operation OK
HREF: I2C Operation OK
VSTRT: I2C Operation OK
VSTOP: I2C Operation OK
VREF: I2C Operation OK
Camera Registers
CLKRC = 80
COM7 = 0
COM3 = 4
COM14 = 1A
SCALING_XSC = 3A
SCALING_YSC = 35
SCALING_DCWCTR = 22
SCALING_PCLK_DIV = F2
SCALING_PCLK_DELAY = 2
TSLB (YUV Order- Higher Bit, Bit[3]) = 0
COM13 (YUV Order - Lower Bit, Bit[1]) = C8
COM17 (DSP Color Bar Selection) = 0
COM4 (works with COM 17) = 0
COM15 (COLOR FORMAT SELECTION) = C0
COM11 (Night Mode) = A
COM8 (Color Control, AWB) = E7
HAECC7 (AEC Algorithm Selection) = 94
GFIX = 0
HSTART = 13
HSTOP = 1
HREF = A4
VSTRT = 2 VSTOP = 7A
VREF = A
9. Next, lets take some QVGA photos. Send the value qvga to the Arduino using the
Serial Monitor. The command should be ackowledged, camera registers should be reset,
and the new camera command with parameters should be displayed. You should see
output similar to the following:
Ready to Accept new Command =>
Raw Command from Serial Monitor: qvga
Changing command or parameters according to your input:
Command or parameter qvga sucessfully set
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
Current Command:
Command: QVGA
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOn
DenoiseParam: DenoiseNo
EdgeParam: EdgeNo
ABLCParam: AblcON
10. To take a photo send the Arduino a t value. The command should be acknowledged,
the current camera command with parameters should be displayed, a detailed breakdown
of the exact camera register write operations being performed is displayed, a printout of
the resulting changes in key registers and information regarding the saving of the photo to
the SD Card is displayed. Some photos that I have taken are shown in Figure 6-9 and
Figure 6-10. You should see output similar to the following:
Ready to Accept new Command =>
Raw Command from Serial Monitor: t
Going to take photo with current command:
Current Command:
Command: QVGA
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOn
DenoiseParam: DenoiseNo
EdgeParam: EdgeNo
ABLCParam: AblcON
Taking a QVGA Photo
Setting Camera for QVGA (YUV)
Photo Width = 320
Photo Height = 240
Bytes Per Pixel = 2
CLKRC: I2C Operation OK
COM7: I2C Operation OK
COM3: I2C Operation OK
COM14: I2C Operation OK SCALING_XSC: I2C Operation OK
SCALING_YSC: I2C Operation OK
SCALING_DCWCTR: I2C Operation OK
SCALING_PCLK_DIV: I2C Operation OK
SCALING_PCLK_DELAY: I2C Operation OK
TSLB: I2C Operation OK
COM13: I2C Operation OK
COM17: I2C Operation OK
.. Setting Camera to 30 FPS ..
CLKRC: I2C Operation OK
DBLV: I2C Operation OK
EXHCH: I2C Operation OK
EXHCL: I2C Operation OK
DM_LNL: I2C Operation OK
DM_LNH: I2C Operation OK
COM11: I2C Operation OK
Setting Camera Histogram Based AEC/AGC Registers
AEW: I2C Operation OK
AEB: I2C Operation OK
HAECC1: I2C Operation OK
HAECC2: I2C Operation OK
HAECC3: I2C Operation OK
HAECC4: I2C Operation OK
HAECC5: I2C Operation OK
HAECC6: I2C Operation OK
HAECC7: I2C Operation OK
.. Setting Camera to Simple AWB ..
COM8(0x13): I2C Operation OK AWBCTR0 Control Register 0(0x6F): I2C Operation
OK
.. Setting Camera Gain ..
COM9: I2C Operation OK
BLUE GAIN: I2C Operation OK
RED GAIN: I2C Operation OK
GREEN GAIN: I2C Operation OK
COM16(ENABLE GAIN): I2C Operation OK
.. Setting Camera Undocumented Registers ..
Setting B0 UNDOCUMENTED register to 0x84:= I2C Operation OK
.. Setting Camera Color Matrix for YUV ..
MTX1: I2C Operation OK
MTX2: I2C Operation OK
MTX3: I2C Operation OK
MTX4: I2C Operation OK
MTX5: I2C Operation OK
MTX6: I2C Operation OK
CONTRAS: I2C Operation OK
MTXS: I2C Operation OK
.. Setting Camera Saturation Level ..
SATCTR: I2C Operation OK
.. Setting Camera Array Control ..
CHLF: I2C Operation OK
ARBLM: I2C Operation OK
.. Setting Camera ADC Control ..
ADCCTR1: I2C Operation OK
ADCCTR2: I2C Operation OK
ADC: I2C Operation OK
ACOM: I2C Operation OK OFON: I2C Operation OK
.. Setting Camera ABLC .
ABLC1: I2C Operation OK
THL_ST: I2C Operation OK
.. Setting Camera Window Output Parameters ..
HSTART: I2C Operation OK
HSTOP: I2C Operation OK
HREF: I2C Operation OK
VSTRT: I2C Operation OK
VSTOP: I2C Operation OK
VREF: I2C Operation OK
Camera Registers
CLKRC = 80
COM7 = 0
COM3 = 4
COM14 = 19
SCALING_XSC = 3A
SCALING_YSC = 35
SCALING_DCWCTR = 11
SCALING_PCLK_DIV = F1
SCALING_PCLK_DELAY = 2
TSLB (YUV Order- Higher Bit, Bit[3]) = 4
COM13 (YUV Order - Lower Bit, Bit[1]) = C2
COM17 (DSP Color Bar Selection) = 0
COM4 (works with COM 17) = 0
COM15 (COLOR FORMAT SELECTION) = C0
COM11 (Night Mode) = A
COM8 (Color Control, AWB) = E7 HAECC7 (AEC Algorithm Selection) = 94
GFIX = 0
HSTART = 13
HSTOP = 1
HREF = 24
VSTRT = 2
VSTOP = 7A
VREF = A
13. Next, lets try to take a photo using the processed VGA mode. Send the command
vgap to the Arduino to change the camera command settings. The command should be
confirmed, the cameras registers should be reset, and the current command should be
displayed. You should see something like the following:
Ready to Accept new Command =>
Raw Command from Serial Monitor: vgap
Changing command or parameters according to your input:
Command or parameter vgap sucessfully set
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
Current Command:
Command: VGAP
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOff
DenoiseParam: DenoiseNo
EdgeParam: EdgeNo ABLCParam: AblcON
14. Now, send the Arduino the t command to actually take the photo. The current
camera settings should be displayed, a detailed list of register setting operations should be
displayed, the contents of key registers are displayed, and SD card related information is
displayed. See Figure 6-12 for a photo I took using these camera settings. You should see
output similar to the following:
Ready to Accept new Command =>
Raw Command from Serial Monitor: t
Going to take photo with current command:
Current Command:
Command: VGAP FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOff
DenoiseParam: DenoiseNo
EdgeParam: EdgeNo
ABLCParam: AblcON
Taking a VGAP Photo
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
Setting Camera for VGA (Raw RGB)
Photo Width = 640
Photo Height = 480
Bytes Per Pixel = 1
CLKRC: I2C Operation OK
COM7: I2C Operation OK
COM3: I2C Operation OK
COM14: I2C Operation OK
SCALING_XSC: I2C Operation OK
SCALING_YSC: I2C Operation OK
SCALING_DCWCTR: I2C Operation OK
SCALING_PCLK_DIV: I2C Operation OK
SCALING_PCLK_DELAY: I2C Operation OK
COM17: I2C Operation OK
.. Setting Camera to 30 FPS ..
CLKRC: I2C Operation OK
DBLV: I2C Operation OK
EXHCH: I2C Operation OK EXHCL: I2C Operation OK
DM_LNL: I2C Operation OK
DM_LNH: I2C Operation OK
COM11: I2C Operation OK
Setting Camera Histogram Based AEC/AGC Registers
AEW: I2C Operation OK
AEB: I2C Operation OK
HAECC1: I2C Operation OK
HAECC2: I2C Operation OK
HAECC3: I2C Operation OK
HAECC4: I2C Operation OK
HAECC5: I2C Operation OK
HAECC6: I2C Operation OK
HAECC7: I2C Operation OK
Setting B0 UNDOCUMENTED register to 0x84:= I2C Operation OK
.. Setting Camera Saturation Level ..
SATCTR: I2C Operation OK
.. Setting Camera Array Control ..
CHLF: I2C Operation OK
ARBLM: I2C Operation OK
.. Setting Camera ADC Control ..
ADCCTR1: I2C Operation OK
ADCCTR2: I2C Operation OK
ADC: I2C Operation OK
ACOM: I2C Operation OK
OFON: I2C Operation OK
.. Setting Camera ABLC .
ABLC1: I2C Operation OK THL_ST: I2C Operation OK
.. Setting Camera Window Output Parameters ..
HSTART: I2C Operation OK
HSTOP: I2C Operation OK
HREF: I2C Operation OK
VSTRT: I2C Operation OK
VSTOP: I2C Operation OK
VREF: I2C Operation OK
- Setting Camera for VGA (Processed Bayer RGB)
COM7: I2C Operation OK
Initializing TSLB register result = I2C Operation OK
Setting B0 UNDOCUMENTED register to 0x84:= I2C Operation OK
.. Setting Camera to Simple AWB ..
COM8(0x13): I2C Operation OK
AWBCTR0 Control Register 0(0x6F): I2C Operation OK
.. Setting Camera Gain ..
COM9: I2C Operation OK
BLUE GAIN: I2C Operation OK
RED GAIN: I2C Operation OK
GREEN GAIN: I2C Operation OK
COM16(ENABLE GAIN): I2C Operation OK
Camera Registers
CLKRC = 80
COM7 = 5
COM3 = 0
COM14 = 0
SCALING_XSC = 3A
SCALING_YSC = 35 SCALING_DCWCTR = 11
SCALING_PCLK_DIV = F0
SCALING_PCLK_DELAY = 2
TSLB (YUV Order- Higher Bit, Bit[3]) = 4
COM13 (YUV Order - Lower Bit, Bit[1]) = 88
COM17 (DSP Color Bar Selection) = 0
COM4 (works with COM 17) = 0
COM15 (COLOR FORMAT SELECTION) = C0
COM11 (Night Mode) = A
COM8 (Color Control, AWB) = E7
HAECC7 (AEC Algorithm Selection) = 94
GFIX = 0
HSTART = 13
HSTOP = 1
HREF = B6
VSTRT = 2
VSTOP = 7A
VREF = A
17. Next, switch to VGA by sending vga to the Arudino. The command should be
confirmed, the camera registers should be reset and the current camera settings should be
displayed as in the following output:
Ready to Accept new Command =>
Raw Command from Serial Monitor: vga
Changing command or parameters according to your input:
Command or parameter vga sucessfully set
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
Current Command:
Command: VGA
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOff
DenoiseParam: DenoiseNo
EdgeParam: EdgeYes
ABLCParam: AblcON
18. Next, take a photo by sending a t character to the Arduino. The current camera
settings should be displayed, the camera registers are set to the required values, the values
of key camera registers are displayed and photo file information is displayed. See 6-14 for
a photo I took using these camera settings. The text output should look similar to the
following:
Ready to Accept new Command =>
Raw Command from Serial Monitor: t
Going to take photo with current command:
Current Command: Command: VGA
FPSParam: ThirtyFPS
AWBParam: SAWB
AECParam: HistAEC
YUVMatrixParam: YUVMatrixOff
DenoiseParam: DenoiseNo
EdgeParam: EdgeYes
ABLCParam: AblcON
Taking a VGA Photo
RESETTING ALL REGISTERS BY SETTING COM7 REGISTER to 0x80: I2C
Operation OK
Setting Camera for VGA (Raw RGB)
Photo Width = 640
Photo Height = 480
Bytes Per Pixel = 1
CLKRC: I2C Operation OK
COM7: I2C Operation OK
COM3: I2C Operation OK
COM14: I2C Operation OK
SCALING_XSC: I2C Operation OK
SCALING_YSC: I2C Operation OK
SCALING_DCWCTR: I2C Operation OK
SCALING_PCLK_DIV: I2C Operation OK
SCALING_PCLK_DELAY: I2C Operation OK
COM17: I2C Operation OK
.. Setting Camera to 30 FPS ..
CLKRC: I2C Operation OK
DBLV: I2C Operation OK EXHCH: I2C Operation OK
EXHCL: I2C Operation OK
DM_LNL: I2C Operation OK
DM_LNH: I2C Operation OK
COM11: I2C Operation OK
Setting Camera Histogram Based AEC/AGC Registers
AEW: I2C Operation OK
AEB: I2C Operation OK
HAECC1: I2C Operation OK
HAECC2: I2C Operation OK
HAECC3: I2C Operation OK
HAECC4: I2C Operation OK
HAECC5: I2C Operation OK
HAECC6: I2C Operation OK
HAECC7: I2C Operation OK
Setting B0 UNDOCUMENTED register to 0x84:= I2C Operation OK
.. Setting Camera Saturation Level ..
SATCTR: I2C Operation OK
.. Setting Camera Array Control ..
CHLF: I2C Operation OK
ARBLM: I2C Operation OK
.. Setting Camera ADC Control ..
ADCCTR1: I2C Operation OK
ADCCTR2: I2C Operation OK
ADC: I2C Operation OK
ACOM: I2C Operation OK
OFON: I2C Operation OK
.. Setting Camera ABLC . ABLC1: I2C Operation OK
THL_ST: I2C Operation OK
.. Setting Camera Window Output Parameters ..
HSTART: I2C Operation OK
HSTOP: I2C Operation OK
HREF: I2C Operation OK
VSTRT: I2C Operation OK
VSTOP: I2C Operation OK
VREF: I2C Operation OK
Camera Registers
CLKRC = 80
COM7 = 1
COM3 = 0
COM14 = 0
SCALING_XSC = 3A
SCALING_YSC = 35
SCALING_DCWCTR = 11
SCALING_PCLK_DIV = F0
SCALING_PCLK_DELAY = 2
TSLB (YUV Order- Higher Bit, Bit[3]) = D
COM13 (YUV Order - Lower Bit, Bit[1]) = 88
COM17 (DSP Color Bar Selection) = 0
COM4 (works with COM 17) = 0
COM15 (COLOR FORMAT SELECTION) = C0
COM11 (Night Mode) = A
COM8 (Color Control, AWB) = 8F
HAECC7 (AEC Algorithm Selection) = 94
GFIX = 0 HSTART = 13
HSTOP = 1
HREF = B6
VSTRT = 2
VSTOP = 7A
VREF = A
In order to transfer your photos from the SD card to your computer for final processing
you will need another SD card reader designed to work with your computer.
I purchased the Transcend Information USB 3.0 Card Reader (TS-RDF5K) from
Amazon.com to transfer my files to my Windows based PC. See Figure 6-15. There were
some reviews complaining of overheating after use but I did not encounter any problems
with excessive heating of the SD card reader.
You will need to stick your SD card into the slot marked as SD. Then stick the SD card
reader into an available USB slot on your computer. The computer should recognize the
SD card reader as just another disk drive. You can use the Windows Explorer to copy files
from the SD card to a folder on your hard disk drive.
Figure 6-15. SD card reader for PC
Once you get your files to your computer you will need to convert these files to a form
that is easily readable and viewable such as the PNG image format. To do this you will
need a program called ffmpeg.
The official web site for the ffmpeg program is
https://www.ffmpeg.org/
You should go there and download the latest version for your computer system. It is free
and available at no charge.
Note: The ffmpeg version I used for this book is 2015-03-12 git-3bedc99. If you are
having problems converting the camera images into a viewable PNG file then try to
download this version of ffmpeg.
FFMPEG CONVERSION
This section describes the ffmpeg command line options that are required to convert the
images into an easily viewable format. The images from the camera that are recorded in
YUV and Raw Bayer format are converted to PNG files. PNG stands for portable network
graphics file which is a common image file type that can be viewed in Windows Explorer
or though a paint program like Paint Shop Pro.
Note: For each of the following commands replace INPUTFILE.YUV or
INPUTFILE.RAW with the actual filename of the YUV file or Bayer RAW file you want
to covert. Change the OUTPUTFILE.PNG filename to the filename you want to save the
new image as.
QQVGA
ffmpeg -f rawvideo -s 160x120 -pix_fmt yuyv422 -i INPUTFILE.YUV -f image2 -vcodec
png OUTPUTFILE.PNG
QVGA ffmpeg -f rawvideo -s 320x240 -pix_fmt yuyv422 -i INPUTFILE.YUV -f image2
-vcodec png OUTPUTFILE.PNG
VGA ffmpeg -f rawvideo -s 640x480 -pix_fmt bayer_bggr8 -i INPUTFILE.RAW -f
image2 -vcodec png OUTPUTFILE.PNG
An easy way to convert the files is to copy the image files into the same directory where
your ffmpeg.exe is located. Then you can create a directory such as outputdir to hold the
processed images. Based on the image filename you can choose one of the commands
below to convert the file and to place the converted image file into a directory.
Note: Replace the outputdir name with the name of the directory that you want to save
the converted file in.
QQVGA ffmpeg -f rawvideo -s 160x120 -pix_fmt yuyv422 -i INPUTFILE.YUV -f
image2 -vcodec png outputdir\OUTPUTFILE.PNG
QVGA ffmpeg -f rawvideo -s 320x240 -pix_fmt yuyv422 -i INPUTFILE.YUV -f image2
-vcodec png outputdir\OUTPUTFILE.PNG
VGA ffmpeg -f rawvideo -s 640x480 -pix_fmt bayer_bggr8 -i INPUTFILE.RAW -f
image2 -vcodec png outputdir\OUTPUTFILE.PNG
Summary
This chapter provided a quick start guide to taking photos with the ov7670 camera and
saving them using a SD card. SD card reader connections and camera connections to the
Arduino are shown. The image capture software is discussed and step by step instructions
on how to use it are given. Then I show how to transfer these photos to your computer and
then convert them into viewable images.
Appendix A: Camera Register Defines
This appendix lists the #defines related to the camera registers.
// Register addresses and values
#define CLKRC 0x11
#define CLKRC_VALUE_VGA 0x01 // Raw Bayer
#define CLKRC_VALUE_QVGA 0x01
#define CLKRC_VALUE_QQVGA 0x01
#define CLKRC_VALUE_NIGHTMODE_FIXED 0x03 // Fixed Frame
#define CLKRC_VALUE_NIGHTMODE_AUTO 0x80 // Auto Frame Rate Adjust
#define COM7 0x12
#define COM7_VALUE_VGA 0x01 // Raw Bayer
#define COM7_VALUE_VGA_COLOR_BAR 0x03 // Raw Bayer
#define COM7_VALUE_VGA_PROCESSED_BAYER 0x05 // Processed Bayer
#define COM7_VALUE_QVGA 0x00
#define COM7_VALUE_QVGA_COLOR_BAR 0x02
#define COM7_VALUE_QVGA_PREDEFINED_COLOR_BAR 0x12
#define COM7_VALUE_QQVGA 0x00
#define COM7_VALUE_QQVGA_COLOR_BAR 0x02
#define COM7_VALUE_RESET 0x80
#define COM3 0x0C
#define COM3_VALUE_VGA 0x00 // Raw Bayer
#define COM3_VALUE_QVGA 0x04 #define COM3_VALUE_QQVGA 0x04 // From
Docs
#define COM3_VALUE_QQVGA_SCALE_ENABLED 0x0C // Enable Scale and DCW
#define COM14 0x3E
#define COM14_VALUE_VGA 0x00 // Raw Bayer
#define COM14_VALUE_QVGA 0x19
#define COM14_VALUE_QQVGA 0x1A
#define COM14_VALUE_MANUAL_SCALING 0x08 // Manual Scaling Enabled
#define COM14_VALUE_NO_MANUAL_SCALING 0x00 // Manual Scaling
DisEnabled
#define SCALING_XSC 0x70
#define SCALING_XSC_VALUE_VGA 0x3A // Raw Bayer
#define SCALING_XSC_VALUE_QVGA 0x3A
#define SCALING_XSC_VALUE_QQVGA 0x3A
#define SCALING_XSC_VALUE_QQVGA_SHIFT1 0x3A
#define SCALING_XSC_VALUE_COLOR_BAR 0xBA
#define SCALING_YSC 0x71
#define SCALING_YSC_VALUE_VGA 0x35 // Raw Bayer
#define SCALING_YSC_VALUE_QVGA 0x35
#define SCALING_YSC_VALUE_QQVGA 0x35
#define SCALING_YSC_VALUE_COLOR_BAR 0x35 // 8 bar color bar
#define SCALING_YSC_VALUE_COLOR_BAR_GREY 0xB5 // fade to grey color bar
#define SCALING_YSC_VALUE_COLOR_BAR_SHIFT1 0xB5 // fade to grey color bar
#define SCALING_DCWCTR 0x72
#define SCALING_DCWCTR_VALUE_VGA 0x11 // Raw Bayer
#define SCALING_DCWCTR_VALUE_QVGA 0x11
#define SCALING_DCWCTR_VALUE_QQVGA 0x22
#define SCALING_PCLK_DIV 0x73
#define SCALING_PCLK_DIV_VALUE_VGA 0xF0 // Raw Bayer
#define SCALING_PCLK_DIV_VALUE_QVGA 0xF1
#define SCALING_PCLK_DIV_VALUE_QQVGA 0xF2
#define SCALING_PCLK_DELAY 0xA2
#define SCALING_PCLK_DELAY_VALUE_VGA 0x02 // Raw Bayer
#define SCALING_PCLK_DELAY_VALUE_QVGA 0x02
#define SCALING_PCLK_DELAY_VALUE_QQVGA 0x02
// Controls YUV order Used with COM13
// Need YUYV format for Android Decoding- Default value is 0xD
#define TSLB 0x3A
#define TSLB_VALUE_YUYV_AUTO_OUTPUT_WINDOW_ENABLED 0x01 // No
custom scaling
#define TSLB_VALUE_YUYV_AUTO_OUTPUT_WINDOW_DISABLED 0x00 // For
adjusting HSTART, etc. YUYV format
#define TSLB_VALUE_UYVY_AUTO_OUTPUT_WINDOW_DISABLED 0x08
#define TSLB_VALUE_TESTVALUE 0x04 // From YCbCr Reference
// Default value is 0x88
// ok if you want YUYV order, no need to change
#define COM13 0x3D
#define COM13_VALUE_DEFAULT 0x88
#define COM13_VALUE_NOGAMMA_YUYV 0x00
#define COM13_VALUE_GAMMA_YUYV 0x80
#define COM13_VALUE_GAMMA_YVYU 0x82
#define COM13_VALUE_YUYV_UVSATAUTOADJ_ON 0x40 // Works with COM4
#define COM17 0x42
#define COM17_VALUE_AEC_NORMAL_NO_COLOR_BAR 0x00
#define COM17_VALUE_AEC_NORMAL_COLOR_BAR 0x08 // Activate Color Bar
for DSP
#define COM4 0x0D
// RGB Settings and Data format
#define COM15 0x40
// Night Mode
#define COM11 0x3B
#define COM11_VALUE_NIGHTMODE_ON 0x80 // Night Mode
#define COM11_VALUE_NIGHTMODE_OFF 0x00
#define COM11_VALUE_NIGHTMODE_ON_EIGHTH 0xE0 // Night Mode 1/8 frame
rate minimum
#define COM11_VALUE_NIGHTMODE_FIXED 0x0A
#define COM11_VALUE_NIGHTMODE_AUTO 0xEA // Night Mode Auto Frame Rate
Adjust
// Color Matrix Control YUV
#define MTX1 0x4f
#define MTX1_VALUE 0x80
#define MTX2 0x50
#define MTX2_VALUE 0x80
#define MTX3 0x51
#define MTX3_VALUE 0x00 #define MTX4 0x52
#define MTX4_VALUE 0x22
#define MTX5 0x53
#define MTX5_VALUE 0x5e
#define MTX6 0x54
#define MTX6_VALUE 0x80
#define CONTRAS 0x56
#define CONTRAS_VALUE 0x40
#define MTXS 0x58
#define MTXS_VALUE 0x9e
// COM8
#define COM8 0x13
#define COM8_VALUE_AWB_OFF 0xE5
#define COM8_VALUE_AWB_ON 0xE7
// Automatic White Balance
#define AWBC1 0x43
#define AWBC1_VALUE 0x14
#define AWBC2 0x44
#define AWBC2_VALUE 0xf0
#define AWBC3 0x45
#define AWBC3_VALUE 0x34 #define AWBC4 0x46
#define AWBC4_VALUE 0x58
#define AWBC5 0x47
#define AWBC5_VALUE 0x28
#define AWBC6 0x48
#define AWBC6_VALUE 0x3a
#define AWBC7 0x59
#define AWBC7_VALUE 0x88
#define AWBC8 0x5A
#define AWBC8_VALUE 0x88
#define AWBC9 0x5B
#define AWBC9_VALUE 0x44
#define AWBC10 0x5C
#define AWBC10_VALUE 0x67
#define AWBC11 0x5D
#define AWBC11_VALUE 0x49
#define AWBC12 0x5E
#define AWBC12_VALUE 0x0E
#define AWBCTR3 0x6C #define AWBCTR3_VALUE 0x0A
#define AWBCTR2 0x6D
#define AWBCTR2_VALUE 0x55
#define AWBCTR1 0x6E
#define AWBCTR1_VALUE 0x11
#define AWBCTR0 0x6F
#define AWBCTR0_VALUE_NORMAL 0x9F
#define AWBCTR0_VALUE_ADVANCED 0x9E
// Gain
#define COM9 0x14
#define COM9_VALUE_MAX_GAIN_128X 0x6A
#define COM9_VALUE_4XGAIN 0x10 // 0001 0000
#define BLUE 0x01 // AWB Blue Channel Gain
#define BLUE_VALUE 0x40
#define RED 0x02 // AWB Red Channel Gain
#define RED_VALUE 0x40
#define GGAIN 0x6A // AWB Green Channel Gain
#define GGAIN_VALUE 0x40
#define COM16 0x41
#define COM16_VALUE 0x08 // AWB Gain on #define GFIX 0x69
#define GFIX_VALUE 0x00
// Edge Enhancement Adjustment
#define EDGE 0x3f
#define EDGE_VALUE 0x00
#define REG75 0x75
#define REG75_VALUE 0x03
#define REG76 0x76
#define REG76_VALUE 0xe1
// DeNoise
#define DNSTH 0x4c
#define DNSTH_VALUE 0x00
#define REG77 0x77
#define REG77_VALUE 0x00
// Denoise and Edge Enhancement
#define
COM16_VALUE_DENOISE_OFF_EDGE_ENHANCEMENT_OFF_AWBGAIN_ON
0x08 // Denoise off, AWB Gain on
#define
COM16_VALUE_DENOISE_ON__EDGE_ENHANCEMENT_OFF__AWBGAIN_ON
0x18
#define
COM16_VALUE_DENOISE_OFF__EDGE_ENHANCEMENT_ON__AWBGAIN_ON
0x28
#define
COM16_VALUE_DENOISE_ON__EDGE_ENHANCEMENT_ON__AWBGAIN_ON
0x38 // Denoise on, Edge Enhancement on, AWB Gain on
// 30FPS Frame Rate , PCLK = 24Mhz #define CLKRC_VALUE_30FPS 0x80
#define DBLV 0x6b
#define DBLV_VALUE_30FPS 0x0A
#define EXHCH 0x2A
#define EXHCH_VALUE_30FPS 0x00
#define EXHCL 0x2B
#define EXHCL_VALUE_30FPS 0x00
#define DM_LNL 0x92
#define DM_LNL_VALUE_30FPS 0x00
#define DM_LNH 0x93
#define DM_LNH_VALUE_30FPS 0x00
#define COM11_VALUE_30FPS 0x0A
// Saturation Control
#define SATCTR 0xc9
#define SATCTR_VALUE 0x60
// AEC/AGC - Automatic Exposure/Gain Control
#define GAIN 0x00
#define GAIN_VALUE 0x00
#define AEW 0x24
#define AEW_VALUE 0x95 #define AEB 0x25
#define AEB_VALUE 0x33
#define VPT 0x26
#define VPT_VALUE 0xe3
// AEC/AGC Control- Histogram
#define HAECC1 0x9f
#define HAECC1_VALUE 0x78
#define HAECC2 0xa0
#define HAECC2_VALUE 0x68
#define HAECC3 0xa6
#define HAECC3_VALUE 0xd8
#define HAECC4 0xa7
#define HAECC4_VALUE 0xd8
#define HAECC5 0xa8
#define HAECC5_VALUE 0xf0
#define HAECC6 0xa9
#define HAECC6_VALUE 0x90
#define HAECC7 0xaa // AEC Algorithm selection
#define HAECC7_VALUE_HISTOGRAM_AEC_ON 0x94
#define HAECC7_VALUE_AVERAGE_AEC_ON 0x00 // Array Control
#define CHLF 0x33
#define CHLF_VALUE 0x0b
#define ARBLM 0x34
#define ARBLM_VALUE 0x11
// ADC Control
#define ADCCTR1 0x21
#define ADCCTR1_VALUE 0x02
#define ADCCTR2 0x22
#define ADCCTR2_VALUE 0x91
#define ADC 0x37
#define ADC_VALUE 0x1d
#define ACOM 0x38
#define ACOM_VALUE 0x71
#define OFON 0x39
#define OFON_VALUE 0x2a
// Black Level Calibration
#define ABLC1 0xb1
#define ABLC1_VALUE 0x0c
#define THL_ST 0xb3 #define THL_ST_VALUE 0x82
// Window Output
#define HSTART 0x17
#define HSTART_VALUE_DEFAULT 0x11
#define HSTART_VALUE_VGA 0x13
#define HSTART_VALUE_QVGA 0x13
#define HSTART_VALUE_QQVGA 0x13 // Works
#define HSTOP 0x18
#define HSTOP_VALUE_DEFAULT 0x61
#define HSTOP_VALUE_VGA 0x01
#define HSTOP_VALUE_QVGA 0x01
#define HSTOP_VALUE_QQVGA 0x01 // Works
#define HREF 0x32
#define HREF_VALUE_DEFAULT 0x80
#define HREF_VALUE_VGA 0xB6
#define HREF_VALUE_QVGA 0x24
#define HREF_VALUE_QQVGA 0xA4
#define VSTRT 0x19
#define VSTRT_VALUE_DEFAULT 0x03
#define VSTRT_VALUE_VGA 0x02
#define VSTRT_VALUE_QVGA 0x02
#define VSTRT_VALUE_QQVGA 0x02
#define VSTOP 0x1A
#define VSTOP_VALUE_DEFAULT 0x7B #define VSTOP_VALUE_VGA 0x7A
#define VSTOP_VALUE_QVGA 0x7A
#define VSTOP_VALUE_QQVGA 0x7A
#define VREF 0x03
#define VREF_VALUE_DEFAULT 0x03
#define VREF_VALUE_VGA 0x0A
#define VREF_VALUE_QVGA 0x0A #define VREF_VALUE_QQVGA 0x0A
Appendix B: Image Capture Program
Variables
const int chipSelect = 48;
const int HardwareSSPin = 53; // For Arduino Mega
int PhotoTakenCount = 0;
// Serial Input
const int BUFFERLENGTH = 255;
char IncomingByte[BUFFERLENGTH]; // for incoming serial data
// VGA Default
int PHOTO_WIDTH = 640;
int PHOTO_HEIGHT = 480;
int PHOTO_BYTES_PER_PIXEL = 2;
// Command and Parameter related Strings
String RawCommandLine = ;
String Command = QQVGA;
String FPSParam = ThirtyFPS;
String AWBParam = SAWB;
String AECParam = HistAEC;
String YUVMatrixParam = YUVMatrixOn;
String DenoiseParam = DenoiseNo; String EdgeParam = EdgeNo;
String ABLCParam = AblcON;
enum ResolutionType
{
VGA,
VGAP,
QVGA,
QQVGA,
None
};
ResolutionType Resolution = None;
// Camera input/output pin connection to Arduino
#define WRST 22 // Output Write Pointer Reset
#define RRST 23 // Output Read Pointer Reset
#define WEN 24 // Output Write Enable
#define VSYNC 25 // Input Vertical Sync marking frame capture
#define RCLK 26 // Output FIFO buffer output clock
// set OE to low gnd
// FIFO Ram input pins
#define DO7 28
#define DO6 29
#define DO5 30
#define DO4 31
#define DO3 32
#define DO2 33
#define DO1 34 #define DO0 35
// I2C
#define OV7670_I2C_ADDRESS 0x21
#define I2C_ERROR_WRITING_START_ADDRESS 11
#define I2C_ERROR_WRITING_DATA 22
#define DATA_TOO_LONG 1 // data too long to fit in transmit buffer
#define NACK_ON_TRANSMIT_OF_ADDRESS 2 // received NACK on transmit of
address
#define NACK_ON_TRANSMIT_OF_DATA 3 // received NACK on transmit of data
#define OTHER_ERROR 4 // other error
#define I2C_READ_START_ADDRESS_ERROR 33
#define I2C_READ_DATA_SIZE_MISMATCH_ERROR 44