I'm using an OV5642 with an Arduino Nano 33 IoT. I would like to get multiple frames per second streamed over WiFi, but so far, I have very high capture times between 1s and 2s. So, I'm very far from the advertised FPS. I am not hoping for a high fps, but at least 10 or 15 fps to get a relative sense of fluidity.
I use the following code:
#include <Wire.h>
#include <WiFiNINA.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"
#include "secrets.h"
/* WiFi setup */
char ssid[] = SECRET_SSID; // network SSID (name)
char pass[] = SECRET_PASS; // network password
int status = WL_IDLE_STATUS; // the WiFi radio's status
const int SERVER_PORT = 80;
WiFiServer server(SERVER_PORT);
/* Arducam setup */
#if !(defined (OV5640_MINI_5MP_PLUS)||defined (OV5642_MINI_5MP_PLUS))
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
// set pin 7 as the slave select for the digital pot:
const int CS = 7;
static const size_t bufferSize = 2048;
static uint8_t buffer[bufferSize] = {0xFF};
int i = 0;
bool is_header = false;
uint8_t start_capture = 0;
ArduCAM camera(OV5642, CS);
uint8_t read_fifo_burst(ArduCAM camera);
void connectNetwork() {
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass);
delay(10000); // wait for connection
}
Serial.print("Connected. ");
server.begin();
IPAddress ip = WiFi.localIP();
Serial.print("Started serving on http://");
Serial.print(ip);
Serial.print(":");
Serial.println(SERVER_PORT);
}
void setupArducam() {
uint8_t vid, pid;
uint8_t temp;
Wire.begin();
// Configure CS
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
// Initialize SPI
SPI.begin();
//Reset the CPLD
camera.write_reg(0x07, 0x80);
delay(100);
camera.write_reg(0x07, 0x00);
delay(100);
while(1) {
//Check if the ArduCAM SPI bus is OK
camera.write_reg(ARDUCHIP_TEST1, 0x55);
temp = camera.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55)
{
Serial.println(F("Arducam SPI interface Error!"));
delay(1000);
continue;
} else {
Serial.println(F("Arducam SPI interface OK"));
break;
}
}
while(1){
// Check if the camera module type is OV5642
camera.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid);
camera.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid);
if ((vid != 0x56) || (pid != 0x42)){
Serial.println(F("Can't find OV5642 module!"));
delay(1000);
continue;
} else {
Serial.println(F("OV5642 detected"));
break;
}
}
//Change to JPEG capture mode and initialize the OV5642 module
camera.set_format(JPEG);
camera.InitCAM();
camera.set_bit(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);
camera.clear_fifo_flag();
camera.write_reg(ARDUCHIP_FRAMES, 0x00);
camera.OV5642_set_JPEG_size(OV5642_320x240);
delay(1000);
}
void startCapture(){
camera.clear_fifo_flag();
camera.start_capture();
}
void sendCapture(WiFiClient client, ArduCAM camera){
uint8_t temp = 0, temp_last = 0;
size_t len = camera.read_fifo_length();
if (len >= MAX_FIFO_SIZE) {
Serial.println(F("Over size."));
}
if (len == 0) {
Serial.println(F("Size is 0."));
}
camera.CS_LOW();
camera.set_fifo_burst();
if (!client.connected()) return;
String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: image/jpeg\r\n";
response += "Content-len: " + String(len) + "\r\n\r\n";
client.print(response);
i = 0;
while (len--) {
temp_last = temp;
temp = SPI.transfer(0x00);
//Read JPEG data from FIFO
if ((temp == 0xD9) && (temp_last == 0xFF)) { //If find the end ,break while,
buffer[i++] = temp; //save the last 0XD9
//Write the remain bytes in the buffer
if (!client.connected()) break;
client.write(&buffer[0], i);
is_header = false;
i = 0;
camera.CS_HIGH();
break;
}
if (is_header == true) {
//Write image data to buffer if not full
if (i < bufferSize)
buffer[i++] = temp;
else {
//Write bufferSize bytes image data to file
if (!client.connected()) break;
client.write(&buffer[0], bufferSize);
i = 0;
buffer[i++] = temp;
}
}
else if ((temp == 0xD8) & (temp_last == 0xFF))
{
is_header = true;
buffer[i++] = temp_last;
buffer[i++] = temp;
}
}
}
void serveImage(WiFiClient client) {
delay(1000);
startCapture();
Serial.println(F("CAM Capturing"));
int total_time = millis();
while (!camera.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
total_time = millis() - total_time;
Serial.print(F("capture total_time used (in miliseconds):"));
Serial.println(total_time, DEC);
Serial.println(F("CAM Capture Done."));
total_time = millis();
sendCapture(client, camera);
total_time = millis() - total_time;
Serial.print(F("send total_time used (in miliseconds):"));
Serial.println(total_time, DEC);
Serial.println(F("CAM send Done."));
}
void serveStream(WiFiClient client) {
int total_time = 0;
uint8_t temp = 0, temp_last = 0;
String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
client.print(response);
while (1) {
startCapture();
total_time = millis();
while (!camera.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
total_time = millis() - total_time;
Serial.print(F("frame capture total_time used (in miliseconds):"));
Serial.println(total_time, DEC);
size_t len = camera.read_fifo_length();
if (len >= MAX_FIFO_SIZE) {
Serial.println(F("Over size."));
continue;
}
if (len == 0) {
Serial.println(F("Size is 0."));
continue;
}
camera.CS_LOW();
camera.set_fifo_burst();
if (!client.connected()) break;
response = "--frame\r\n";
response += "Content-Type: image/jpeg\r\n\r\n";
client.print(response);
while (len--) {
temp_last = temp;
temp = SPI.transfer(0x00);
//Read JPEG data from FIFO
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
{
buffer[i++] = temp; //save the last 0XD9
//Write the remain bytes in the buffer
camera.CS_HIGH();;
if (!client.connected()) break;
client.write(&buffer[0], i);
is_header = false;
i = 0;
}
if (is_header == true) {
//Write image data to buffer if not full
if (i < bufferSize)
buffer[i++] = temp;
else
{
//Write bufferSize bytes image data to file
camera.CS_HIGH();
if (!client.connected()) break;
client.write(&buffer[0], bufferSize);
i = 0;
buffer[i++] = temp;
camera.CS_LOW();
camera.set_fifo_burst();
}
} else if ((temp == 0xD8) & (temp_last == 0xFF)) {
is_header = true;
buffer[i++] = temp_last;
buffer[i++] = temp;
}
}
if (!client.connected()) break;
}
}
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial);
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < "1.0.0") {
Serial.println("Please upgrade the firmware");
}
setupArducam();
connectNetwork();
}
void loop() {
WiFiClient client = server.available();
if (client) {
String requestLine = String();
boolean requestLineRead = false;
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
Serial.println(requestLine);
// Simple HTTP request parsing
if (requestLine.length() > 13 && requestLine.substring(0, 13).equalsIgnoreCase("GET /capture ")) {
serveImage(client);
} else if (requestLine.length() > 12 && requestLine.substring(0, 12).equalsIgnoreCase("GET /stream ")) {
serveStream(client);
} else {
Serial.println("No route handler for this one");
}
break;
}
if (c == '\n') {
currentLineIsBlank = true;
requestLineRead = true;
} else if (c != '\r') {
// you've got a character on the current line
currentLineIsBlank = false;
if (!requestLineRead) {
requestLine += c;
}
}
}
}
// close the connection:
delay(1);
client.stop();
}
}
which results in output like this on the serial:
00:33:36.980 -> capture total_time used (in miliseconds):1157
00:33:36.980 -> CAM Capture Done.
00:33:37.207 -> send total_time used (in miliseconds):217
00:33:37.207 -> CAM send Done.
00:33:37.431 -> GET /favicon.ico HTTP/1.1
00:33:37.431 -> No route handler for this one
00:33:39.328 -> GET /capture HTTP/1.1
00:33:40.315 -> CAM Capturing
00:33:42.060 -> capture total_time used (in miliseconds):1737
00:33:42.060 -> CAM Capture Done.
00:33:42.275 -> send total_time used (in miliseconds):213
00:33:42.275 -> CAM send Done.
00:33:42.308 -> GET /favicon.ico HTTP/1.1
00:33:42.308 -> No route handler for this one
00:33:44.113 -> GET /capture HTTP/1.1
00:33:45.137 -> CAM Capturing
00:33:46.129 -> capture total_time used (in miliseconds):1008
00:33:46.129 -> CAM Capture Done.
00:33:46.349 -> send total_time used (in miliseconds):213
00:33:46.349 -> CAM send Done.
00:33:46.416 -> GET /favicon.ico HTTP/1.1
00:33:46.416 -> No route handler for this one
Is there anything I could do to improve capture time? Thanks in advance!!
I'm using an OV5642 with an Arduino Nano 33 IoT. I would like to get multiple frames per second streamed over WiFi, but so far, I have very high capture times between 1s and 2s. So, I'm very far from the advertised FPS. I am not hoping for a high fps, but at least 10 or 15 fps to get a relative sense of fluidity.
I use the following code:
which results in output like this on the serial:
Is there anything I could do to improve capture time? Thanks in advance!!