Sending a picture from Arduino to NodeMCU with i2C

Hi everyone,

Could you give me some guidance here?

I am building a home-surveillance robot using Mega 2560 + NodeMCU. In summary, Arduino Mega is responsible for sensors and navigation, while NodeMCU acts as a webserver, provides WiFi connectivity and makes connections to APIs/Databases.

Both boards are connected with i2c to exchange commands and data. The robot can be driven already remotely with a web control panel served by NodeMCU.

The problem I have right now:

The Arduino board is controlling a MicroSD adapter (SPI) to store the images taken with a serial VGA Camera (OV7670), likewise connected to Arduino. The idea is to show the last picture in a web page served by NodeMCU itself.

And the 1M$ question:

How would you access the picture stored in the MicroSD adapter from the NodeMCU, since the card reader is controlled by the Arduino board? How would you do it?

Some possibilities I thought so far:

  1. Sharing the MicroSD Adapter between Arduino and NodeMCU by implementing a multi-master SPI scheme -> It seems to be quite tricky and somehow unnatural.

  2. Access the MicroSD by i2C from the other board, requesting an image, buffering it and then getting it out -> it would toggle the master/slave mode in both Arduino and NodeMCU to have a bi-directional conversation everytime. I guess it introduces a lot of delay and I would need to freeze the communication since both boards are constantly speaking because of the occurrence of many asynchronous events.

  3. Moving the MicroSD and the camera to NodeMCU to have direct access to those device --> maybe the simplest idea, but then I cannot sepparate anymore the architecture: sensors and robot functions (Arduino) and communication services (NodeMCU).

Do you have any other ideas? I would appreciate a lot your experience and opinion.

Thanks!

valheru:
2. Access the MicroSD by i2C from the other board, requesting an image, buffering it and then getting it out -> it would toggle the master/slave mode in both Arduino and NodeMCU to have a bi-directional conversation everytime. I guess it !

That'd be the way, but why would you switch the master/slave roles?

The NodeMCU will be the master, as it has to request the data from the Mega - be it sensor data or the image. The Mega can just stream (no need to locally buffer beyond the I2C buffers) the whole thing to the NodeMCU in one go.

Thank you a lot for your answer, wvmarle! That helps a lot :slight_smile:

but why would you switch the master/slave roles?

I have been reading deeper on i2c and you are definitely right, in this case it wouldn't be necessary to switch the roles.

The Mega can just stream (no need to locally buffer beyond the I2C buffers) the whole thing to the NodeMCU in one go.

That's a great point! I couldn't find any example with a similar implementation. Could you please show me a pseudo-code about how the thing would be done?

My guess in a rough coding:

#Slave (Arduino Mega)

void setup(){             
 Wire.begin(8); 
 Wire.onRequest(streamLastPicture);}
void streamLastPicture(){

  File lastPicture = SD.open("lastpicture.jpg");
  
  if (lastPicture){
      Wire.write(lastPicture); //Just like that?
  }else{
     Wire.write(-1);
 }
  lastPicture.close();
}

#Master (NodeMCU)

File streamedImage;

void Loop(){

    if (HttpGetRequest(request)){
        httpResponse(request));
    }  

}

httpResponse(request){

 Wire.requestFrom(8,Bytes); //How many Bytes to request without knowing Image size??
 
   while (Wire.available()){

       File streamedImage = Wire.read(); //How to buffer here?
   }

  imageJPG = streamedImage.renderAsJpg(streamedImage); //How to treat the streamed Bytes as Image?

  httpResponse(httpHeaders + "<html><body><img src ="+imageJPG+ "/></body></html>); 

}

Everything can be summarized now in one more question: how can I get from the i2c wire the bytes of a JPG file in order to serve it immediately in a valid HTTP Response??

You have to read the file byte by byte until EOF, then send those bytes one by one to Wire.

One more thing: you have to check the file size beforehand, so you can start by sending that number to the NodeMCU, followed by the file. So I envision communication to go something like this:

NodeMCU sends command: please send me size of file "niceimage.jpg" (so a byte with the command followed by the file name).
Mega: checks file size.
NodeMCU requests data: expects unsigned long - 4 bytes (the file size).
Mega: sends file size.
ModeMCU sends command: please send the file.
Mega: prepares to send file.
NodeMCU: requests data (expect file size number of bytes)
Mega: sends the file, byte by byte.