Corrupt HEAP - ESP23 - BlynkEdgent

Hi, In order to use the dual core capabilities of ESP32 to avoid the BlynkEdgent blocking of the devices process I’m migrating my code (originally designed for ESP8266) to ESP32.

I already made some succesful testing using dual core and avoiding edgent blocking. See this topic

But now, when try to test my full code, I’m getting this error:

13:00:17.851 -> CORRUPT HEAP: Bad head at 0x3ffd5de0. Expected 0xabba1234 got 0x3ffdae0c
13:00:17.901 -> abort() was called at PC 0x40086ad9 on core 0
13:00:17.901 -> 
13:00:17.901 -> ELF file SHA256: 0000000000000000
13:00:17.901 -> 
13:00:17.901 -> Backtrace: 0x400887a0:0x3ffcfc60 0x40088a1d:0x3ffcfc80 0x40086ad9:0x3ffcfca0 0x40086c05:0x3ffcfcd0 0x401074d7:0x3ffcfcf0 0x401022dd:0x3ffcffb0 0x401021b9:0x3ffd0000 0x4008d471:0x3ffd0030 0x40081cb2:0x3ffd0050 0x40081e21:0x3ffd0070 0x40135202:0x3ffd0090 0x401285c6:0x3ffd00b0 0x400d8c00:0x3ffd00d0 0x400d8801:0x3ffd00f0 0x400d88e1:0x3ffd0110 0x400d8845:0x3ffd0130 0x40177592:0x3ffd0150 0x40177483:0x3ffd0180 0x400d4ed9:0x3ffd01a0 0x400d7c8a:0x3ffd01d0 0x400d831a:0x3ffd01f0 0x40089a2e:0x3ffd0210
13:00:17.942 -> 
13:00:17.942 -> Rebooting...
13:00:17.942 -> ets Jun  8 2016 00:22:57
13:00:17.942 -> 
13:00:17.942 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
13:00:17.942 -> configsip: 0, SPIWP:0xee
13:00:17.942 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
13:00:17.942 -> mode:DIO, clock div:1
13:00:17.942 -> load:0x3fff0018,len:4
13:00:17.942 -> load:0x3fff001c,len:1044
13:00:17.942 -> load:0x40078000,len:10124
13:00:17.942 -> load:0x40080400,len:5856
13:00:17.942 -> entry 0x400806a8

Reading about, a Corrupt Heap error is related with a overwrite of a portion of memory where another data is suppossed to be.

Core0 is where Blynk routines are running

I created the task in setup

xTaskCreatePinnedToCore(loop1, "loop1", 4608, NULL, 2, NULL, 0);

and these are my loops:

void loop1(void *pvParameters) //loop para procesos de BLYNK en Core0
{
  while (1)
  {
    BlynkEdgent.run();
    delay(1);
  }
}

void loop() {
  timer.run();
  millis_actual = millis();
  if ( (millis_actual - millis_anterior) >= Intervalo_dosis)
  {
    dosificar = true;
    millis_anterior = millis_actual;
  }
}

Any ideas in how to find the error?

Unless you share your full code it’s unlikely that anyone will have any useful insight.

Pete.

It’s a very long code but I’ll post the main of it:

// Fill-in information from your Blynk Template here
#define BLYNK_TEMPLATE_ID           "no to be shown"
#define BLYNK_DEVICE_NAME           "Dosif Continuo 4Ch"

#define BLYNK_FIRMWARE_VERSION        "0.2.00"
#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7
//#define USE_ESP32C3_DEV_MODULE
#define USE_ESP32S2_DEV_KIT

#include "BlynkEdgent.h"
#include <EEPROM.h>
#include <SPI.h>
#include <TFT_eSPI.h>

#include <WidgetRTC.h>

#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI();       // Invoke custom library
SimpleTimer timer;
#define Max_Dosis 2881

#define Inicio_Eeprom 0



//Define Pines Virtuales Blynk
#define VIRTUAL_PIN_Terminal 0
#define VIRTUAL_PIN_Bomba_Accion 1
#define VIRTUAL_PIN_CANTIDAD_ACCION 2
#define VIRTUAL_PIN_ACCION_RELLENA 3
#define VIRTUAL_PIN_ACCION_ADITA 4
#define VIRTUAL_PIN_BUTTON_IMAGE 5
#define Setup_Notifica_Alarmas 6
#define Setup_Correo_Alarmas 7
#define VIRTUAL_PIN_INTERVALO_DOSIS 8
#define VIRTUAL_PIN_Dosis_Totales 9
#define Configura_Dosis_Canal_1 10
#define Configura_Dosis_Canal_2 11
#define Configura_Dosis_Canal_3 12
#define Configura_Dosis_Canal_4 13
#define Setup_Nombre_Bomba_1 20
#define Setup_Nombre_Bomba_2 21
#define Setup_Nombre_Bomba_3 22
#define Setup_Nombre_Bomba_4 23
#define Setup_Calibrar_Bomba_1 30
#define Setup_Calibrar_Bomba_2 31
#define Setup_Calibrar_Bomba_3 32
#define Setup_Calibrar_Bomba_4 33
#define Setup_Calibracion_Bomba_1 40
#define Setup_Calibracion_Bomba_2 41
#define Setup_Calibracion_Bomba_3 42
#define Setup_Calibracion_Bomba_4 43
#define Panel_Level_Bomba_1 50
#define Panel_Level_Bomba_2 51
#define Panel_Level_Bomba_3 52
#define Panel_Level_Bomba_4 53
#define Panel_Activa_Bomba_1 60
#define Panel_Activa_Bomba_2 61
#define Panel_Activa_Bomba_3 62
#define Panel_Activa_Bomba_4 63
#define Setup_Alarma_Aditivo_1 70
#define Setup_Alarma_Aditivo_2 71
#define Setup_Alarma_Aditivo_3 72
#define Setup_Alarma_Aditivo_4 73
#define Configura_Micro_Dosis_Bomba_1 80
#define Configura_Micro_Dosis_Bomba_2 81
#define Configura_Micro_Dosis_Bomba_3 82
#define Configura_Micro_Dosis_Bomba_4 83
#define Panel_Sensor_Bomba_1 90
#define Panel_Sensor_Bomba_2 91
#define Panel_Sensor_Bomba_3 92
#define Panel_Sensor_Bomba_4 93
#define LCD 100 // LCD Blynk
#define ON_OFF 101 // Enciende/Apaga dosificadora

