CRC When transferring JPG over serial

Hi,

Been following this thread and have the final code working a ESP32CAM(Slave) and another donor ESP32 (Master).

https://forum.arduino.cc/t/transfer-pictures-from-esp32-cam-to-esp32-via-serial/647488/59

Trying to add the ESP32CAM to a different ESP(Master).

I am sure I have the code correct but get a CRC error.

Both ESP's (Slave/Master) have the same baud rate set, tried as low as 9600
Serial2.begin(115200, SERIAL_8N1,TX,RX); (pins are defined in another file)

#include "SerialTransfer.h"
SerialTransfer myTransfer;
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
uint16_t packetCounter=1;
uint16_t bufferPointer=0;
char tempImageBuffer[32000];
  }else if(myTransfer.status < 0) { 
    pDBG("ERROR: ");
    if(myTransfer.status == -1)
      pDBGln(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      pDBGln(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      pDBGln(F("STOP_BYTE_ERROR"));
  }

My question is what does CRC myTransfer.status == -1 mean so I can fault find? I added the TX from the ESPCAM32(Slave) to the Master and can see the transfer go through without error to the serial console but CRC error to the my defined GPIO Pins. Tried different GPIOs Pins as well.

I am stumped to what my issue is and need a tiny bit of guidance if possible please?

Can you explain the myTransfer,status codes to get me in the right direction? Or another way to fault find?

Using as per the thread SerialTransfer.h release 1.4.1

Adding the Master's TX to the ESP32CAM output GPIO TX PIN I am only seeing garbage? But Serial Bauds are the same.

Add the ESP32CAM Output (TX) to Master ESP TX I see the correct output.

Obviously not.. Since you only post snippets and no schematic, no one is able to help you.

1 Like

It appears the solution is possible but where to start? Posting an annotated schematic, not a frizzy diagram with links to "Technical" information on each of the hardware items will go a long way in allowing us to help you. If the code is correct and the hardware is correct (no schematic) it has to be working as designed, probably not as intended but as designed. Post the full code properly.

If that data is the jpg image, serial monitor will not be able to display it. Serial monitor will only display ASCII.

Thanks and apologies. The code that I am using is as per the post but included below.

Txt - ESP32CAM

#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "esp_camera.h"
#include "Arduino.h"
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include "SerialTransfer.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

SerialTransfer myTransfer;
HardwareSerial Comm(1);
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
const uint16_t PIXELS_PER_PACKET = MAX_PACKET_SIZE - sizeof(ImgMetaData);

void setup(){
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Comm.begin(962100, SERIAL_8N1,15,14);     //, Comm_Txd_pin, Comm_Rxd_pin); // Define and start Comm serial port
  myTransfer.begin(Comm);
 
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
 
//  if(psramFound()){
//    config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
//    config.jpeg_quality = 10;
//    config.fb_count = 2;
//  } else {
//    config.frame_size = FRAMESIZE_SVGA;
//    config.jpeg_quality = 12;
//    config.fb_count = 1;
//  }

    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
 
  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK){
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
}

void loop(){
  uint16_t startIndex = 0;
  camera_fb_t * fb = NULL;
  //Take Picture with Camera
  fb = esp_camera_fb_get(); 
   
  ImgMetaData.imSize       = fb->len;                             //sizeof(myFb);
  ImgMetaData.numLoops     = (fb->len / PIXELS_PER_PACKET) + 1;   //(sizeof(myFb)/PIXELS_PER_PACKET) + 1; 
  ImgMetaData.sizeLastLoop = fb->len % PIXELS_PER_PACKET;         //(sizeof(myFb)%PIXELS_PER_PACKET);

  for(ImgMetaData.counter=1; ImgMetaData.counter<=ImgMetaData.numLoops; ImgMetaData.counter++){
    myTransfer.txObj(ImgMetaData, sizeof(ImgMetaData));
    //printStructBuf();
    stuffPixels(fb->buf, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //stuffPixels(myFb, startIndex, sizeof(ImgMetaData), PIXELS_PER_PACKET);
    //printStructBuf();   
    myTransfer.sendData(MAX_PACKET_SIZE);
     
    pDBGln(F("Sent:"));
    pDBG(F("img.counter: "));      pDBGln((uint16_t)((myTransfer.txBuff[1] << 8) | myTransfer.txBuff[0]));
    pDBG(F("img.imSize: "));       pDBGln((uint16_t)((myTransfer.txBuff[3] << 8) | myTransfer.txBuff[2]));
    pDBG(F("img.numLoops: "));     pDBGln((uint16_t)((myTransfer.txBuff[5] << 8) | myTransfer.txBuff[4]));
    pDBG(F("img.sizeLastLoop: ")); pDBGln((uint16_t)((myTransfer.txBuff[7] << 8) | myTransfer.txBuff[6]));

    startIndex += PIXELS_PER_PACKET;    
    delay(100);
    //printBuf();  
  }
  esp_camera_fb_return(fb);   //clear camera memory
  delay(10000);
}

void printStructBuf(){
  pDBG(F("Internal Struct: { "));
  for (uint16_t k=0; k<sizeof(ImgMetaData); k++){
    pDBG(myTransfer.txBuff[k]);
    if (k<(sizeof(ImgMetaData)-1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void printBuf(){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=8; k<MAX_PACKET_SIZE; k++){
    pDBG(myTransfer.txBuff[k]);
    if (k < (MAX_PACKET_SIZE - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
  pDBGln();
}

void stuffPixels(const uint8_t * pixelBuff, const uint16_t &bufStartIndex, const uint16_t &txStartIndex, const uint16_t &len){
  uint16_t txi = txStartIndex;
  for (uint16_t i=bufStartIndex; i<(bufStartIndex + len); i++)  {
    myTransfer.txBuff[txi] = pixelBuff[i];
    txi++;
  }
}

Receiver

/*Receives picture via serial and saves to ftp*/

#define DEBUG_ESP              //comment out to deactivate debug console

#ifdef DEBUG_ESP
  #define pDBGln(x) Serial.println(x)
  #define pDBG(x)   Serial.print(x)
#else 
  #define pDBG(...)
  #define pDBGln(...)
#endif

#include "SerialTransfer.h"
SerialTransfer myTransfer;
struct img_meta_data{
  uint16_t counter;
  uint16_t imSize;
  uint16_t numLoops;
  uint16_t sizeLastLoop;
} ImgMetaData;
uint16_t packetCounter=1;
uint16_t bufferPointer=0;
char tempImageBuffer[32000];

#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;

// FTP Client Lib
#include "ESP32_FTPClient.h"

// Your WiFi credentials.
char ssid[] = "myssid";
char pass[] = "mypass";

// FTP Server credentials
char ftp_server[] = "192.168.0.1";
char ftp_user[]   = "pcborges"; 
char ftp_pass[]   = "mypass";

// picture name
String picPrefix ="";
String pic_name;  

// Connection timeout;
#define CON_TIMEOUT   10*1000                     // milliseconds

ESP32_FTPClient ftp(ftp_server, ftp_user, ftp_pass);

void setup(){
  //Serial.begin(Baud Rate, Data Protocol, Txd pin, Rxd pin);
  Serial.begin(115200);                                                     // Define and start serial monitor
  // 115200,256000,512000,962100
  Serial2.begin(962100, SERIAL_8N1); //Receiver_Txd_pin, Receiver_Rxd_pin); // Define and start Receiver serial port
  myTransfer.begin(Serial2);

  WiFi.begin(ssid, pass);
  pDBGln("Connecting Wifi...");
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      pDBG(".");
  }
  pDBGln("");
  pDBG("IP address: ");
  pDBGln(WiFi.localIP());
  pDBGln();

  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, for example:
  // GMT +1 = 3600, GMT +8 = 28800, GMT -1 = -3600, GMT 0 = 0
  timeClient.setTimeOffset(3600*-3);  
}

void loop(){
  if(myTransfer.available())  {
    myTransfer.rxObj(ImgMetaData, sizeof(ImgMetaData));
    pDBG("Struct Data: ");
    pDBG(ImgMetaData.counter);
    pDBG(", ");
    pDBG(ImgMetaData.imSize);
    pDBG(", ");  
    pDBG(ImgMetaData.numLoops);
    pDBG(", ");
    pDBG(ImgMetaData.sizeLastLoop);
    pDBG(", PacketCounter: ");
    pDBGln(packetCounter);  

    if(ImgMetaData.counter==1){  
      copyToImageBuff(MAX_PACKET_SIZE-sizeof(ImgMetaData));
    }else{
      if(ImgMetaData.counter==packetCounter){  
        if(packetCounter<ImgMetaData.numLoops){        
          copyToImageBuff(MAX_PACKET_SIZE-sizeof(ImgMetaData));
        }else if(ImgMetaData.counter==packetCounter){
          copyToImageBuff(ImgMetaData.sizeLastLoop);     
        }
      }
    }
 
    if(packetCounter>ImgMetaData.numLoops){  
      pic_name  = picPrefix;
      pic_name += getDateTime() + ".jpg";  
      FTP_upload();     
      packetCounter=1;
      bufferPointer=0;
      delay(2000);
      //while(1){}
    }  

  }else if(myTransfer.status < 0) { 
    pDBG("ERROR: ");
    if(myTransfer.status == -1)
      pDBGln(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      pDBGln(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      pDBGln(F("STOP_BYTE_ERROR"));
  }
}
  

void copyToImageBuff(uint16_t dataLenght){
  for(int y=0;y<dataLenght;y++){
    tempImageBuffer[bufferPointer+y] = myTransfer.rxBuff[y+sizeof(ImgMetaData)];
  } 
  bufferPointer+=dataLenght;
  packetCounter++;  

  pDBG("dataLenght: ");
  pDBG(dataLenght);  
  pDBG(", bufferPointer: ");
  pDBGln(bufferPointer);
}

void printBuf(char localBuff){
  pDBG(F("Pixel Values: { "));
  for (uint16_t k=0; k<sizeof(myTransfer.rxBuff); k++){
    pDBG(myTransfer.rxBuff[k]);
    if (k < (sizeof(myTransfer.rxBuff) - 1))
      pDBG(F(", "));
    else
      pDBGln(F(" }"));
  }
}

void FTP_upload(){
  pDBG("Uploading via FTP: "); 
  ftp.OpenConnection();
  //ftp.ChangeWorkDir("/public_html/zyro/");
  //Create a file and write the image data to it;
  ftp.InitFile("Type I");
  const char *f_name = pic_name.c_str();
  ftp.NewFile( f_name ); 
  pDBGln( f_name );    
  ftp.WriteData((unsigned char*)tempImageBuffer, ImgMetaData.imSize);
  ftp.CloseFile();
  // Breath, withouth delay URL failed to update.
  pDBGln("Done... Waiting next transfer...");
  delay(100);
}

String getDateTime(){
  String curDateTime="";

  while(!timeClient.update()) {
    timeClient.forceUpdate();
  }
  // The formattedDate comes with the following format:
  // 2018-05-28T16:00:13Z
  // We need to extract date and time
  formattedDate = timeClient.getFormattedDate();

  #ifdef DEGUB_ESP
    // Extract date
    int splitT = formattedDate.indexOf("T");
    dayStamp = formattedDate.substring(0, splitT);
    // Extract time
    timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
    pDBGln(formattedDate);  
    pDBG("DATE: ");
    pDBGln(dayStamp);
    pDBG("HOUR: ");
    pDBGln(timeStamp);    
  #endif
  
  curDateTime  = formattedDate.substring(8,10);  //day
  curDateTime += formattedDate.substring(5,7);   //month
  curDateTime += formattedDate.substring(2,4);   //year
  curDateTime += formattedDate.substring(11,13); //hour
  curDateTime += formattedDate.substring(14,16); //minute
  curDateTime += formattedDate.substring(17,19); //seconds
  return curDateTime;
}

So I have got a step further by reducing the the code to the above.

The receiver loop section and is looking for myTransfer.available to become available and this is where the issue lies.

I need to place other display, and functions in the loop section but what appears to be happening is any other code is interupting the transfer and that where I am confused.

The reciever GPIO pin 14/15 and Reciever GPIO 0,39 for example is where the image is tranferred (Serial2). So what is my misunderstanding here is slave send a image via serial to the master across this pins via serial2, that any other code in the loop causes the CRC error which is the brokenup transfer?

  mqtt.loop(); //calls mqtt.loop in the pubsubclient library

  // Display the Alarm Bell
  display.clearDisplay();
  display.drawBitmap(0, 0, NoMovement, 128, 64, WHITE);
  display.setCursor(29, 57);
  //display.print(" A R M E D ");
  display.display();
  //display.display();

  //Update and also check temperature
  Update_temp();
  Temp_Overthreshold();

// PIR Detector Enable / Disable
    if ((PIRonoffStatus) == HIGH ) {
    display.clearDisplay();
    display.drawBitmap(0, 0, NoMovement, 128, 64, WHITE);
    display.setCursor(29, 57);
    display.print(" A R M E D ");
    display.display();
    Check_PIR();
    //Serial.print("PIR Sensor: ");
    //Serial.println(PIRonoffStatus);
  }
  else {
    display.clearDisplay();
    display.drawBitmap(0, 0, NoMovement, 128, 64, WHITE);
    display.setCursor(15, 57);
    display.print(" D I S A R M E D ");
    display.display();
    //delay(1000);
    //Serial.print("PIR Sensor: ");
    //Serial.println(PIRonoffStatus);
  }

How do I get around being able to add any other code to the loop section? Where transferphoto() is the reciever code loop section?

E.g.

void loop()
{
    if (myTransfer.available()) {
    SerialMon.println(myTransfer.status); 
    //transferphoto();
    //}
    else {
    //SerialMon.println("status not 0"); 
    }
} // close of loop section

Seriously, why do you care if there is a CRCC error? You have no error recovery mechanism.

CRC is telling me that the file hasn't transferred.

I guess my point was how to accommodate other functions into the loop and to allow it to continue to check if a transfer is available?

A CRC error tells you there is at least one bit error in that message.

Thanks and thats due to adding code as per my example to the loop. I need a way to listen for a transfer but also add my code in the loop.

if(myTransfer.available()) 

If available transfer else run my other functions. I can seem to figure out how to determine if a transfer available or not.

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