Search code examples
c++multithreadingarduinoesp32arduino-ide

Use variables with both cores and tasks ESP32


Im trying to read data from an i2c device, which is recieved by core 0, then that data is stored into some global values, and then those values are readed by the core 1, and then printed out. The problem is whenever the core 0 tries to access those variables, it outputs "guru meditation error core 0 panic'ed (loadprohibited). exception was unhandled". What is the way in which the 2 cores can communicate to one another?

TaskHandle_t Task1;
TaskHandle_t Task2;
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads; 
volatile int16_t adc0, adc1, adc2, adc3;
volatile float volts0, volts1, volts2, volts3;
void setup() {
  Serial.begin(115200); 
  delay(1000);
  Serial.println("Hello!");
  Serial.println("Getting single-ended readings from AIN0..3");
  Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115");
  //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
  xTaskCreatePinnedToCore(
                    Task1code,   /* Task function. */
                    "Task1",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &Task1,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */                  
  delay(500); 

  //create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
  xTaskCreatePinnedToCore(
                    Task2code,   /* Task function. */
                    "Task2",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    2,           /* priority of the task */
                    &Task2,      /* Task handle to keep track of created task */
                    1);          /* pin task to core 1 */
    delay(500); 
    if (!ads.begin()) {
    Serial.println("Failed to initialize ADS.");
    while (1);
  }
}

void Task1code( void * pvParameters ){
  for(;;){
  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
adc0 = ads.readADC_SingleEnded(0);
  adc1 = ads.readADC_SingleEnded(1);
  adc2 = ads.readADC_SingleEnded(2);
  adc3 = ads.readADC_SingleEnded(3);

  volts0 = ads.computeVolts(adc0);
  volts1 = ads.computeVolts(adc1);
  volts2 = ads.computeVolts(adc2);
  volts3 = ads.computeVolts(adc3);
  delay(100);
  }
}

void Task2code( void * pvParameters ){
  delay(500);
  Serial.print("Task2 running on core ");
  Serial.println(xPortGetCoreID());

  for(;;){}{
    Serial.println("-----------------------------------------------------------");
  Serial.print("AIN0: "); Serial.print(adc0); Serial.print("  "); Serial.print(volts0); Serial.println("V");
  Serial.print("AIN1: "); Serial.print(adc1); Serial.print("  "); Serial.print(volts1); Serial.println("V");
  Serial.print("AIN2: "); Serial.print(adc2); Serial.print("  "); Serial.print(volts2); Serial.println("V");
  Serial.print("AIN3: "); Serial.print(adc3); Serial.print("  "); Serial.print(volts3); Serial.println("V");
  delay(100);
  }
}

void loop() {
  
}

Solution

  • You can create a semaphore and take it when try to access the variable. If you done accessing it, you can give it back. When you take a semaphore, other code blocks will wait for the other to give it back. You can configure the time it should wait for a given semaphore. Here is a (link) explaining in more details.

    Here is an example:

    SemaphoreHandle_t i2cSemaphore;
    void createSemaphore(){
        i2cSemaphore = xSemaphoreCreateMutex();
        xSemaphoreGive( ( i2cSemaphore) );
    }
    
    // Lock the variable indefinietly. ( wait for it to be accessible )
    void lockVariable(){
        xSemaphoreTake(i2cSemaphore, portMAX_DELAY);
    }
    
    // give back the semaphore.
    void unlockVariable(){
        xSemaphoreGive(i2cSemaphore);
    }
    
    TaskHandle_t Task1;
    TaskHandle_t Task2;
    #include <Adafruit_ADS1X15.h>
    Adafruit_ADS1015 ads; 
    volatile int16_t adc0, adc1, adc2, adc3;
    volatile float volts0, volts1, volts2, volts3;
    void setup() {
      Serial.begin(115200); 
      delay(1000);
      Serial.println("Hello!");
      Serial.println("Getting single-ended readings from AIN0..3");
      Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115");
      createSemaphore();
      //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
      xTaskCreatePinnedToCore(
                        Task1code,   /* Task function. */
                        "Task1",     /* name of task. */
                        10000,       /* Stack size of task */
                        NULL,        /* parameter of the task */
                        1,           /* priority of the task */
                        &Task1,      /* Task handle to keep track of created task */
                        0);          /* pin task to core 0 */                  
      delay(500); 
    
      //create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
      xTaskCreatePinnedToCore(
                        Task2code,   /* Task function. */
                        "Task2",     /* name of task. */
                        10000,       /* Stack size of task */
                        NULL,        /* parameter of the task */
                        2,           /* priority of the task */
                        &Task2,      /* Task handle to keep track of created task */
                        1);          /* pin task to core 1 */
        delay(500); 
        if (!ads.begin()) {
        Serial.println("Failed to initialize ADS.");
        while (1);
      }
    }
    
    void Task1code( void * pvParameters ){
      for(;;){
      lockVariable();
      Serial.print("Task1 running on core ");
      Serial.println(xPortGetCoreID());
    adc0 = ads.readADC_SingleEnded(0);
      adc1 = ads.readADC_SingleEnded(1);
      adc2 = ads.readADC_SingleEnded(2);
      adc3 = ads.readADC_SingleEnded(3);
    
      volts0 = ads.computeVolts(adc0);
      volts1 = ads.computeVolts(adc1);
      volts2 = ads.computeVolts(adc2);
      volts3 = ads.computeVolts(adc3);
      unlockVariable();
      vTaskDelay(100);
      }
    }
    
    void Task2code( void * pvParameters ){
      delay(500);
      Serial.print("Task2 running on core ");
      Serial.println(xPortGetCoreID());
    
      for(;;){}{
       lockVariable();
        Serial.println("-----------------------------------------------------------");
      Serial.print("AIN0: "); Serial.print(adc0); Serial.print("  "); Serial.print(volts0); Serial.println("V");
      Serial.print("AIN1: "); Serial.print(adc1); Serial.print("  "); Serial.print(volts1); Serial.println("V");
      Serial.print("AIN2: "); Serial.print(adc2); Serial.print("  "); Serial.print(volts2); Serial.println("V");
      Serial.print("AIN3: "); Serial.print(adc3); Serial.print("  "); Serial.print(volts3); Serial.println("V");
      unlockVariable();
      vTaskDelay(100);
      }
    }
    
    void loop() {
      
    }