//Define salidas/entradas DIO

#define Sleep_BCD_A 12 //GPIO D4
#define Sleep_BCD_B 13 //GPIO Tx
#define Sleep_BCD_C 14 //GPIO Rx
#define StepPin 16 //GPIO D0

// TFT Defines. The scrolling area must be a integral multiple of TEXT_HEIGHT
#define TEXT_HEIGHT 8 // Height of text to be printed and scrolled
#define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
#define TOP_FIXED_AREA 48 // Number of lines in top fixed area (lines counted from top of screen)
#define YMAX 320 // Bottom of screen area


WidgetLCD lcd(LCD);
WidgetRTC rtc;
WidgetTerminal terminal(VIRTUAL_PIN_Terminal);

//Definiciones de variables TFT
// The initial y coordinate of the top of the scrolling area
uint16_t yStart = TOP_FIXED_AREA;
// yArea must be a integral multiple of TEXT_HEIGHT
uint16_t yArea = YMAX-TOP_FIXED_AREA-BOT_FIXED_AREA;
// The initial y coordinate of the top of the bottom text line
uint16_t yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;

// Keep track of the drawing x coordinate
uint16_t xPos = 0;

// For the byte we read from the serial port
//byte data = 0;

// A few test variables used during debugging
boolean change_colour = 1;
boolean selected = 1;

// We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds
// for a full width line, meanwhile the serial buffer may be filling... and overflowing
// We can speed up scrolling of short text lines by just blanking the character we drew
int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking



float dosis[6] = { 0.0,0.0,0.0,0.0};
float paso[6] = { 0.0,0.0,0.0,0.0};
float Nro_Dosis[6] = {0,0,0,0,0};
float dosis_Blynk[6] = { 0.0,0.0,0.0,0.0};
float paso_Blynk[6] = { 0.0,0.0,0.0,0.0};
float micro_dosis[6] = {0.1,0.2,0.5,1.0,5.0};
int motor[6] = {0,0,0,0,0};
float Aditivo_Restante[6];
int Steps[6] = {0,0,0,0,0};
String Bomba[6];
int alarma_aditivo[6] = {0,0,0,0,0};
bool correo_alarmas = false;
bool notifica_alarmas = false;

float Numero_dosis = 0;
int index_dosis = 0;
byte Canales_Activos = 0;
bool Canal_Activo[5]={false, false, false, false};
bool encuentra;
bool Blynk_conectado = false;
bool dosificar = false;
unsigned long millis_anterior;
unsigned long millis_actual;
unsigned long Intervalo_dosis = 86400000;
unsigned long Ciclo_dosis;
byte secuencia[Max_Dosis];
bool conectado = false;
bool Restart = true;
bool Dosificador_activado = false;
byte Aditivo_Recarga = 0;
int Cantidad_Recarga = 0;
char Date_Time[32]; //contendrá la fecha y hora a imprimir
char Time[9]; // contendrá la hora a imprimir


int eeAddress = 1024;



// Inicia Rutinas Blynk

BLYNK_CONNECTED() {
  // Synchronize time on connection
  // Change Web Link Button message to "Congratulations!"
  Blynk.sendInternal("rtc", "sync");
  delay(10);
//  rtc.begin();
//  Blynk.setProperty(VIRTUAL_PIN_BUTTON_IMAGE, "offImageUrl", "https://jumpseller.s3.eu-west-1.amazonaws.com/store/triton-labs-chile/assets/Logo%20Sunny%20Reef%20On.png");
//  Blynk.setProperty(VIRTUAL_PIN_BUTTON_IMAGE, "onImageUrl",  "https://jumpseller.s3.eu-west-1.amazonaws.com/store/triton-labs-chile/assets/Logo%20Sunny%20Reef%20On.png");
  Blynk.setProperty(VIRTUAL_PIN_BUTTON_IMAGE, "url", "https://www.triton-labs.cl/");

  conectado = true;
  terminal.println();
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawCentreString(F("Blynk v" BLYNK_VERSION), 120, yDraw, 1);
  yDraw = scroll_line();
  terminal.println(F("Blynk v" BLYNK_VERSION));
  tft.drawCentreString(F("---------------------"), 120, yDraw, 1);
  yDraw = scroll_line();
  terminal.println(F("---------------------"));
  tft.drawCentreString(F("**  Doser Continuo **"), 120, yDraw, 1);
  yDraw = scroll_line();
  terminal.println(F("**  Doser Continuo **"));
  tft.drawCentreString(F("**      Listo      **"), 120, yDraw, 1);
  yDraw = scroll_line();
  terminal.println(F("**      Listo      **"));
  tft.drawCentreString(F("----------------------"), 120, yDraw, 1);
  yDraw = scroll_line();
  terminal.println(F("----------------------"));
  terminal.print(F("V "));
  terminal.println(BLYNK_FIRMWARE_VERSION);
  
  
  int t = now(); // Guarda la hora actual en t

  String currentTime = String(hour()) + ":" + minute();
  int h = hour(t);  // returns the hour for the given time t
  int m = minute(t);// returns the minute for the given time t
  Serial.println("hora " + String(h) + ":" + String(m));
  terminal.println("hora " + String(h) + ":" + String(m));

  if (Restart)
  {
    Blynk.notify("ALERTA DOSER: Reiniciando Dispositivo" +  currentTime);
    String Mensaje = String("ALERTA DOSER: Reiniciando Dispositivo " + currentTime);
    Blynk.email("Alerta Dispositivo Acuario", Mensaje);
    terminal.println(Mensaje);
    Restart = false;
  }
  else
  {
    Blynk.notify("ALERTA DOSER: Reconectando Dispositivo" +  currentTime);
    String Mensaje = String("ALERTA DOSER: Reconectando Dispositivo " + currentTime);
    Blynk.email("Alerta Dispositivo Acuario", Mensaje);
    terminal.println(Mensaje);
  }
  terminal.flush();
  Blynk.syncAll();
  Filtra_Canales();
  calcula_intervalo()
}

