LoRa Problem Slow code or Error Code

Hi everyone. I created some code on an ESP32 to acquire info from multiple sensors, and save it to an SD, and I also wanted to send it via LoRa radio. the original code I created worked very well both for saving data on the SD card and for printing them on the serial port quite quickly. the problem is that by introducing LoRa it either slows down the code (if I put the data sending in the main loop) or if I separate it into a separate task on the extra core of the ESP32 it works but after a certain amount of time it signals me on the serial line that errors are writing to the SD and it slows down. How can I solve it? I'm not good at programming....

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <SPI.h>
#include <Adafruit_BME680.h>
#include <TinyGPS++.h>
#include <Adafruit_INA219.h>
#include <SD.h>

#include <LoRa.h>
const int ss = 15;    // Pin CS (Chip Select)
const int rst = 33;  // Pin RST (Reset)
const int dio0 = 32;  // Pin IRQ (Interrupt Request)
byte destination = 0x3D;

// Dichiarazione dei pin
#define BME_SCK 22
#define BME_MOSI 21
#define SEALEVELPRESSURE_HPA (1013.25)

// Dichiarazione degli oggetti dei sensori
Adafruit_BNO055 bno = Adafruit_BNO055(-1, 0x28, &Wire);
Adafruit_BME680 bme;
TinyGPSPlus gps;
Adafruit_INA219 ina219;

// Dichiarazione delle variabili per i dati dei sensori
float roll, pitch, yaw, roll_d, pitch_d, yaw_d;
float temperature, humidity, pressure, altitude;
float lat, lng, alt, speed = 0;
int year, month, day, hour, minute, second = 0;
float shuntvoltage, busvoltage, current_mA, loadvoltage, power_mW;

// Offsets BNO055
int16_t offsets[] = {-26, 13, 0, -1, 0, 0, 2585, -13725, 32700, 1000, 627};

// Variabili per il controllo del tempo
uint32_t lastExecution = 0;
uint32_t currentMillis = 0; // Dichiarazione di currentMillis come variabile globale

uint32_t lastSendTime = 0;
const uint32_t sendInterval = 2000; // Intervallo di invio in millisecondi (2 secondi)

String sensorData;

// Oggetto per la scheda SD
File dataFile;

// Funzione per leggere i dati del sensore BME680 e INA219 (da eseguire sul secondo core)
void readSensorData(void * parameter) {
  uint32_t lastSendTime = 0;
  const uint32_t sendInterval = 2000; // Intervallo di invio in millisecondi (2 secondi)

  while (true) {
    // Lettura dei dati del sensore BME680
    temperature = bme.readTemperature();
    humidity = bme.readHumidity();
    pressure = bme.readPressure() / 100;
    altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);

    // Lettura dei dati del sensore INA219
    shuntvoltage = ina219.getShuntVoltage_mV();
    busvoltage = ina219.getBusVoltage_V();
    current_mA = ina219.getCurrent_mA();
    power_mW = ina219.getPower_mW();
    loadvoltage = busvoltage + (shuntvoltage / 1000);

    // Invio dei dati tramite LoRa ogni 2 secondi
    
      // Trasmissione dei dati tramite LoRa
      LoRa.beginPacket();
      LoRa.write(destination);
      LoRa.print("£ , ");  
      LoRa.print(altitude);
      LoRa.print(" , ");
      
      LoRa.print(lat);
      LoRa.print(" , ");
      
      LoRa.print(lng);
      LoRa.print(" , ");
      LoRa.endPacket(); 
    

    // Attendi per un secondo prima di eseguire una nuova lettura
    delay(3000);
  }
}


