Alexander idid
Alexander idid

Reputation: 11

Problems with ESP32 WROOM 32U, SIMCOM A7670 and LoRa cores

Description: My current project uses the two cores of the ESP32 WROOM 32U to run two tasks in parallel: one for LoRa communication, where I receive text strings, and another for connection to an MQTT server via a SIMCOM modem that connects to 4G using AT commands. I faced two main problems:

- Watchdog Timer Reboot Issue: I experience ESP32 reboots due to Watchdog Timer, especially when disconnecting from the server, internet, or when starting the ESP32 for the first time.

Problem details:

Detailed description of the problem: The main problem lies in the failures when using both cores: the restart by the Watchdog.

Steps taken: I have extensively reviewed my code over several days to ensure that it is properly adapted to the hardware and network configuration. Additionally, I have verified the physical hardware connections and network settings on the MQTT server. I have tried several solutions suggested on forums, such as using timers like 'vTaskDelay', but none have effectively solved the problem.

Error Logs:


09:52:24.052 -> E (38279) task_wdt: CPU 1: loopTask
09:52:24.052 -> E (38279) task_wdt: Aborting.
09:52:24.052 -> E (38279) task_wdt: Print CPU 0 (current core) backtrace
09:52:24.052 -> 
09:52:24.052 -> 
09:52:24.052 -> 
09:52:24.052 -> 
09:52:24.052 -> Backtrace: 0x40082d29:0x3ffb47f0 0x40089a22:0x3ffb4810 0x400d5ce9:0x3ffb4830 0x400d1c92:0x3ffb4850 0x400d1e82:0x3ffb4880 0x400d1ed1:0x3ffb48e0 0x400d27e8:0x3ffb4910 0x400d2829:0x3ffb4930 0x400d2d21:0x3ffb4950 0x400d2d75:0x3ffb4970 0x400d2e63:0x3ffb49b0
09:52:24.087 -> 
09:52:24.087 -> 
09:52:24.087 -> 
09:52:24.087 -> 
09:52:24.087 -> ELF file SHA256: 717e4228e872b1c6
09:52:24.087 -> 
09:52:24.087 -> Rebooting...
09:52:24.087 -> ets Jul 29 2019 12:21:46
09:52:24.087 -> 
09:52:24.087 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)

code

//Sistema
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <string.h>

//EEPROM
#include <EEPROM.h>

//Lora
#include <SPI.h>
#include <LoRa.h>

//Simcom ~ mqtt
#define TINY_GSM_MODEM_SIM7600 //a7670xx
#define TINY_GSM_RX_BUFFER 1024
#define SerialAT Serial1
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false

#include <TinyGsmClient.h>
#include <PubSubClient.h>

//Pin Lora
#define ss 4
#define rst 25
#define dio0 27

//config EEPROM -- Registros Date
#define ARRAY_SIZE 80 // Tamaño del array para las fechas
#define EEPROM_START_ADDRESS 0 // Dirección de inicio en la EEPROM
struct DataStruct {
  char data[21];
};

DataStruct dateTimeRegistrerMaster[ARRAY_SIZE];
#define DATOS_SIZE sizeof(dateTimeRegistrerMaster[0].data)
#define EEPROM_SIZE (ARRAY_SIZE * sizeof(DataStruct))
int counterRecived = 0;

// Configuración EEPROM -- Registros Order
#define ARRAY_SIZE_NEW 10 // Tamaño del array para los nuevos registros
#define EEPROM_START_ADDRESS_NEW (EEPROM_START_ADDRESS + EEPROM_SIZE) // Nueva dirección de inicio en la EEPROM para los nuevos registros

struct OrderDataStruct {
  char data[8]; // Nueva estructura para los nuevos registros
};

OrderDataStruct orderMqttStorage[ARRAY_SIZE_NEW];
#define NEW_DATOS_SIZE sizeof(orderMqttStorage[0].data)
#define NEW_EEPROM_SIZE (ARRAY_SIZE_NEW * sizeof(OrderDataStruct))
int counterRecivedMqtt = 0;

//Sistena
const int ledPin = 2;

//Lora identificación dispositivo
byte localAddress = 0xFF;   // Dirección de este dispositivo
const char* customDeviceID = "aa01";