BLYNK_WRITE(Panel_Activa_Bomba_1)
{
  int i = 0;
  Canal_Activo[i] = param.asInt();
}

BLYNK_WRITE(Panel_Activa_Bomba_2)
{
  int i = 1;
  Canal_Activo[i] = param.asInt();
}

BLYNK_WRITE(Panel_Activa_Bomba_3)
{
  int i = 2;
  Canal_Activo[i] = param.asInt();
}

BLYNK_WRITE(Panel_Activa_Bomba_4)
{
  int i = 3;
  Canal_Activo[i] = param.asInt();
}
}

BLYNK_WRITE(Configura_Dosis_Canal_1)
{
  int i = 0;
  dosis_Blynk[i] = param.asFloat();
}

BLYNK_WRITE(Configura_Dosis_Canal_2)
{
  int i = 1;
  dosis_Blynk[i] = param.asFloat();
}

BLYNK_WRITE(Configura_Dosis_Canal_3)
{
  int i = 2;
  dosis_Blynk[i] = param.asFloat();
}

BLYNK_WRITE(Configura_Dosis_Canal_4)
{
  int i = 3;
  dosis_Blynk[i] = param.asFloat();
}

BLYNK_WRITE(Configura_Micro_Dosis_Bomba_1)
{
  int i = 0;
  paso_Blynk[i] = micro_dosis[param.asInt()];
}

BLYNK_WRITE(Configura_Micro_Dosis_Bomba_2)
{
  int i = 1;
  paso_Blynk[i] = micro_dosis[param.asInt()];
}

BLYNK_WRITE(Configura_Micro_Dosis_Bomba_3)
{
  int i = 2;
  paso_Blynk[i] = micro_dosis[param.asInt()];
}

BLYNK_WRITE(Configura_Micro_Dosis_Bomba_4)
{
  int i = 3;
  paso_Blynk[i] = micro_dosis[param.asInt()];
}

BLYNK_WRITE(ON_OFF)
{
  bool change = false;
  Dosificador_activado = param.asInt();
  eeAddress = Inicio_Eeprom;
  EEPROM.put(eeAddress,Dosificador_activado);
  delay(10);
  EEPROM.commit(); 
}

BLYNK_WRITE(Panel_Level_Bomba_1)
{
  Aditivo_Restante[0] = param.asFloat();
}

BLYNK_WRITE(Panel_Level_Bomba_2)
{
  Aditivo_Restante[1] = param.asFloat();
}

BLYNK_WRITE(Panel_Level_Bomba_3)
{
  Aditivo_Restante[2] = param.asFloat();
}

BLYNK_WRITE(Panel_Level_Bomba_4)
{
  Aditivo_Restante[3] = param.asFloat();
}

BLYNK_WRITE(Setup_Alarma_Aditivo_1)
{
  alarma_aditivo[0] = param.asInt();
}

BLYNK_WRITE(Setup_Alarma_Aditivo_2)
{
  alarma_aditivo[1] = param.asInt();
}

BLYNK_WRITE(Setup_Alarma_Aditivo_3)
{
  alarma_aditivo[2] = param.asInt();
}

BLYNK_WRITE(Setup_Alarma_Aditivo_4)
{
  alarma_aditivo[3] = param.asInt();
}

BLYNK_WRITE(Setup_Notifica_Alarmas)
{
  if(param.asInt())
  {
    notifica_alarmas = true;
  }
  else
  {
    notifica_alarmas = false;
  }
}

BLYNK_WRITE(Setup_Correo_Alarmas)
{
  if(param.asInt())
  {
    correo_alarmas = true;
  }
  else
  {
    correo_alarmas = false;
  }
}

BLYNK_WRITE(Setup_Nombre_Bomba_1)
{
  int i = 0;
  Bomba[i] = param.asStr();
//  Blynk.setProperty(Configura_Dosis_Canal_1, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(VIRTUAL_PIN_Bomba_Accion, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(Panel_Level_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Panel_Activa_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Configura_Micro_Dosis_Bomba_1 + i,"label","Micro Dosis "+ Bomba[i]);
  Blynk.setProperty(Configura_Dosis_Canal_1 + i,"label","Dosis "+ Bomba[i]);
  Blynk.setProperty(Setup_Alarma_Aditivo_1 + i,"label","Alarma nivel "+ Bomba[i]);
}