void setup() {
  Serial.begin(115200);
  Serial2.begin(9600); // Inizializzazione del GPS su Serial2
  delay(1000);

  // Inizializzazione del sensore BNO055
  if (!bno.begin(OPERATION_MODE_NDOF)) {
    Serial.println("Could not find BNO055 sensor!");
    while (1);
  }
  // Calibrazione offset BNO055 
  adafruit_bno055_offsets_t calibrationData;
  calibrationData.accel_offset_x = offsets[0];
  calibrationData.accel_offset_y = offsets[1];
  calibrationData.accel_offset_z = offsets[2];
  calibrationData.gyro_offset_x = offsets[3];
  calibrationData.gyro_offset_y = offsets[4];
  calibrationData.gyro_offset_z = offsets[5];
  calibrationData.mag_offset_x = offsets[6];
  calibrationData.mag_offset_y = offsets[7];
  calibrationData.mag_offset_z = offsets[8];
  calibrationData.accel_radius = offsets[9];
  calibrationData.mag_radius = offsets[10];
  bno.setSensorOffsets(calibrationData);

  // Inizializzazione del sensore BME680
  if (!bme.begin()) {
    Serial.println("Could not find BME680 sensor!");
    while (1);
  }

  // Configurazione delle impostazioni del sensore BME680
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);

  // Inizializzazione del INA219
  if (!ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    while (1) { delay(10); }
  }

  Serial.println("Measuring voltage and current with INA219 ...");

  // Inizializzazione della scheda SD
  if (!SD.begin(5)) {
    Serial.println("Card failed, or not present");
    while (1);
  }

  // Creazione del file di log
  dataFile = SD.open("/datalog.txt", FILE_APPEND);
  if (dataFile) {
    dataFile.println("NUOVO Avvio test");
    dataFile.println("£ , ANNO , MESE , GIORNO , ORA , MINUTO , SECONDI , ROLL , PITCH , YAW , ROLL_D , PITCH_D , YAW_D , LAT , LONG , ALT , SPEED , $");
    dataFile.close();
  } else {
    Serial.println("Errore apertura file in scrittura");
  }
    // Inizializza il modulo LoRa con i pin specifici
  LoRa.setPins(ss, rst, dio0);
  if (!LoRa.begin(868E6)) {
   Serial.println("Starting LoRa failed!");
    while (1);  }
  LoRa.setTxPower(17);   //17 dB (defoult)(max power)
  LoRa.setSpreadingFactor(10);  //7 defoult (can be set from 6 to 12)
  LoRa.setSignalBandwidth(62.5E3); //125E3 defoult (7.8 10.4 15.6 20.8 31.25 41.7 62.5 125 250 500) 
  LoRa.setCodingRate4(8); //5 defoult (can be from 5 to 8 that correspond to 4/5 and 4/8)

  // Creazione di un task separato per leggere i dati del sensore BME680 e INA219 (Core 1)
  xTaskCreatePinnedToCore(
    readSensorData,            // Funzione da eseguire
    "readSensorData",          // Nome del task
    10000,                     // Dimensione dello stack del task
    NULL,                      // Parametro passato alla funzione
    1,                         // Priorità del task
    NULL,                      // Handle del task (opzionale)
    1                          // Core su cui eseguire il task (Core 1)
  );
}

void loop() {
  currentMillis = millis(); // Aggiorna il valore di currentMillis

  // Controllo del tempo per la lettura del sensore BNO055 ogni 100 millisecondi
  invio();
}

void invio(){
  if (currentMillis - lastExecution >= 100) {
    lastExecution += 100;

    // Lettura dei dati del sensore BNO055
    imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);
    yaw = euler.x();
    roll = euler.y();
    pitch = -euler.z();

    imu::Vector<3> gyro = bno.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
    yaw_d = gyro.z();
    roll_d = gyro.y();
    pitch_d = gyro.x();

    // Lettura dei dati del GPS
    while (Serial2.available() > 0) {
      if (gps.encode(Serial2.read())) {
        if (gps.location.isValid()) {
          lat = gps.location.lat();
          lng = gps.location.lng();
        }
        if (gps.altitude.isValid()) {
          alt = gps.altitude.meters();
        }
        if (gps.speed.isValid()) {
          speed = gps.speed.kmph();
        }
        if (gps.date.isValid() && gps.time.isValid()) {
          year = gps.date.year();
          month = gps.date.month();
          day = gps.date.day();
          hour = gps.time.hour();
          minute = gps.time.minute();
          second = gps.time.second();
        }
      }
    }

    // Creazione della stringa con i dati dei sensori
    sensorData = "&, ";
    sensorData += String(roll) + "," + String(pitch) + "," + String(yaw) + ",";
    sensorData += String(roll_d) + "," + String(pitch_d) + "," + String(yaw_d) + ",";
    sensorData += String(temperature) + "," + String(pressure) + "," + String(humidity) + "," + String(altitude) + ",";
    sensorData += String(year) + "," + String(month) + "," + String(day) + "," + String(hour) + "," + String(minute) + "," + String(second) + ",";
    sensorData += String(lat) + "," + String(lng) + "," + String(alt) + "," + String(speed) + ",";
    sensorData += String(busvoltage) + "," + String(shuntvoltage) + "," + String(loadvoltage) + "," + String(current_mA) + "," + String(power_mW) + ", §";

    // Stampa dei dati dei sensori
    Serial.println(sensorData);

    // Salvataggio dei dati su scheda SD
    dataFile = SD.open("/datalog.txt", FILE_APPEND);
    if (dataFile) {
      dataFile.println(sensorData);
    } else {
      Serial.println("Errore apertura file in scrittura");
    }
  }
}