char completeLocalAddress[7]; 


// byte destination = 0xBB;    // Dirección a la que enviar mensajes

//Config Simcom - mqtt
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqttClient(client);

const char* mqtt_server = "Myserver mqtt"; 
const int mqtt_port = 7010;//for example 1884
const char* mqtt_sub_topic = "TopicNa";
const char* mqtt_pub_topic = "Topic2";

//Config APN
const char apn[] = "Apncfg";
const char gprsUser[] = "user";
const char gprsPass[] = "pass"; 

//Config  perdurancia internet
bool networkConnected = false;
bool gprsConnected = false;


//Creamos 2 tareas
TaskHandle_t simComMqtt;
TaskHandle_t loraProtocol;


void setup() {
  Serial.begin(115200);
  SerialAT.begin(115200, SERIAL_8N1, 16, 17); // RX y TX  -- Comunicación SimCom 
  delay(3000); // Espera para que el módem se inicialice correctamente

  //Desactivar pines bornOut
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  // SetUp pines
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);


 //Memoria EEPROM
  EEPROM.begin(EEPROM_SIZE + NEW_EEPROM_SIZE);
  initializeEEPROMData<DataStruct>(ARRAY_SIZE, EEPROM_START_ADDRESS); //Registros
  initializeEEPROMData<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW); //Ordenes

  //SetUp Lora
  while (!Serial);
  Serial.println("LoRa Duplex");
  LoRa.setPins(ss, rst, dio0);
  while (!LoRa.begin(433E6)) {
    Serial.println(".");
    delay(500);
  }
  
  // Ajusta el nivel de potencia de salida (en dBm)
  LoRa.setTxPower(0); // Prueba con diferentes valores, 20 dBm es el máximo para SX1278
  // Establece el factor de esparcimiento en 10
  LoRa.setSpreadingFactor(10);
  // Ancho de banda de 125 kHz
  LoRa.setSignalBandwidth(125E3);
  // Tasa de codificación de 4/5
  LoRa.setCodingRate4(5);
  // Longitud del preámbulo de 8 símbolos
  LoRa.setPreambleLength(8);
  LoRa.setSyncWord(0xF3);
  Serial.println("LoRa Initializing OK!"); 

  // Setup SimCom
  String name = modem.getModemName();
  Serial.print("Modem Name: ");  
  Serial.println(name);

  String ccid = modem.getSimCCID();
  Serial.println("CCID: " + ccid);

  String imei = modem.getIMEI();
  Serial.println("IMEI: " + imei);

  String cop = modem.getOperator();
  Serial.println("Operator: " + cop);

  IPAddress local = modem.localIP();
  Serial.println("Local IP: " + String(local));

  int csq = modem.getSignalQuality();
  Serial.println("Signal quality: " + String(csq));

  Serial.print("Esperando a la red...");
  // reconnectNetwork(); // Asegura la conexión de red en el setup

  Serial.print(F("Conectando a "));
  Serial.print(apn);

  //SetUp Mqtt 
  mqttClient.setServer(mqtt_server, mqtt_port);
  mqttClient.setCallback(callback);

  //Tarea para Wifi & Mqtt
  xTaskCreatePinnedToCore(
                    simComMqttcode,   /* Task function. */
                    "simComMqtt",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &simComMqtt,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */                  
  delay(500); 

  //Tarea para solo lora
  xTaskCreatePinnedToCore(
                    loraProtocolcode,   /* Task function. */
                    "loraProtocol",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &loraProtocol,      /* Task handle to keep track of created task */
                    1);          /* pin task to core 1 */
    delay(500); 

}

