Connection project NodeMCU and OV5640 Camera Board (B)

Hello, I need to do a project in which the camera OV5640 Camera Board (B) is connected to the NodeMCU board in order to take pictures with the camera and then see them in a web page with the wifi function of the ESP8266MOD. Before writing this publication I tried to gather information, but I did not find anything similar in terms of connections and, most importantly, the sketch. My knowledge of Arduino is quite limited. I hope that one of you will help me carry this out. If anyone knew how to make the sketch and the connections, I would appreciate it if you would pass it on to me. Next, I show you a picture of the two modules I have.

In general, it's much easier to buy a mass-produced consumer good than to prototype something. I'm sure there are a kajillion purchasables on the internet that will do exactly this.

As stated, this is a sizeable project. This page states that the module will produced "compressed data". If that means JPEG or PNG, then this project just got a lot a notch easier.

This seems applicable, but I get the impression that it is built for some sort of adapter board named 'ArduCAm' that sits between an arduino and the camera.

This appears to have the information needed to talk to the camera without some sort of intermediary board. A programmer would be looking for an arduino library that will compile for the NodeMCU that can 'speak' that protocol. Otherwise, it's a big job.

Maybe someone else knows more - I'm just a programmer that has never dealt with this hardware before. To me it looks like hours and hours of time (which is to say, thousands of dollars), and of course I'd have to purchase the modules myself to get any sort of result any time this century.

If you want a webcam, get a webcam. If you want to learn programming, start with something much simpler. If you are building something commercially for profit share or otherwise have deep pockets, or if you can persuade someone that this is a charity gig, then all I can say is that this project is certainly do-able.

Don't let my response dishearten you. There's every possibility that someone on this forum has already done exactly this project using exactly these components.

Actually it sounds quite straightforward to me - indeed hoping the webcam can produce jpg/png images on request. NodeMCU requests image from the web cam, stores it in SPIFFS (up to 3 MB available on board - if need more then you need an external SD card), and then can transmit the image as is in a web site.

Assuming there’s no need to do any changes to the image, there’s no need for decompression, and the image as received from the camera is the image used for the web page.

Now the question: why use a NodeMCU for that? My web cam can do just that: connect to WiFi, have clients connect to it and get the latest image from the camera. Or get the complete video stream, of course. Though iirc the stills can be higher quality than the video stream.

All in all it seems quite straightforward to do, the hardest part may be the communication between the camera and the NodeMCU. No idea how that works - I’ll have to look into the documentation of the camera. As it appears to be designed for use with a MCU that shouldn’t be too hard.

There is an arducam using esp8266 issue on github :

Should ask there, it looks they managed to make it work, at least for low resolution mode.

I really have tried to find something that works for me on the internet and I have not found anything. Effectively the images can be jpg / png. The camera does not have Wi-Fi access, so I implemented the NodeMCU. I have found a program that could work, take a look, the problem is that I do not know how to connect the camera to the NodeMCU according to that program. I do not see any pin defined in the program, or so I think.

// ArduCAM Mini demo (C)2016 Lee
// web: http://www.ArduCAM.com
// This program is a demo of how to use most of the functions
// of the library with ArduCAM ESP8266 5MP camera.
// This demo was made for ArduCAM ESP8266 OV5640 5MP Camera.
// It can take photo and send to the Web.
// It can take photo continuously as video streaming and send to the Web.
// The demo sketch will do the following tasks:
// 1. Set the camera to JEPG output mode.
// 2. if server.on("/capture", HTTP_GET, serverCapture),it can take photo and send to the Web.
// 3.if server.on("/stream", HTTP_GET, serverStream),it can take photo continuously as video 
//streaming and send to the Web.

// This program requires the ArduCAM V4.0.0 (or later) library and ArduCAM ESP8266 5MP camera
// and use Arduino IDE 1.5.8 compiler or above
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"
#if !(defined ESP8266 )
#error Please select the ArduCAM ESP8266 UNO board in the Tools/Board
#endif

//This demo can only work on OV5640_MINI_5MP_PLUS or ARDUCAM_SHIELD_V2 platform.
#if !(defined (OV5640_MINI_5MP_PLUS)||(defined (ARDUCAM_SHIELD_V2) && defined (OV5640_CAM)))
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif

