ESP32 Dual Core task keeps crashing

I try to understand the concept of the dual core operation, but my solutions keep crashing.
Step one is the basic, dual led example, which works. Now I add an oled display and NTPclient and would like to run the Oled code displaying the time in one of the tasks.
Step 2:
If i put the Oled and NTP code in the main loop function, all is well. The time is displayed and the leds keep blink async. However if i move the time code to a task. it crashes. If i leave the fetching of the date in the loop function and move the display only to the task, then it works. But i had to make the variables global.
Why is it that i cannot move the call's to NTPclient to the task. Nor the calls to the WiFi. In the end my goals is that in one task the time is updated once per second, but the RSSI measurement as fast as possible.
FreeRTOS.ino (3.7 KB)

Please post an example sketch that illustrates the problem

Sorry, forgot that. The whole working version is posted, but i'd like to have the fetching of NTP data in the task as well and have it run at a different timing as the RSSI. By the way, normally i would use

while(!timeClient.update()) {
timeClient.forceUpdate();

but that did not work at all. Here is the crashing code

#include "Arduino.h"
#include <WiFi.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
const char* ssid = "xxxxxxxxxxxxxxx";
const char* password =  "xxxxxxxxxxxxxxxxxx";


#define NTP_OFFSET  3600 // In seconds 
#define NTP_INTERVAL 60 * 1000    // In miliseconds
#define NTP_ADDRESS  "1.asia.pool.ntp.org"

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

// definitions for OLED screen size, reset and i2 addresses / run i2c discovery to
#define SCREEN_WIDTH 128    // OLED display width, in pixels
#define SCREEN_HEIGHT 64    // OLED display height, in pixels
#define OLED_RESET     -1   // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3c //< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

String formattedTime;
long rssi;

TaskHandle_t Task0;
TaskHandle_t Task1;

#define LED0 27
#define LED1 25

void loop0(void * parameter) {

  for (;;) {
    Serial.print("Running OLED on core: ");
    Serial.println(xPortGetCoreID());

    timeClient.update();
    formattedTime = timeClient.getFormattedTime();
    rssi = WiFi.RSSI();
    display.clearDisplay();
    display.setCursor(20, 0);
    display.println(formattedTime);
    display.setCursor(10, 30);
    display.print("RSSI :");
    display.setCursor(85, 30);
    display.print(rssi);
    display.display();   // write the buffer to the display


    digitalWrite(LED0, HIGH);
    delay(500);
    digitalWrite(LED0, LOW);

    delay(500);
  }
}

void loop1(void * parameter) {
  for (;;) {
    Serial.print("\t\t\tRunning RSSI on core: ");
    Serial.println(xPortGetCoreID());

    Serial.print("RSSI:");
    Serial.println(rssi);

    digitalWrite(LED1, HIGH);
    delay(200);
    digitalWrite(LED1, LOW);
    delay(200);
  }
}

void setup()
{
  delay(1000);
  display.begin();
  Serial.begin(115200);

  Serial.println();
  Serial.println("sketch name: ESP32_oled_cloack");
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  delay(1000);
  timeClient.begin();
  timeClient.setTimeOffset(3600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    //Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }

  long rssi = WiFi.RSSI();
  //Serial.print("RSSI:");
  //Serial.println(rssi);

  display.clearDisplay();
  display.setTextColor(WHITE);
  //display.startscrollright(0x00, 0x0F);
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print("  Internet ");
  display.println("  Clock ");
  display.display();
  delay(3000);

  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);

  xTaskCreatePinnedToCore(
    loop0, /* Function to implement the task */
    "Task0", /* Name of the task */
    1000, /* Stack size in words */
    NULL, /* Task input parameter */
    0, /* Priority of the task */
    &Task0, /* Task handle. */
    0); /* Core where the task should run */

  xTaskCreatePinnedToCore(
    loop1, /* Function to implement the task */
    "Task1", /* Name of the task */
    1000, /* Stack size in words */
    NULL, /* Task input parameter */
    0, /* Priority of the task */
    &Task1, /* Task handle. */
    1); /* Core where the task should run */
  Serial.println("Setup completed.");
}

void loop()
{

  // Serial.println(formattedTime);
  delay(10);
}

That is not quite what I had in mind when I asked for the full sketch to be posted

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the </> icon above the compose window) to make it easier to read and copy for examination

Don't use heavy code on the core 0, otherwise watchdog will not be happy due to the "high priority" WiFi stuffs.

FreeRTOS implementation with ESP32 has enough "power" to run all user task on core 1 (where setup() and loop() are located)

If you are using WiFI only put the code on core1 and WiFI will use core0. It will still multitask.

So i have followed your advice, but displaying data on the OLED crashes as soon as i call the display with display.display().

I also implemented vTaskDelayUntil to make the display of time run only once every second.

here is the task concerned:

void loop0(void * parameter) {

  TickType_t xLastWakeTime;
  const TickType_t xFrequency = 2000;
  // Initialise the xLastWakeTime variable with the current time.
  xLastWakeTime = xTaskGetTickCount();


  for ( ;; )
  {
    // Wait for the next cycle.
    vTaskDelayUntil( &xLastWakeTime, xFrequency );


    Serial.print("Running OLED on core: ");
    Serial.println(xPortGetCoreID());

    Serial.print("formatted time is :");
    Serial.println(formattedTime);

    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(2);
    display.setCursor(20, 0);
    display.print(formattedTime);
    //display.display(); // activate this and the crash occurs....
  }
}

So do I have to understand that you cannot call a function outside the task and is there a way to overcome this ?

Does the crash dump give any clues about what is wrong?

Bill, thanks for pointing me out. I entered the backtrace in the exception decoder but it didn't tell me something useful. (which is my fault). Then i decided to put the whole prcoces for obtaining the time and displaying it into the task. It then crashed but told me tat I had way too little stack size. So i increased it to 8000, and now it is running for 5 minutes without crash. Now i can measure how much i actually need, and then decrease the size.

here are the changes:


xTaskCreatePinnedToCore(
    loop0, /* Function to implement the task */
    "Task0", /* Name of the task */
    8000, /* Stack size in words increased from 1000 to 8000 for the time being*/
    NULL, /* Task input parameter */
    0, /* Priority of the task */
    &Task0, /* Task handle. */
    0); /* Core where the task should run */

And here is the revised task code

void loop0(void * parameter) {

  TickType_t xLastWakeTime;
  const TickType_t xFrequency = 1000;
  // Initialise the xLastWakeTime variable with the current time.
  xLastWakeTime = xTaskGetTickCount();
  String formattedTime;
  long rssi;


  for ( ;; )
  {
    // Wait for the next cycle.
    vTaskDelayUntil( &xLastWakeTime, xFrequency );

    timeClient.update();
    formattedTime = timeClient.getFormattedTime();
    rssi = WiFi.RSSI();

    Serial.print("Running OLED on core: ");
    Serial.println(xPortGetCoreID());
    Serial.println(uxTaskGetStackHighWaterMark(NULL));  //print unused stack memory
    delay(1000);

    Serial.print("formatted time is :");
    Serial.println(formattedTime);

    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(2);
    display.setCursor(20, 0);
    display.print(formattedTime);
    display.display();


  }

}

I will now try when I run it from core 1 (move it to loop1).

Everyone who has taken the time to help me, point me, many thanks i learned a lot. This code will be part of an antenna rotor driven by an ESP32, where samples from the antenna position will be taken more frequently than, time updates, and another task will run as near as possible to real-time sensing the switches etc.