//~ Funcion SimCom Conexion 4G
void reconnectNetwork() {
  if (!modem.isNetworkConnected()) {
    Serial.println("Red 4G desconectada");
    while (!modem.isNetworkConnected()) {
      if (!modem.waitForNetwork(10000L, true)) {  // 10 segundos de espera
        Serial.println("Fallo en conexion a red 4G");
        delay(5000);  // Espera 10 segundos antes de intentar de nuevo
      }
    }
    Serial.println("Red reconectada");
    networkConnected = true;
  }

  if (!modem.isGprsConnected()) {
    Serial.println("GPRS desconectado!");
    while (!modem.isGprsConnected()) {
      Serial.println("Conectando a GPRS");
      if (!modem.gprsConnect(apn, gprsUser, gprsPass)) { // Añadido: Llama a gprsConnect() con los argumentos apropiados
        Serial.println("Fallo en conexion");
        delay(5000);  // Espera 10 segundos antes de intentar de nuevo
      }
    }
    Serial.println("GPRS reconectado");
    gprsConnected = true;
  }
}

// ~ Funciones Mqtt
void reconnectMQTT() {
  reconnectNetwork();
  while (!mqttClient.connected()) {
    Serial.println("Conectando al broker MQTT...");
    mqttClient.setServer(mqtt_server, mqtt_port);
    mqttClient.setCallback(callback);  // Establecer la función de callback

    if (mqttClient.connect("ESP32Client")) {
      Serial.println("Conectado al broker MQTT");
      mqttClient.subscribe(mqtt_sub_topic);
    } else {
      Serial.print("Error de conexión al broker MQTT, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" Intentando de nuevo en 2 segundos");
      delay(2000);  // Espera 15 segundos antes de intentar de nuevo
    }
  }
  
}

//CallBack de topico mqtt
void callback(char* topic, byte* payload, unsigned int length) {
  // Convertir el payload a una cadena de caracteres
  char payloadStr[length + 1];
  for (int i = 0; i < length; i++) {
    payloadStr[i] = (char)payload[i];
  }
  payloadStr[length] = '\0'; // Añadir el carácter nulo al final de la cadena
  String payloadString = String(payloadStr); //Casteo a String
  Serial.println("Esta es la trama que recibo del mqtt: ");
  Serial.println(payloadString);

  //Extraer los primeros cuatro caracteres como una subcad
  String mqttMasterAdress = payloadString.substring(0, 6); //Direccion maestro
  String mqttSlaveOrder = payloadString.substring(6,10); //esclavo y orden

  //Obtener la dirección completa del dispositivo
  sprintf(completeLocalAddress, "%02X%s", localAddress, customDeviceID);
  String completeLocalAddressString = String(completeLocalAddress);


  if (mqttMasterAdress == completeLocalAddressString){
    Serial.println("Coincide");
    Serial.println("Almacenando orden MQTT en EEPROM...");
    strcpy(orderMqttStorage[counterRecivedMqtt].data, mqttSlaveOrder.c_str());
    storeDataInEEPROM<OrderDataStruct>(counterRecivedMqtt, orderMqttStorage[counterRecivedMqtt], EEPROM_START_ADDRESS_NEW);
    counterRecivedMqtt++;
    
    if (counterRecivedMqtt >= ARRAY_SIZE_NEW) {
      counterRecivedMqtt=0;
    }

  }else{
    Serial.println("La orden enviada no coincide con la dirección del maestro");

    readDataFromEEPROM<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW);
  }

}

//Enviar EEPROM mqtt 
void sendDataEepromMqtt() {
  for (int i = 0; i < ARRAY_SIZE; i++) {
    int address = EEPROM_START_ADDRESS + (i * sizeof(DataStruct));
    DataStruct data;
    EEPROM.get(address, data);
    if(strlen(data.data) == 0){
      continue;
    }else {
      //Enviar datos al mqtt
      Serial.println(data.data);
      mqttClient.publish("AlertaETB",data.data);
      delay(200);

      // Borrar el dato de la EEPROM
      DataStruct emptyData;
      memset(emptyData.data, 0, sizeof(emptyData.data)); // Inicializar los datos con 0
      EEPROM.put(address, emptyData); // Escribir datos vacíos en la EEPROM
      EEPROM.commit(); // Guardar los cambios en la EEPROM
    }
  }
}