I think the problem has to do with a conflict between the Lora and the SD. I tried removing the SD loop and it seems to go fast on the serial and at the same time sends the data to the Lora receiver. how can I solve it then? because I would like to save all the fast data on the SD while occasionally sending useful data.

A number of SD modules on the market are known not to share the SPI bus properly. Post the details of your setup and forum members can advise.

And of course, the delay(3000) simply wastes 3 seconds:

    // Attendi per un secondo prima di eseguire una nuova lettura
    delay(3000);

I use an SD module with a jumper between 3.3V and 5V (it works fine on its own but maybe you're right). I use this:
image

https://www.amazon.com/HiLetgo-Adater-Interface-Conversion-Arduino/dp/B07BJ2P6X6

for lora radio this:

That looks like the type of module with the problem. See this post for a possible fix.

I just finished testing both the hardware and software solutions but in both cases it doesn't solve the problem, I think it's the lora or the library I'm using...

If the radio works alone, without the SD module, there is nothing obviously wrong with it or the library, and there is nothing to fix with the setup.

Some sort of interaction between the radio and the SD module is a possibility, but to determine the nature of the problem will require some test equipment and technical skills.

but if instead I have another ESP with an SD connected, is there a way to send the printed data to the serial print of the primary ESP? It seems to me that rx0 and tx0 are connected to the d-d+ of the USB port, right? or I create a connector that transmits d+ d- crossed between the two esp32. so that the secondary esp receives the serial print of the fast primary esp and stores the input data. Correct me if it's a valid or bizarre idea

yes - the ESP32 has three hardware serial ports Serial, Serial1 and Serial2
have a look at post serial-communication-between-arduino-and-2-esp32

Very, very unlikely.

The LoRa library you are using has been around for a while with a great many Arduino users. It would seem unlikely that you have discovered a bug.

On an ESP32 I have seen issues with mixing SPI LoRa devices and SPI SD cards on the same bus, the problem appears to be something to do with espressifs implementation of the SD library, since this problem only appears to manifest itself on an ESP32.

If you want to use an SD card on an ESP32 then put it on its own seperate SPI bus, this is easy enough to do, and its much more reliable.

Not sure why your doing an SD.open() possibly every time a GPS character is read.

as @srnet recommended If you want to use an SD card on an ESP32 then put it on its own seperate SPI bus

this ESP32 code uses two SPI devices a SD reader (on HSPI) and a MFRC522 RFID card reader (on VSPI)

// SD card test modified to use HSPI
// see https://forum.arduino.cc/t/esp32-initialize-hspi-as-default-spi/1155093/12

/* original SD code from
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-microsd-card-arduino/
*/

// define HSPI pins
#define HSPI_SCK 4
#define HSPI_MISO 16
#define HSPI_MOSI 17
#define SD_CS 15

// default HSPI pins crash processor
/*#define HSPI_SCK 14
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define SD_CS 15*/

#include "FS.h"
#include "SD.h"
#include "SPI.h"

SPIClass *hspi = NULL;  // SPI object

// MFRC522 RFID reader
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
MFRC522DriverPinSimple ss_1_pin(5);  // Configurable, take an unused pin, only HIGH/LOW required, must be different to SS 2.
MFRC522DriverSPI driver_1{ ss_1_pin };
MFRC522 reader = driver_1;  // Create MFRC522 instance.

// ESP32 RTC
#include <ESP32Time.h>
ESP32Time rtc(3600);  // offset in seconds GMT+1

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("Read MRFC522 RFID card save time and data to SD card");
  rtc.setTime(1609459200);  // initialise RTC 1st Jan 2021 00:00:00
  // setup SD card reader
  hspi = new SPIClass(HSPI);                           // create SPI class
  hspi->begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, SD_CS);  // setup SPI pins
  if (!SD.begin(SD_CS, *hspi)) {                       // mount card
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();
  if (cardType == CARD_NONE) {
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if (cardType == CARD_MMC) {
    Serial.println("MMC");
  } else if (cardType == CARD_SD) {
    Serial.println("SDSC");
  } else if (cardType == CARD_SDHC) {
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
  listDir(SD, "/", 0);
  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));

  // setup MRFC522 RFID reader
  Serial.print("open MRFC522 RFID reader");
  reader.PCD_Init();  // Init MFRC522 card.
  MFRC522Debug::PCD_DumpVersionToSerial(reader, Serial);
}