// set GPIO16 as the slave select :
const int CS = 16;
//you can change the value of wifiType to select Station or AP mode.
//Default is AP mode.
int wifiType = 1; // 0:Station  1:AP

//AP mode configuration
//Default is arducam_esp8266.If you want,you can change the AP_aaid  to your favorite name
const char *AP_ssid = "arducam_esp8266"; 
//Default is no password.If you want to set password,put your password here
const char *AP_password = "";

//Station mode you should put your ssid and password
const char* ssid = "SSID"; // Put your SSID here
const char* password = "PASSWORD"; // Put your PASSWORD here

ESP8266WebServer server(80);

ArduCAM myCAM(OV5640, CS);

void start_capture(){
  myCAM.clear_fifo_flag();
  myCAM.start_capture();
}

void camCapture(ArduCAM myCAM){
  WiFiClient client = server.client();
  
  size_t len = myCAM.read_fifo_length();
  if (len >= MAX_FIFO_SIZE){
    Serial.println("Over size.");
    return;
  }else if (len == 0 ){
    Serial.println("Size is 0.");
    return;
  }
  
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  #if !(defined (ARDUCAM_SHIELD_V2) && defined (OV5640_CAM))
  SPI.transfer(0xFF);
  #endif
  if (!client.connected()) return;
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: image/jpeg\r\n";
  response += "Content-Length: " + String(len) + "\r\n\r\n";
  server.sendContent(response);
  
  static const size_t bufferSize = 4096;
  static uint8_t buffer[bufferSize] = {0xFF};
  
  while (len) {
      size_t will_copy = (len < bufferSize) ? len : bufferSize;
      SPI.transferBytes(&buffer[0], &buffer[0], will_copy);
      if (!client.connected()) break;
      client.write(&buffer[0], will_copy);
      len -= will_copy;
  }
  
  myCAM.CS_HIGH();
}

void serverCapture(){
  start_capture();
  Serial.println("CAM Capturing");

  int total_time = 0;
  total_time = millis();
  while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
  total_time = millis() - total_time;
  Serial.print("capture total_time used (in miliseconds):");
  Serial.println(total_time, DEC);
  total_time = 0;
  Serial.println("CAM Capture Done!");
  total_time = millis();
  camCapture(myCAM);
  total_time = millis() - total_time;
  Serial.print("send total_time used (in miliseconds):");
  Serial.println(total_time, DEC);
  Serial.println("CAM send Done!");
}

void serverStream(){
  WiFiClient client = server.client();
  
  String response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  server.sendContent(response);
  
  while (1){
    start_capture();   
    while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)); 
    size_t len = myCAM.read_fifo_length();
    if (len >= MAX_FIFO_SIZE){
      Serial.println("Over size.");
      continue;
    }else if (len == 0 ){
      Serial.println("Size is 0.");
      continue;
    }
    
    myCAM.CS_LOW();
    myCAM.set_fifo_burst(); 
    #if !(defined (ARDUCAM_SHIELD_V2) && defined (OV5640_CAM))
    SPI.transfer(0xFF);
    #endif   
    if (!client.connected()) break;
    response = "--frame\r\n";
    response += "Content-Type: image/jpeg\r\n\r\n";
    server.sendContent(response);
    
    static const size_t bufferSize = 4096;
    static uint8_t buffer[bufferSize] = {0xFF};
    
    while (len) {
      size_t will_copy = (len < bufferSize) ? len : bufferSize;
      SPI.transferBytes(&buffer[0], &buffer[0], will_copy);
      if (!client.connected()) break;
      client.write(&buffer[0], will_copy);
      len -= will_copy;
    }
    myCAM.CS_HIGH();
    if (!client.connected()) break;
  }
}

void handleNotFound(){
  String message = "Server is running!\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  server.send(200, "text/plain", message);
  
  if (server.hasArg("ql")){
    int ql = server.arg("ql").toInt();
    myCAM.OV5640_set_JPEG_size(ql);
    delay(1000);
    Serial.println("QL change to: " + server.arg("ql"));
  }
}

