/****************************************************
QVGA and ILI9341 test program for OV7670 library
Transfers a QVGA image to ILI9341 TFT screen
Capable of 15.0 Frames per second
This code takes advantage of the fact that the
OV7670 in QVGA mode matches the 320x240 pixels
of the ILI9341
requires T4.1 and saves frames in DMAMEM
which means that you do not need PSRAM
******************************************************** */
#include <OV7670.h>
#include <ILI9341_t3n.h>
//Specify the pins used for Non-SPI functions
#define TFT_CS 10 // AD_B0_02
#define TFT_DC 9 // AD_B0_03
#define TFT_RST 8
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST);
const int imarkpin = 32; // used for o'scope frame rate timing
#define IMARKHI digitalWriteFast(imarkpin, HIGH); // Also marks IRQ handler timing
#define IMARKLO digitalWriteFast(imarkpin, LOW);
#define IMARKTOGGLE digitalToggleFast(imarkpin);
// Put all the buffers in DMAMEM
uint8_t image[320l * 240l * 2] DMAMEM;
uint8_t cbuff1[320l * 240l * 2] DMAMEM;
uint8_t cbuff2[320l * 240l * 2] DMAMEM;
const char compileTime [] = " Compiled on " __DATE__ " " __TIME__;
const int pinCamReset = 14;
void setup() {
Serial.begin(9600);
delay(200);
Wire.begin();
pinMode(pinCamReset, OUTPUT);
pinMode(imarkpin, OUTPUT);
digitalWriteFast(pinCamReset, LOW);
delay(10);
digitalWriteFast(pinCamReset, HIGH); // subsequent resets via SCB
if (OV7670.begin(QVGA, cbuff1, cbuff2)) {
Serial.println("OV7670 camera initialized.");
Serial.printf("cbuff1 at %p\n", cbuff1);
Serial.printf("cbuff2 at %p\n", cbuff2);
} else {
Serial.println("Error initializing OV7670");
}
// 12 MHz gives 15FPS. 16MHz will do 20FPS, but leaves little time
// for anything but video display.
OV7670.SetCamClock(12);
// Start ILI9341
tft.begin();
tft.setRotation(3); // Need rot = 3 for right-side up on MJB proto board
CMSI();
CMGV(); // Jump right into video, so you don't even need a terminal!
}
void loop() {
// Only 3 choices: 's' System Info 'f' capture single frame 'v' video to TFT
char ch;
if (Serial.available()) {
ch = Serial.read();
if (ch == 's') CMSI();
if (ch == 'v') CMGV();
if (ch == 'f') CMGF();
}
}
void CMSI(void) {
Serial.printf("\n\nOV7670 Camera and ILI9341 QVGA Test 3 %s\n", compileTime);
OV7670.ShowCamConfig();
}
// display QVGA video. CSI and ILI9341_t3n.h can keep up at 15 Frames Per Second
void CMGV(void){
Serial.println("Press any key to halt video");
do{
CMGF();
delayMicroseconds(10);
}while(!Serial.available()); // Serial input sends you back to loop()
}
// Capture and display a single frame from OV7670
void CMGF(void) {
uint16_t readyframe;
uint32_t imagesize;
imagesize = OV7670.ImageSize();
uint16_t lastframe = OV7670.FrameReady();
do {
readyframe = OV7670.FrameReady();
} while (readyframe == lastframe); // wait until a frame just completed
// copy the frame to image buffer to prevent tearing and glitches
if (readyframe == 2) memcpy(image, cbuff2, imagesize);
if (readyframe == 1) memcpy(image, cbuff1, imagesize);
// display the frame. Seems simple---until you look behind the curtain!
// That's where KurtE does the hard work!
IMARKHI
tft.writeRect(0, 0, tft.width(), tft.height(), (uint16_t *)&image);
// This takes about 42mSec-thus the 15FPS setting
IMARKLO
}