Search code examples
c++esp32freertos

ESP32 not updating the variable when multiple cores are used


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 );
  }
  
  
}


Solution

  • 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