void setup() {
  uint8_t vid, pid;
  uint8_t temp;
#if defined(__SAM3X8E__)
  Wire1.begin();
#else
  Wire.begin();
#endif
  Serial.begin(115200);
  Serial.println("ArduCAM Start!");

  // set the CS as an output:
  pinMode(CS, OUTPUT);

  // initialize SPI:
  SPI.begin();
  SPI.setFrequency(4000000); //4MHz

  //Check if the ArduCAM SPI bus is OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55){
    Serial.println("SPI1 interface Error!");
    while(1);
  }
  //Check if the camera module type is OV5640
  myCAM.wrSensorReg16_8(0xff, 0x01);
  myCAM.rdSensorReg16_8(OV5640_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg16_8(OV5640_CHIPID_LOW, &pid);
   if((vid != 0x56) || (pid != 0x40)){
   Serial.println("Can't find OV5640 module!");
   while(1);
   }
   else
   Serial.println("OV5640 detected.");
 

  //Change to JPEG capture mode and initialize the OV5642 module
  myCAM.set_format(JPEG);
   myCAM.InitCAM();
   myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
   myCAM.OV5642_set_JPEG_size(OV5640_320x240);delay(1000);

  if (wifiType == 0){
    if(!strcmp(ssid,"SSID")){
       Serial.println("Please set your SSID");
       while(1);
    }
    if(!strcmp(password,"PASSWORD")){
       Serial.println("Please set your PASSWORD");
       while(1);
    }
    // Connect to WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
    
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("WiFi connected");
    Serial.println("");
    Serial.println(WiFi.localIP());
  }else if (wifiType == 1){
    Serial.println();
    Serial.println();
    Serial.print("Share AP: ");
    Serial.println(AP_ssid);
    Serial.print("The password is: ");
    Serial.println(AP_password);
    
    WiFi.mode(WIFI_AP);
    WiFi.softAP(AP_ssid, AP_password);
    Serial.println("");
    Serial.println(WiFi.softAPIP());
  }
  
  // Start the server
  server.on("/capture", HTTP_GET, serverCapture);
  server.on("/stream", HTTP_GET, serverStream);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("Server started");
}
void loop() {

  server.handleClient();
}

Pin definitions I suppose will be in the ArduCAM library.

A quick look at the data sheet suggests it uses an 8-bit wide parallel output, or the I2C interface. I2C default pins on NodeMCU are D1 for SCL and D2 for SDA.

I have opened the serial monitor with the program that I have gone through before and this is the message that I get:

Soft WDT reset

ctx: cont 
sp: 3fff1fb0 end: 3fff21c0 offset: 01b0

>>>stack>>>
3fff2160:  3fffdad0 3fff1164 3fff1164 40202a60  
3fff2170:  feefeffe feefeffe feefeffe feefeffe  
3fff2180:  feefeffe feefeffe feefeffe feefeffe  
3fff2190:  feefeffe feefeffe feefeffe 3fff1190  
3fff21a0:  3fffdad0 00000000 3fff1188 40208220  
3fff21b0:  feefeffe feefeffe 3fff11a0 40100710  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v614f7c32
~ld
ArduCAM Start!
SPI1 interface Error!

Soft WDT reset

There's an ESP exception decoder out there, which integrates nicely with the IDE. It will give clues on what is going wrong.

wvmarle:
Pin definitions I suppose will be in the ArduCAM library.

A quick look at the data sheet suggests it uses an 8-bit wide parallel output, or the I2C interface. I2C default pins on NodeMCU are D1 for SCL and D2 for SDA.

but what are those pins, if my camera does not have those, as are not the sioc siod .... Really this is impossible to do. I have the camera module that less people use so there is not much information.
I'm sure none of this forum has it.

If it works with an Arduino you can normally make it work with a NodeMCU - but you'll have to study the data sheet in more detail (as said I just skimmed it) to understand how this camera communicates, and check the ArduCAM library for any changes (e.g. pin definitions) that need to be made to make it work with the NodeMCU.

For your board: SOIC and SOID are probably Clock and Data for I2C.

You may be able to use the parallel interface but you need 9 pins for that, out of the 11 you have available on a NodeMCU. For that reason I'd first try the I2C interface, though almost certainly the parallel one can be much faster.