BLYNK_WRITE(Setup_Nombre_Bomba_2)
{
  int i = 1;
  Bomba[i] = param.asStr();
//  Blynk.setProperty(Configura_Dosis_Canal_1, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(VIRTUAL_PIN_Bomba_Accion, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(Panel_Level_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Panel_Activa_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Configura_Micro_Dosis_Bomba_1 + i,"label","Micro Dosis "+ Bomba[i]);
  Blynk.setProperty(Configura_Dosis_Canal_1 + i,"label","Dosis "+ Bomba[i]);
  Blynk.setProperty(Setup_Alarma_Aditivo_1 + i,"label","Alarma nivel "+ Bomba[i]);
}

BLYNK_WRITE(Setup_Nombre_Bomba_3)
{
  int i = 2;
  Bomba[i] = param.asStr();
//  Blynk.setProperty(Configura_Dosis_Canal_1, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(VIRTUAL_PIN_Bomba_Accion, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(Panel_Level_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Panel_Activa_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Configura_Micro_Dosis_Bomba_1 + i,"label","Micro Dosis "+ Bomba[i]);
  Blynk.setProperty(Configura_Dosis_Canal_1 + i,"label","Dosis "+ Bomba[i]);
  Blynk.setProperty(Setup_Alarma_Aditivo_1 + i,"label","Alarma nivel "+ Bomba[i]);
}

BLYNK_WRITE(Setup_Nombre_Bomba_4)
{
  int i = 3;
  Bomba[i] = param.asStr();
//  Blynk.setProperty(Configura_Dosis_Canal_1, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(VIRTUAL_PIN_Bomba_Accion, "labels", Bomba[0], Bomba[1], Bomba[2], Bomba[3]);
  Blynk.setProperty(Panel_Level_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Panel_Activa_Bomba_1 + i, "label", Bomba[i]);
  Blynk.setProperty(Configura_Micro_Dosis_Bomba_1 + i,"label","Micro Dosis "+ Bomba[i]);
  Blynk.setProperty(Configura_Dosis_Canal_1 + i,"label","Dosis "+ Bomba[i]);
  Blynk.setProperty(Setup_Alarma_Aditivo_1 + i,"label","Alarma nivel "+ Bomba[i]);
}

BLYNK_WRITE(VIRTUAL_PIN_Bomba_Accion)
{
  Aditivo_Recarga = param.asInt();
}

  BLYNK_WRITE(VIRTUAL_PIN_CANTIDAD_ACCION)
{
  Cantidad_Recarga = param.asInt();
}


// Termina Rutinas Blynk

void guarda_activo( byte indice, bool dato )
{
  eeAddress = 1 + (indice * sizeof(bool));
  // Serial.println("Guarda Activo " + String(indice) + " en " + String(eeAddress));
  EEPROM.put(eeAddress,dato);
  EEPROM.commit();
}

void guarda_dosis( byte indice, float dato )
{
  eeAddress = 5 + ( indice * sizeof(float));
  // Serial.println("Guarda Dosis " + String(indice) + " en " + String(eeAddress));
  EEPROM.put(eeAddress,dato);
  EEPROM.commit();  
}

void guarda_paso( byte indice, float dato)
{
  eeAddress = 21 + (indice * sizeof(float));
  // Serial.println("Guarda Paso " + String(indice) + " en " + String(eeAddress));
  EEPROM.put(eeAddress,dato);
  EEPROM.commit();    
}

void dosificadora_off()
{
  lcd.clear();
  lcd.print(0,0,"   DETENIENDO   ");
  lcd.print(0,1,"  DOSIFICADORA  ");
  //             1234567890123456
      
  Blynk.virtualWrite(ON_OFF, LOW);
  Dosificador_activado = false;

}


float redondear(float valor)
{
  long expo = 1;  
  float aux= (long)(valor*expo+0.5)/(float)expo;
  return aux;
}

void Filtra_Canales()
{
  // función que filtra solo los canales activos y recalcula el Numero_dosis
  Canales_Activos = 0;
  int indice = 0;
  int fin = 0 ;
  int index = 0;
  for (int i = 0; i < 4 ; i++)
  {

    if (Canal_Activo[i])
    {
      dosis[index] = dosis_Blynk[i];
      paso[index] = paso_Blynk[i];
      fin = indice + (paso[index]/dosis[index]);
      motor[index] = i;
      for ( int x = inicio ; x < fin ; x++ )
      {
        secuencia[x] = motor[index]
        indice++;
      }
      Canales_Activos++;
      index++;
            
    }
  }
  // Serial.println("Filtra Canales...");
  for (int i = 0; i < Canales_Activos ; i++)
  {
    // Serial.println(String(i) + " : " + String(dosis[i]) + " : " + String(paso[i]));
  }
  
}



bool calcula_intervalo()
{
  // Calcula el total de dosis considerando las bombas activas, la dosis total y el paso de cada dosis
  bool aux = false;
  Numero_dosis = 0;
  // Serial.println("Calcula Intervalo...:" + String(Numero_dosis));
  for ( int i = 0 ; i < Canales_Activos ; i++)
  {
    Nro_Dosis[i] = dosis[i]/paso[i];
    Numero_dosis = Numero_dosis + Nro_Dosis[i];
    Steps[i] = paso[i] * 1000;
    // Serial.println(String(i) + " : " + String(dosis[i]) + " : " + String(paso[i]) + " : " + String(Nro_Dosis[i]) + " : " + String(Numero_dosis));
  }
  if ( Numero_dosis < Max_Dosis )
  {
    for ( int i = 0; i < Numero_dosis ; i++)
    {
      secuencia[i] = 5;
    }
  
    Intervalo_dosis = 24*60*60*1000/(Numero_dosis + 1);
    Blynk.virtualWrite(VIRTUAL_PIN_INTERVALO_DOSIS, Intervalo_dosis/1000);
    Blynk.setProperty(VIRTUAL_PIN_Dosis_Totales, "color", "#23C48E");
    Blynk.virtualWrite(VIRTUAL_PIN_Dosis_Totales, Numero_dosis);
    aux = true;
  }
  else
  {
    lcd.print(0,0,"EXCESO DE DOSIS ");
    lcd.print(0,1,"BAJAR MICRODOSIS");
    Blynk.setProperty(VIRTUAL_PIN_Dosis_Totales, "color", "#D3435C");
    Blynk.virtualWrite(VIRTUAL_PIN_Dosis_Totales, Numero_dosis);
  }
  
  return aux;  
}