//Funciones Lora
void onReceive(int packetSize) {
  if (packetSize == 0) return; // Salir si no hay datos
  
  byte recipient = LoRa.read(); // Leer la dirección del destinatario
  byte sender = LoRa.read(); // Leer la dirección del remitente
  
  // Leer la fecha y hora como una cadena de caracteres
  char dateTime[18]; // Tamaño suficiente para almacenar la fecha y hora en formato YYYYMMDDHHMMSS
  for (int i = 0; i < 12; i++) {
    dateTime[i] = LoRa.read();
  }
  dateTime[12] = '\0'; // Añadir un carácter nulo al final para indicar el final de la cadena

  // Leer el valor adicional
  uint8_t value = LoRa.read();

  // Imprimir la información recibida
  Serial.print("Received from: 0x");
  Serial.println(sender, HEX);
  Serial.print("Date and Time: ");
  Serial.println(dateTime);
  Serial.print("Additional Value: ");
  Serial.println(value);
  Serial.print("RSSI: ");
  Serial.println(LoRa.packetRssi());
  Serial.println();

  //Envio mqtt & confirmación a esclavo Alerta
  if (value == 1) {
    digitalWrite(ledPin, HIGH); // Enciende el LED si el mensaje recibido es 1
    //Guardar datos en la memoria ~~ Se envian cuando haya conexion mqtt
    String datosApertura =  String(localAddress, HEX) + String(customDeviceID) + String(sender, HEX) + String(dateTime);

    //Enviar confirmación & orden SOTA a Slave especifico
    sendOrderSlave(sender);

    int dataToSend=1;
    sendMessage(sender, dataToSend);//Envio de confrimacion


    delay(200);
    digitalWrite(ledPin, LOW);
    Serial.println("Almacenar datos en EEPROM");
    strcpy(dateTimeRegistrerMaster[counterRecived].data, datosApertura.c_str());
    storeDataInEEPROM<DataStruct>(counterRecived, dateTimeRegistrerMaster[counterRecived], EEPROM_START_ADDRESS);

    // Incrementar el contador
    counterRecived++;
    if (counterRecived >= ARRAY_SIZE) {
      counterRecived=0;
    }
  }
}

void sendMessage(byte destination,int outgoing) {
  LoRa.beginPacket();
  LoRa.write(destination);
  LoRa.write(localAddress);
  LoRa.write(sizeof(outgoing)); // Enviar el tamaño del entero
  LoRa.write((uint8_t*)&outgoing, sizeof(outgoing)); // Enviar el entero
  delay(500); // Puedes ajustar el tiempo según tus necesidades
  LoRa.endPacket();
  Serial.println("Se envio confirmación");
}

//~ Tareas
//simComMqttcode: Intenta conectarse a wifi & mqtt - Envia los datos de almacenados
void simComMqttcode(void *pvParameters) {
  while (true) {
    // Manejar reconexión si se pierde la conexión MQTT
    if (!mqttClient.connected()) {
        // reconnectNetwork();
        reconnectMQTT();
        // readDataFromEEPROM<DataStruct>(ARRAY_SIZE, EEPROM_START_ADDRESS);
        // readDataFromEEPROM<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW);
    } else {
        // Envía datos al servidor si está conectado a MQTT
        sendDataEepromMqtt();
    }
    
    mqttClient.loop();
    delay(10); // Pequeña pausa para permitir que otras tareas se ejecuten
  }
}

//loraProtocolcode: Escucha entradas Lora
void loraProtocolcode( void * pvParameters ){
  while (true) {
    int packetSize = LoRa.parsePacket();
    if (packetSize) {
      onReceive(packetSize);
    }
    delay(10); // Pequeña pausa para permitir que otros hilos se ejecuten
  }
}

//DEBE ESTAR VACIO
void loop() {
}

Code note: I do not upload some parts of the code to have better readability, these parts are related to the storage of the information obtained from the Lora protocol in the EEPROM memory

Purpose of the post:

I am seeking assistance from the community to find a solution to this problem.

I appreciate any help or suggestions to resolve these issues!

Upvotes: 0

Views: 263

Answers (1)

hcheung
hcheung

Reputation: 4034

onReceive(packetSize);

  1. onReceive() function is a callback setup function to be called once only (i.e. during setup), not to be called endlessly in a task as you did in the loraProtocolcode task.
  2. the onReceive() API is expecting a pointer to a callback function as the parameter onReceive(callback_func). See example.
  3. If you want to do "polling" in a task loop, again, there is example for it.

Upvotes: 0

Related Questions