0

My plan is to collect data from ESP32's CORE-1 and use ESP32's CORE-0 for all other tasks. However, I see that the variables are not updated properly when multiple cores are used. Here in this example, I see that the value of getAllData is updated only once.


const TickType_t xDelay = 1000 / portTICK_PERIOD_MS;

TaskHandle_t collectData;


bool volatile getAllData;
bool volatile dataReadyToSend;





void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    Serial.flush();
    getAllData = true;
  }
  Serial.print("From loop: ");
  Serial.println(getAllData);
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(getAllData);
    if (getAllData) {
      getAllData=0;
    }
    vTaskDelay( xDelay );
  }  
}

Output of the above code is given below. Where I typed xxx. It is observed that the variable getAllData got updated at this instance, but not changing later.

From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
xxx
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1
From loop: 1
From collectData: 1

UPDATE

Upon suggestions, I used atomic with the following code. Still I see no success.


#ifdef __cplusplus
#include <atomic>
using namespace std;
#else
#include <stdatomic.h>
#endif



TaskHandle_t collectData;



atomic<bool> getAllData;
atomic<bool> dataReadyToSend;


#include "collectData.h"




void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    Serial.flush();
    atomic_store (&getAllData, true);
  }
  Serial.print("From loop: ");
  Serial.println(atomic_load(&getAllData));
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(atomic_load(&getAllData));
    if (atomic_load(&getAllData)) {
      atomic_store (&getAllData, false);
    }
    vTaskDelay( xDelay );
  }
  
  
}

2
  • 1
    volatile doesn't do anything for cross-thread synchronization. Use std::atomic<bool>.. Commented Nov 16, 2021 at 19:03
  • @PeteBecker, I see no success with atomic. I updated the question with the atomic code. Commented Nov 16, 2021 at 19:23

1 Answer 1

1

I found the answer. The problem is not with the variable itself, it is with the Arduino's Serial.flush(). From the version 1.0, arduino is using Serial.flush() to clear the outgoing serial data not the incoming serial data. So, I replaced the Serial.flush() with the following code.


while(Serial.available()) {
  Serial.read();
}

With this update, my code is working good. Thanks to the comment of @PeteBecker, I am using atomic. The final code and results are given below.

#ifdef __cplusplus
#include <atomic>
using namespace std;
#else
#include <stdatomic.h>
#endif



TaskHandle_t collectData;



atomic<bool> getAllData;
atomic<bool> dataReadyToSend;


#include "collectData.h"




void setup() {
  Serial.begin(115200);
  Serial.print("setup() is running on core ");
  Serial.println(xPortGetCoreID());
  xTaskCreatePinnedToCore(collectDataCode,"collectData",10000,NULL,1,&collectData,0);
  delay(500);
}

void loop() {
  if (Serial.available()) {
    while(Serial.available()) {
      Serial.read();
    }
    getAllData.store(true);
    Serial.println("Received data request");
  }
  Serial.print("From loop: ");
  Serial.println(getAllData.load());
  if (dataReadyToSend) {
    dataReadyToSend = false;
  }
  delay(1000);
}



void collectDataCode(void * params) {
  while (1) {
    Serial.print("From collectData: ");
    Serial.println(atomic_load(&getAllData));
    if (getAllData.load()) {
      getAllData.store(false);
    }
    vTaskDelay( xDelay );
  }
  
  
}

Results

From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
.
From loop: 0
From collectData: 0
Received data request
From loop: 1
From collectData: 1
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
From collectData: 0
From loop: 0
Sign up to request clarification or add additional context in comments.

4 Comments

"For some reason, the Serial.flush() is not clearing the Serial.available()" Because flush() flushes the outgoing data, and available() returns the size of incoming data.
@gre_gor, I misunderstood it. Seems very silly. I am sorry to waste time for everyone.
@gre_gor, you contributed more than what I did. If you post the answer, I will select as the accepted answer.
You can just edit yours to clarify the misunderstanding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.