void activa_motor(int motor)
{
  if ( motor == 0)
  {
//    digitalWrite(Enable1, LOW);
    digitalWrite(Sleep_BCD_A, HIGH);
    digitalWrite(Sleep_BCD_B, LOW);
    digitalWrite(Sleep_BCD_C, LOW);
  }
  if ( motor == 1)
  {
//    digitalWrite(Enable2, LOW);
    digitalWrite(Sleep_BCD_A, LOW);
    digitalWrite(Sleep_BCD_B, HIGH);
    digitalWrite(Sleep_BCD_C, LOW);
  }
  if ( motor == 2)
  {
//    digitalWrite(Enable3, LOW);
    digitalWrite(Sleep_BCD_A, HIGH);
    digitalWrite(Sleep_BCD_B, HIGH);
    digitalWrite(Sleep_BCD_C, LOW);
  }
  if ( motor == 3)
  {
//    digitalWrite(Enable4, LOW);
    digitalWrite(Sleep_BCD_A, LOW);
    digitalWrite(Sleep_BCD_B, LOW);
    digitalWrite(Sleep_BCD_C, HIGH);
  }
  if ( motor == 5)
  {
    digitalWrite(Sleep_BCD_A, LOW);
    digitalWrite(Sleep_BCD_B, LOW);
    digitalWrite(Sleep_BCD_C, LOW);
/*    digitalWrite(Enable1, HIGH);
    digitalWrite(Enable2, HIGH);
    digitalWrite(Enable3, HIGH);
    digitalWrite(Enable4, HIGH); */
  }
  
}



void Verifica_dosis()
{
  if (dosificar)
  {
    if (index_dosis >= Numero_dosis) 
    {
      index_dosis = 0;
    }
    
    if (Dosificador_activado)
    {
      int t = now(); // Guarda la hora actual en t
      String currentTime = String(hour(t)) + ":" + minute(t);
      activa_motor(secuencia[index_dosis]);
      delay(1);
      for (int paso = 0; paso < Steps[secuencia[index_dosis]] ; paso++ )
        {
          digitalWrite(StepPin, HIGH);
          delayMicroseconds(1000);
          digitalWrite(StepPin, LOW);
          delayMicroseconds(1000);
          yield();
        }
      delay(1);
      activa_motor(5);
      Aditivo_Restante[secuencia[index_dosis]] = Aditivo_Restante[secuencia[index_dosis]] - paso_Blynk[secuencia[index_dosis]];

      if ( Aditivo_Restante[secuencia[index_dosis]] < alarma_aditivo[secuencia[index_dosis]] )
      {
        String Mensaje = String(" Aditivo Bajo - Debe recargar " + Bomba[secuencia[index_dosis]]);
        if (notifica_alarmas) Blynk.notify("ALERTA DOSER: " +  currentTime + Mensaje);
        if (correo_alarmas) Blynk.email("Alerta Dispositivo Acuario", Mensaje);
      }
      
//      Blynk.virtualWrite(Panel_Level_Bomba_1 + secuencia[index_dosis] , Aditivo_Restante[secuencia[index_dosis]]);
      
      int h = hour(t);  // returns the hour for the given time t
      int m = minute(t);// returns the minute for the given time t
      int s = second(t);// returns the seconds for the given time t
      int y = year(t);
      int mo = month(t);
      int d = day(t);
      char Txt_print_1[17];
      char Txt_print_2[17];
      char txt_paso[3];
      lcd.clear();
 //     tft.drawString("                                       ", 0, yDraw, 1);  
      yDraw = scroll_line();
      xPos = 0;
      tft.setTextColor(TFT_WHITE, TFT_BLACK);        
      snprintf(Txt_print_1, sizeof(Txt_print_1), "%02d/%02d %02d:%02d:%02d ", d, mo, h, m, s);
      lcd.print(0,0,Txt_print_1);
      xPos += tft.drawString(Txt_print_1, xPos, yDraw, 1);
      dtostrf(paso_Blynk[secuencia[index_dosis]], 3 , 1, txt_paso);
      snprintf(Txt_print_2, sizeof(Txt_print_2), "%-9s\n", Bomba[secuencia[index_dosis]]);
//      Blynk.logEvent("dosis", String(Txt_print_1) + String(Txt_print_2) + String(txt_paso) + String(" ml"));
      lcd.print(0,1,Txt_print_2);
      xPos += tft.drawString(Txt_print_2, xPos, yDraw, 1);
      lcd.print(10,1,txt_paso);
      xPos += tft.drawString(txt_paso, xPos, yDraw, 1);
      lcd.print(14,1,"ml");
      xPos += tft.drawString(" ml", xPos, yDraw, 1);  
      yDraw = scroll_line(); 
      // Serial.println(String(index_dosis) + " : -> " + String(h) + ":" + String(m) + " - " + Bomba[secuencia[index_dosis]] + " " + String(Steps[secuencia[index_dosis]]));
      
    }
    index_dosis++;
    dosificar = false;
  }
}