void loop() {
  // check Serial input read or delete data file
  if (Serial.available()) {
    char ch = Serial.read();
    if (ch == 'p')
      readFile(SD, "/data.txt");
    if (ch == 'd')
      deleteFile(SD, "/data.txt");
  }
  // check MFRC522 RFID reader
  if (reader.PICC_IsNewCardPresent() && reader.PICC_ReadCardSerial()) {
    Serial.print("\n");
    Serial.println(rtc.getTime("%A, %B %d %Y %H:%M:%S"));  // (String) returns time with specified format
    // Show some details of the PICC (that is: the tag/card).
    Serial.print(F(" Card UID:"));
    MFRC522Debug::PrintUID(Serial, reader.uid);
    Serial.print("  PICC type: ");
    MFRC522::PICC_Type piccType = reader.PICC_GetType(reader.uid.sak);
    Serial.println(MFRC522Debug::PICC_GetTypeName(piccType));
    // save card details to SD
    String s = rtc.getTime("%A, %d/%m/%Y %H:%M:%S") + " Card UID:";
    for (byte i = 0; i < reader.uid.size; i++) {
      char text[10] = { 0 };
      snprintf(text, 100, " 0x%2X", reader.uid.uidByte[i]);
      s += String(text);
    }
    s += "  PICC type: " + String((const char *)MFRC522Debug::PICC_GetTypeName(piccType)) + "\n";
    appendFile(SD, "/data.txt", s.c_str());
    // Halt PICC.
    reader.PICC_HaltA();
    // Stop encryption on PCD.
    reader.PCD_StopCrypto1();
    delay(1000);
  }
}
// ************** SD functions **************************

void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {
  Serial.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      Serial.print("  DIR : ");
      Serial.println(file.name());
      if (levels) {
        listDir(fs, file.name(), levels - 1);
      }
    } else {
      Serial.print("  FILE: ");
      Serial.print(file.name());
      Serial.print("  SIZE: ");
      Serial.println(file.size());
    }
    file = root.openNextFile();
  }
}

void createDir(fs::FS &fs, const char *path) {
  Serial.printf("Creating Dir: %s\n", path);
  if (fs.mkdir(path)) {
    Serial.println("Dir created");
  } else {
    Serial.println("mkdir failed");
  }
}

void removeDir(fs::FS &fs, const char *path) {
  Serial.printf("Removing Dir: %s\n", path);
  if (fs.rmdir(path)) {
    Serial.println("Dir removed");
  } else {
    Serial.println("rmdir failed");
  }
}

void readFile(fs::FS &fs, const char *path) {
  Serial.printf("\nReading file: %s\n", path);

  File file = fs.open(path);
  if (!file) {
    Serial.println("Failed to open file for reading");
    return;
  }

  //Serial.print("Read from file: ");
  while (file.available()) {
    Serial.write(file.read());
  }
  file.close();
}

