Advice on transferring image data from Arduino with Arducam to Arduino with display

About a year ago, I started working on a project that would allow me to use an Arduino Giga + Display to program a device to take images of cells (sort of a macroscope), using Arducams controlled by a slave board, at user defined intervals with controlled lighting and a few sensors. Currently, the Giga controls most of the devices/sensors, but the Arducams (I have two) are running on a Mega with the Arducam multicamera adapter shield - I am also running a Sparkfun Triad spectral sensor on the Mega.

Currently, the Giga controls the Mega through Serial (using Serial 1 [ RX1/TX1] on both boards for communication), through a logic level converter, and asks it to run a process and transfer data back to the Giga. I have successfully implemented data transfer of the Triad sensor to the Giga and have the Giga display showing a graph of the spectral intensities which is updated every time the Triad is triggered.

I have also troubleshot (after previous advice) the general Serial transfer code within a simpler project that sends a pre-generated image from a Mega to the Giga, which the Giga then displays (though this image was only 64x64).

Putting all of this together, I have code within my Giga project that sends a command via Serial1 to the Mega, which it receives also on Serial1. If the command is a '5' this triggers the triad sensor. If the command is a '3' or a '4' it triggers one of the two Arducams. This activates the camera in RAW mode with an image size of 320x240 and captures an image (read_fifo_burst) which is transferred back to the Giga by Serial1.

void enableArduCamRAW (ArduCAM myCAM, int camNUM) {
  uint8_t temp;
  // Renable the ArduCAM module
  if(camNUM == 1){
    pinMode(CS1, OUTPUT);
    digitalWrite(CS1, HIGH); 
  }
  if (camNUM == 2){
    pinMode(CS2, OUTPUT);
    digitalWrite(CS2, HIGH);
  }
  // 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(F("SPI interface Error!"));
  } else {
    Serial.println(F("Arducam OK"));
  }
  
  // Re-enable the sensor module 
  myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK);
  // Re-enable the memory controller circuit 

  // Reset all of the sensor module settings
  myCAM.set_format(RAW);
  myCAM.InitCAM();
  myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
  myCAM.clear_fifo_flag();
  myCAM.write_reg(ARDUCHIP_FRAMES, FRAMES_NUM);
  myCAM.OV5642_set_RAW_size(OV5642_320x240);
  delay(100);
}

uint8_t read_fifo_burst(ArduCAM myCAM, int cam){
  char VL;
  myCAM.flush_fifo(); 
  myCAM.clear_fifo_flag(); 
  myCAM.OV5642_set_RAW_size(OV5642_320x240);
  delay(100);
  myCAM.start_capture();
  Serial.println("Start Capture"); 
  while ( !myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)); 
  Serial.println(F("CAM Capture Done."));
  Serial1.print("<");
  for(int i = 0; i < 320; i++){
    for(int j = 0; j < 240; j++){
        VL = myCAM.read_fifo();
        Serial1.write(VL);
    }
  }
  Serial1.print(">");
  myCAM.clear_fifo_flag();
  Serial.println("Acquired Image");
}

On the Giga side, before triggering the camera, the LVGL image container is filled with zeros to clear it. Then "serialRecImage" triggers the camera and waits for Serial1 to receive something back. The code for this is based off the Serial Arduino to Arduino transfer examples (example 3) and looks for a startMarker and endMarker to initiate and terminate the recording process. After the startMarker is received it saves all following bytes in the LVGL image container until it either receives the endMarker or times out with no received data.

void serialRecImage(int num) {
  static boolean receiveUntilTimeout = false;
  //static byte ndx = 0;
  int ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  int timeReceived;
  if (num == 1){
    Serial1.print(3);
  }
  if (num == 2){
    Serial1.print(4);
  }
  delay(100);
  while(!Serial1.available()){ 
  }

  if (Serial1.available() > 0 && !receiveUntilTimeout)
  {
    rc = Serial1.read();
    if (rc == startMarker)
    {
      receiveUntilTimeout = true;
      Serial.print("Receiving");
      timeReceived = millis();
    }
  }
  while (receiveUntilTimeout)
  {
    if (Serial1.available() > 0 )
    {
      rc = Serial1.read();
      if (rc == endMarker)
      {
        Serial.print("Done");
        break;
      }
      img_map[ndx] = rc;
      //Serial.print(receiveUntilTimeout);
      ///Serial.print(".");
      Serial.println(ndx);
      //Serial.print(":");
      //Serial.print(rc);
      ndx++;
      timeReceived = millis();
    }
    if (!Serial1.available())
    {
      if (millis() - timeReceived >= 12000)
      {
        receiveUntilTimeout = false;
        Serial.println(ndx);
        break;
      }
    }
  }
  receiveUntilTimeout = false;
  Serial.println(ndx);
}

Now onto my issue, and where I need guidance. Ideally, to make the LVGL image container work perfectly, I would want to preload an image of some sort that is 320x240 in RAW format. However, when I do this, the resultant 153,600 element array makes the rest of my code sluggish and crashes after every second interaction with the display. This is true whether I try to preload it with an actual image or just an empty array of the correct size. If I don't pre-set the image container the rest of my code works fine, but the image transfer is super spotty and either A) pretends to transfer data and stops between 1-50 bytes in (which does not cause it to crash) or B) actually starts a transfer between the Mega and Giga but this crashes around 60,000 bytes in and causes the board to crash.

After beating my head on this for a while, I'm guessing these observable problems are due to the image container (img_map) being too large for the board to handle in case A and not being the right size in case B. Is there anything I can do to pre-load an image container of the correct size that does not make my code unstable?

P.S - If I preload a place-holder image of the right size as the img_map object and then ask LVGL to display it in setup(), it does so without a problem. From there I can interact with the screen ONCE without it crashing (example - going to a submenu from the home screen by pressing a button on the screen). If I try to interact with the screen again (example - going back to the home screen from the submenu by pressing a button on the screen) the code crashes and the Giga gives me the red flashing light of doom. It does not matter what I press first or second - only that the second interaction ALWAYS crashes the code.

Sorry for the length of this post. I hope someone can help me out here as this last hiccup is the last hurdle before I can finalize my code and start putting together my macroscope device. Thanks!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.