void Update_time_TFT()
{
  int t = now(); // Guarda la hora actual en t
  String currentTime = String(hour()) + ":" + minute();
  int h = hour(t);  // returns the hour for the given time t
  int m = minute(t);// returns the minute for the given time t
  int s = second(t);// returns the seconds for the given time t
  int y = year(t);
  int mo = month(t);
  int d = day(t);
  snprintf(Date_Time, sizeof(Date_Time), "%02d/%02d/%4d %02d:%02d:%02d", d, mo, y, h, m, s);
  tft.setTextColor(TFT_WHITE, TFT_BLUE);
  tft.drawCentreString(Date_Time,120,32,2);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  

  if (Blynk.connected())
  {
    if (!Blynk_conectado)
    {
      Blynk_conectado = true;
      for ( int i = 0 ; i < 4 ; i++)
      {
         tft.fillRect(222 + i*2,8 + i*4 , 16 - i*4 , 2, TFT_GREEN);
      }
    }
  } else
  {
    if (Blynk_conectado)
    {
      Blynk_conectado = false;
      for ( int i = 0 ; i < 4 ; i++)
      {
         tft.fillRect(222 + i*2,8 + i*4 , 16 - i*4 , 2, TFT_RED);
      }
    }
  } 
  tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
  tft.setFreeFont(NULL);
}

void setup() {
  // put your setup code here, to run once:
  pinMode(Sleep_BCD_A, OUTPUT);
  pinMode(Sleep_BCD_B, OUTPUT);
  pinMode(Sleep_BCD_C, OUTPUT);
  pinMode(StepPin, OUTPUT);
  digitalWrite(StepPin, LOW);
  activa_motor(5);
  EEPROM.begin(2048);
  // Serial.begin(115200);
  // Serial.println("comienza algoritmo");
//  dosis[0] = 12; paso[0] = 0.1; // 120
//  dosis[1] = 16; paso[1] = 0.1; // 120
//  dosis[2] = 18; paso[2] = 0.1; // 120
//  dosis[3] = 20; paso[3] = 0.1; // 120 */

  millis_anterior = millis();

    // Setup the TFT display
  tft.init();
  tft.setRotation(0); // Must be setRotation(0) for this sketch to work correctly
  tft.fillScreen(TFT_BLACK);
  
  tft.setTextColor(TFT_WHITE, TFT_BLUE);
  tft.fillRect(0,0,240,48, TFT_BLUE);
  tft.drawCentreString(" WWW.TRITON-LABS.CL ",120,0,2);
  tft.drawCentreString(" Doser Cont. - V2.00 ",120,16,2);


  // Change colour for scrolling zone text
  tft.setTextColor(TFT_WHITE, TFT_BLACK);

  // Setup scroll area
  setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);

  // Zero the array
  for (byte i = 0; i<18; i++) blank[i]=0;
  
  BlynkEdgent.begin();

//  xTaskCreatePinnedToCore(loop2, "loop2", 4096, NULL, 1, NULL, 1);
  xTaskCreatePinnedToCore(loop1, "loop1", 4608, NULL, 1, NULL, 0);
  
  timer.setInterval(1000, Verifica_dosis); //ejecuta cada 1 segundo
  timer.setInterval(1000, Update_time_TFT);//actualiza la fecha/hora en la pantalla TFT

  eeAddress = Inicio_Eeprom;
  // Serial.println("comienza lectura eeprom");
  EEPROM.get(eeAddress,Dosificador_activado);
  eeAddress += sizeof(bool); //Mueve la dirección al próximo byte después de un booleano
  // Serial.println("Ha leido el primer dato");
  // Serial.println("Activado : " + String(Dosificador_activado));
  for (int i = 0 ;  i < 4 ; i++)
  {
    EEPROM.get(eeAddress,Canal_Activo[i]);
    // Serial.print(String(eeAddress) + " : " + String(Canal_Activo[i]) + " ");
    eeAddress += sizeof(bool); //Mueve la dirección al próximo byte después de un booleano
  }
  // Serial.println();
  for (int i = 0 ;  i < 4 ; i++)
  {
    EEPROM.get(eeAddress, dosis_Blynk[i]);
    // Serial.print(String(eeAddress) + " : " + String(dosis_Blynk[i]) + " ");
    eeAddress += sizeof(float); //Mueve la dirección al próximo byte después de un flotante.
    
  }
  // Serial.println();
  for (int i = 0 ;  i < 4 ; i++)
  {
    EEPROM.get(eeAddress, paso_Blynk[i]);
    // Serial.print(String(eeAddress) + " : " + String(paso_Blynk[i]) + " ");    
    eeAddress += sizeof(float); //Mueve la dirección al próximo byte después de un flotante.
  }
  Filtra_Canales();
  calcula_intervalo()
}

void loop1(void *pvParameters) //loop para procesos de BLYNK en Core0
{
  while (1)
  {
    BlynkEdgent.run();
    delay(1);
  }
}

void loop() {
  timer.run();
  millis_actual = millis();
  if ( (millis_actual - millis_anterior) >= Intervalo_dosis)
  {
    dosificar = true;
    millis_anterior = millis_actual;
  }
}


// ##############################################################################################
// Call this function to scroll the display one text line
// ##############################################################################################
int scroll_line() {
  int yTemp = yStart; // Store the old yStart, this is where we draw the next line
  // Use the record of line lengths to optimise the rectangle size we need to erase the top line
//  tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT],TEXT_HEIGHT, TFT_BLACK);
  tft.fillRect(0,yStart,240,TEXT_HEIGHT, TFT_BLACK);
  // Change the top of the scroll area
  yStart+=TEXT_HEIGHT;
  // The value must wrap around as the screen memory is a circular buffer
  if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - YMAX + BOT_FIXED_AREA);
  // Now we can scroll the display
  scrollAddress(yStart);
  return  yTemp;
}