void writeFile(fs::FS &fs, const char *path, const char *message) {
  Serial.printf("Writing file: %s\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if (file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

void appendFile(fs::FS &fs, const char *path, const char *message) {
  //Serial.printf("Appending to file: %s\n", path);

  File file = fs.open(path, FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if (file.print(message)) {
    //Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void renameFile(fs::FS &fs, const char *path1, const char *path2) {
  Serial.printf("Renaming file %s to %s\n", path1, path2);
  if (fs.rename(path1, path2)) {
    Serial.println("File renamed");
  } else {
    Serial.println("Rename failed");
  }
}

void deleteFile(fs::FS &fs, const char *path) {
  Serial.printf("Deleting file: %s\n", path);
  if (fs.remove(path)) {
    Serial.println("File deleted");
  } else {
    Serial.println("Delete failed");
  }
}

void testFileIO(fs::FS &fs, const char *path) {
  File file = fs.open(path);
  static uint8_t buf[512];
  size_t len = 0;
  uint32_t start = millis();
  uint32_t end = start;
  if (file) {
    len = file.size();
    size_t flen = len;
    start = millis();
    while (len) {
      size_t toRead = len;
      if (toRead > 512) {
        toRead = 512;
      }
      file.read(buf, toRead);
      len -= toRead;
    }
    end = millis() - start;
    Serial.printf("%u bytes read for %u ms\n", flen, end);
    file.close();
  } else {
    Serial.println("Failed to open file for reading");
  }


  file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }

  size_t i;
  start = millis();
  for (i = 0; i < 2048; i++) {
    file.write(buf, 512);
  }
  end = millis() - start;
  Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
  file.close();
}

serial monitor output

Read MRFC522 RFID card save time and data to SD card
SD Card Type: SDHC
SD Card Size: 14992MB
Listing directory: /
  DIR : System Volume Information
  FILE: test.txt  SIZE: 1048576
  FILE: data.txt  SIZE: 891
Total space: 14984MB
Used space: 2MB
open MRFC522 RFID readerFirmware Version: 0x92 = v2.0
dDeleting file: /data.txt
File deleted

Friday, January 01 2021 01:00:14
 Card UID: ZZ XX FD C2  PICC type: MIFARE 1KB

Friday, January 01 2021 01:00:18
 Card UID: Z0 XF 62 1A  PICC type: MIFARE 1KB

Friday, January 01 2021 01:00:19
 Card UID: Z0 XF 62 1A  PICC type: MIFARE 1KB

Friday, January 01 2021 01:00:22
 Card UID: ZZ XX FD C2  PICC type: MIFARE 1KB

Friday, January 01 2021 01:00:23
 Card UID: ZZ XX FD C2  PICC type: MIFARE 1KB

Friday, January 01 2021 01:02:30
 Card UID: Z0 XF 62 1A  PICC type: MIFARE 1KB
p
Reading file: /data.txt
Friday, 01/01/2021 01:00:14 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:18 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:19 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:22 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:23 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:02:30 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB

Friday, January 01 2021 01:03:28
 Card UID: ZZ XX FD C2  PICC type: MIFARE 1KB
p
Reading file: /data.txt
Friday, 01/01/2021 01:00:14 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:18 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:19 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:22 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:00:23 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:02:30 Card UID: 0xZ0 0xXF 0x62 0x1A  PICC type: MIFARE 1KB
Friday, 01/01/2021 01:03:28 Card UID: 0xZZ 0xXX 0xFD 0xC2  PICC type: MIFARE 1KB

EDIT: ran tests with both SD reader and MFRC522 RFID reader connected to VSPI
running separate test programs (connecting SS of device to GPIO5) SD reader works OK MFRC522 gives
Reader 1: = (unknown)
WARNING: Communication failure, is the MFRC522 properly connected?

as soon as I disconnect SD reader MISO and MOSI the MFRC522 gives
Reader 1: Firmware Version: 0x92 = v2.0

clearly problems attempting to use SD reader and another device on same SPI bus

1 Like

thank it's work :slight_smile:

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