// ##############################################################################################
// Setup a portion of the screen for vertical scrolling
// ##############################################################################################
// We are using a hardware feature of the display, so we can only scroll in portrait orientation
void setupScrollArea(uint16_t tfa, uint16_t bfa) {
  tft.writecommand(ILI9341_VSCRDEF); // Vertical scroll definition
  tft.writedata(tfa >> 8);           // Top Fixed Area line count
  tft.writedata(tfa);
  tft.writedata((YMAX-tfa-bfa)>>8);  // Vertical Scrolling Area line count
  tft.writedata(YMAX-tfa-bfa);
  tft.writedata(bfa >> 8);           // Bottom Fixed Area line count
  tft.writedata(bfa);
}

// ##############################################################################################
// Setup the vertical scrolling start address pointer
// ##############################################################################################
void scrollAddress(uint16_t vsp) {
  tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer
  tft.writedata(vsp>>8);
  tft.writedata(vsp);
}

These are all Legacy functions. You need to migrate them to IoT.

I’d guess that this is causing a conflict with the EEPROM used by Edgent for the programstore

Pete.

Thanks for the hints, I’ll star from there.

By the way, I was using all those legacy functions with the new blynk and Edgent on ESP8266 without any issues. But I will follow your advice.

Pete, about the RTC, I was looking at the example included at Blynk:

and it looks like how I’m using it.

https://docs.blynk.io/en/blynk.edgent-firmware-api/rtc-clock

Pete.

After several tests, I found that If I try to send any data to Blynk server inside the function I’m running every XX seconds the device will disconnect from wifi and it will try to reconnect again.

In setup I created the repeating function to make a dosis and created the task in Core 0 where Blynk will run

  xTaskCreatePinnedToCore(loop1, "loop1", 4608, NULL, 1, NULL, 0);  
  timer.setInterval(1000, Verifica_dosis); //ejecuta cada 1 segundo

I have a loop running on Core 1 to decide when is time to “dose” a specific chemical to my aquarium:

void loop1(void *pvParameters) //loop para procesos de BLYNK en Core0
{
  while (1)
  {
    BlynkEdgent.run();
    delay(1);
  }
}

void loop() // loop para procesos del dosificador
{
  timer.run();
  millis_actual = millis();
  if ( (millis_actual - millis_anterior) >= Intervalo_dosis)
  {
    dosificar = true;
    millis_anterior = millis_actual;
  }
}

When dosificar is true, the repeating function will make a dose and will write some information on the display and, I would like to send information to Blynk to show the dose made (now are commented, If I uncomment any of them, the device will disconnect and will try to connect again)

void Verifica_dosis()
{
  if (dosificar)
  {
    if (index_dosis >= Numero_dosis) 
    {
      index_dosis = 0;
    }
    
    if (Dosificador_activado)
    {
      int t = now(); // Guarda la hora actual en t
      String currentTime = String(hour(t)) + ":" + minute(t);
      activa_motor(secuencia[index_dosis]);
      delay(1);
      for (int paso = 0; paso < Steps[secuencia[index_dosis]] ; paso++ )
        {
          digitalWrite(StepPin, HIGH);
          delayMicroseconds(1000);
          digitalWrite(StepPin, LOW);
          delayMicroseconds(1000);
          yield();
        }
      delay(1);
      activa_motor(5);
      Aditivo_Restante[secuencia[index_dosis]] = Aditivo_Restante[secuencia[index_dosis]] - paso_Blynk[secuencia[index_dosis]];

      if ( Aditivo_Restante[secuencia[index_dosis]] < alarma_aditivo[secuencia[index_dosis]] )
      {
        String Mensaje = String(" Aditivo Bajo - Debe recargar " + Bomba[secuencia[index_dosis]]);
//        if (notifica_alarmas) Blynk.notify("ALERTA DOSER: " +  currentTime + Mensaje);   // commented to avoid disconnect from wifi.
//        if (correo_alarmas) Blynk.email("Alerta Dispositivo Acuario", Mensaje);   // commented to avoid disconnect from wifi.
      }
      
//      Blynk.virtualWrite(Panel_Level_Bomba_1 + secuencia[index_dosis] , Aditivo_Restante[secuencia[index_dosis]]);   // commented to avoid disconnect from wifi.
      
      int h = hour(t);  // returns the hour for the given time t
      int m = minute(t);// returns the minute for the given time t
      int s = second(t);// returns the seconds for the given time t
      int y = year(t);
      int mo = month(t);
      int d = day(t);
      char Txt_print_1[17];
      char Txt_print_2[17];
      char txt_paso[3];
//      lcd.clear();   // commented to avoid disconnect from wifi.
 
      yDraw = scroll_line();
      xPos = 0;
      tft.setTextColor(TFT_WHITE, TFT_BLACK);        
      snprintf(Txt_print_1, sizeof(Txt_print_1), "%02d/%02d %02d:%02d:%02d ", d, mo, h, m, s);
//      lcd.print(0,0,Txt_print_1);   // commented to avoid disconnect from wifi.
      xPos += tft.drawString(Txt_print_1, xPos, yDraw, 1);
      dtostrf(paso_Blynk[secuencia[index_dosis]], 3 , 1, txt_paso);
      snprintf(Txt_print_2, sizeof(Txt_print_2), "%-9s\n", Bomba[secuencia[index_dosis]]);
//      Blynk.logEvent("dosis", String(Txt_print_1) + String(Txt_print_2) + String(txt_paso) + String(" ml"));   // commented to avoid disconnect from wifi.
//      lcd.print(0,1,Txt_print_2);   // commented to avoid disconnect from wifi.
      xPos += tft.drawString(Txt_print_2, xPos, yDraw, 1);
//      lcd.print(10,1,txt_paso);   // commented to avoid disconnect from wifi.
      xPos += tft.drawString(txt_paso, xPos, yDraw, 1);
//      lcd.print(14,1,"ml");  // commented to avoid disconnect from wifi.
      xPos += tft.drawString(" ml", xPos, yDraw, 1);  
      yDraw = scroll_line();
    } 
    index_dosis++;
    dosificar = false;
  }
}

I have to remark that this problem started when I placed Blynk in the second Core. If I leave the original loop and doesn’t work with the second core, or, If I leave Blynk in Core 1 (main) everything works (but with the blocking problem I’m trying to solve).

I think you need to declare some volatile variables that can be updated by both cores. You can then monitor this variable in core0 and update Blynk with some appropriate data if it changes.

Pete.

Pete, I think I solved this issue in a very succesful way:

I create a new timer to be runned on Core 0, the same core for Blynk

SimpleTimer timer;
SimpleTimer timer_Core0;

In Setup I created the timers and task, with a new function to ve runned in the new timer .

  xTaskCreatePinnedToCore(loop1, "loop1", 4608, NULL, 1, NULL, 0);
  
  timer.setInterval(1000, Verifica_dosis); //ejecuta cada 1 segundo
  timer_Core0.setInterval(5000, envia_datos);

And the loops:

void loop1(void *pvParameters) //loop para procesos de BLYNK en Core0
{
  while (1)
  {
    BlynkEdgent.run();
    timer_Core0.run();
    delay(1);
  }
}

void loop() // loop para procesos del dosificador
{
  timer.run();
  millis_actual = millis();
  if ( (millis_actual - millis_anterior) >= Intervalo_dosis)
  {
    dosificar = true;
    millis_anterior = millis_actual;
  }
}

The repeating functions:

void Verifica_dosis()
{
  if (dosificar)
  {
    if (index_dosis >= Numero_dosis) 
    {
      index_dosis = 0;
    }
    
    if (Dosificador_activado)
    {
      int t = now(); // Guarda la hora actual en t
      String currentTime = String(hour(t)) + ":" + minute(t);
      activa_motor(secuencia[index_dosis]);
      delay(1);
      for (int paso = 0; paso < Steps[secuencia[index_dosis]] ; paso++ )
        {
          digitalWrite(StepPin, HIGH);
          delayMicroseconds(1000);
          digitalWrite(StepPin, LOW);
          delayMicroseconds(1000);
          yield();
        }
      delay(1);
      activa_motor(5);
      Aditivo_Restante[secuencia[index_dosis]] = Aditivo_Restante[secuencia[index_dosis]] - paso_Blynk[secuencia[index_dosis]];
 
      int h = hour(t);  // returns the hour for the given time t
      int m = minute(t);// returns the minute for the given time t
      int s = second(t);// returns the seconds for the given time t
      int y = year(t);
      int mo = month(t);
      int d = day(t);


      enviar_data = true;
      Log_dosis = "";
      yDraw = scroll_line();
      xPos = 0;
      tft.setTextColor(TFT_WHITE, TFT_BLACK);        
      snprintf(Txt_print_1, sizeof(Txt_print_1), "%02d/%02d %02d:%02d:%02d ", d, mo, h, m, s);
      xPos += tft.drawString(Txt_print_1, xPos, yDraw, 1);
      snprintf(Txt_print_2, sizeof(Txt_print_2), "%-9s\n", Bomba[secuencia[index_dosis]]);
      xPos += tft.drawString(Txt_print_2, xPos, yDraw, 1);
      Log_dosis = Log_dosis + Txt_print_2;
      dtostrf(paso_Blynk[secuencia[index_dosis]], 3 , 1, txt_paso);
      xPos += tft.drawString(txt_paso, xPos, yDraw, 1);
      Log_dosis = Log_dosis + txt_paso + " ml";
      xPos += tft.drawString(" ml", xPos, yDraw, 1);  
      yDraw = scroll_line();
    } 
    index_dosis++;
    dosificar = false;
  }
}

void envia_datos()
{
  if ((enviar_data) and Blynk.connected())
  {
    Blynk.virtualWrite(Panel_Level_Bomba_1 + secuencia[index_dosis-1] , Aditivo_Restante[secuencia[index_dosis-1]]);
    if ( Aditivo_Restante[secuencia[index_dosis-1]] < alarma_aditivo[secuencia[index_dosis-1]] )
    {
      String Mensaje = String(" Aditivo Bajo - Debe recargar " + Bomba[secuencia[index_dosis-1]]);
      if (notifica_alarmas) Blynk.notify("ALERTA DOSER: " + Mensaje);
      if (correo_alarmas) Blynk.email("Alerta Dispositivo Acuario", Mensaje);
    }
    lcd.clear();
    lcd.print(0,0,Txt_print_1);
    Blynk.logEvent("dosis", String(Txt_print_1) + Log_dosis);
    lcd.print(0,1,Log_dosis);
    enviar_data = false;
  }
}

And now everything is working like a charme. I have to test for several days in order to check that it will work for a long time, but it seems that this approach have some logic.

  1. BLYNK running in core 0 doesn’t block the work of the device even if wifi goes off
  2. If you delete the device from the Blynk mobile app, the device will keep working, but available to be provissioned. Keep in mind that, if you need to stop the work of the device for a new provissioning, you have to reset it.
  3. I´m Happy
  4. Thanks @PeteKnight for giving me this challenge.
1 Like