Page 1 of 4

Variable doesn't update between cores

Posted: Mon Apr 01, 2019 2:18 am
by spyder0069
I came across this and am looking for some insight. Using arduino to program I have set up two tasks each pinned to a separate core. My application was to check if the core1 stops responding. So in that core I set a variable. In core 0 I check to see if that variable has been set and if so I clear it. However, in this example it does not set the variable unless you have a delay or some other statement also in that loop. Here is the code:

Code: Select all


TaskHandle_t Task0;
TaskHandle_t Task1;

byte variable1=0;
byte variable2=0;


void setup(void) {
  Serial.begin(115200);


  
  //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
  xTaskCreatePinnedToCore(
                    Task0code,   /* Task function. */
                    "Task0",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    2,           /* priority of the task */
                    &Task0,      /* 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(
                    Task1code,   /* Task function. */
                    "Task1",     /* name of task. */
                    10000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    2,           /* priority of the task */
                    // when priority was set to 100 then network scan would not complete
                    &Task1,      /* Task handle to keep track of created task */
                    1);          /* pin task to core 1 */
    delay(500); 
}



void loop() {
  // put your main code here, to run repeatedly:

}



void Task0code( void * pvParameters ){
  delay(1000);
  for (;;){  //create an infinate loop
    //Serial.println("variable1=" + String(variable1));
    if(variable1>0){
      variable1=0;
    }else{
      variable2=1;
    }
    delay(5);

    if(variable2==1){
      Serial.println("error");
      delay(1000);
    }
    
  }
}



void Task1code( void * pvParameters ){
  for (;;){  //create an infinate loop
    variable1=1;    
    //delayMicroseconds(1);
  }
}
Running this code variable1 will always equal zero and give the error. However, if you uncomment the delay in the Task1code it works properly and does not produce an error. Something is funky. Why would it not adjust the variable1 in task1code unless a delay or some other commands are added after it?

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 3:17 am
by WiFive
Compiler thinks it is a dumb thing to do and optimizes it out.

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 5:11 am
by ESP_Angus
More helpful answer: You need to tell the compiler that the variables "variable1", "variable2" may be updated by other running code at any time. Do this by declaring them "volatile byte variable1;", etc.

You can search online for "volatile Arduino" to find some explanations of "volatile" for Arduino programmers. They're usually talking about interrupts, but updating from the other core is similar.

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 5:32 am
by spyder0069
Thank you for the reply. I will look into this. I have been trouble shooting a project of mine which works perfectly fine for days and then sometimes my flag goes off. I suspect this may not be the cause of the problem if this is only having to do with the compiler editing out the code.

My main project will occasional flag that the other core stopped responding because the variable is not incremented. Is there a preferred method for the two cores to do this? If the variable is in the process of being changed in one core and the other core goes to read it will it wait or will there be a corrupted variable?

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 9:55 am
by markkuk
You should be using the task synchronization and communication mechanisms available in ESP-IDF: https://docs.espressif.com/projects/esp ... aphore-api. See also: https://en.wikipedia.org/wiki/Synchroni ... r_science)
Here's a modified version of your code using a binary semaphore:
  1. TaskHandle_t Task0;
  2. TaskHandle_t Task1;
  3.  
  4. SemaphoreHandle_t binsem1;
  5.  
  6. void setup(void) {
  7.   Serial.begin(115200);
  8.  
  9.   // create a binary semaphore for task synchronization
  10.   binsem1 = xSemaphoreCreateBinary();
  11.  
  12.   //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
  13.   xTaskCreatePinnedToCore(
  14.                     Task0code,   /* Task function. */
  15.                     "Task0",     /* name of task. */
  16.                     10000,       /* Stack size of task */
  17.                     NULL,        /* parameter of the task */
  18.                     2,           /* priority of the task */
  19.                     &Task0,      /* Task handle to keep track of created task */
  20.                     0);          /* pin task to core 0 */                  
  21.   delay(500);
  22.  
  23.   //create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
  24.   xTaskCreatePinnedToCore(
  25.                     Task1code,   /* Task function. */
  26.                     "Task1",     /* name of task. */
  27.                     10000,       /* Stack size of task */
  28.                     NULL,        /* parameter of the task */
  29.                     2,           /* priority of the task */
  30.                     // when priority was set to 100 then network scan would not complete
  31.                     &Task1,      /* Task handle to keep track of created task */
  32.                     1);          /* pin task to core 1 */
  33.     delay(500);
  34. }
  35.  
  36.  
  37.  
  38. void loop() {
  39.   // put your main code here, to run repeatedly:
  40.   delay(1000);
  41. }
  42.  
  43.  
  44.  
  45. void Task0code( void * pvParameters ){
  46.   delay(1000);
  47.   for (;;){  //create an infinate loop
  48.      if(xSemaphoreTake(binsem1, 5) == pdFALSE){
  49.       // the other task didn't give the semaphore within 5 ticks
  50.       Serial.println("error");
  51.       delay(1000);
  52.     }
  53.   }
  54. }
  55.  
  56.  
  57.  
  58. void Task1code( void * pvParameters ){
  59.   for (;;){  //create an infinate loop
  60.     xSemaphoreGive(binsem1);
  61.     delay(1); // prevent the idle task watchdog from triggering
  62.   }
  63. }

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 10:36 am
by username
Something is funky. Why would it not adjust the variable1 in task1code unless a delay or some other commands are added after it?
You need to read more on how a RTOS operates. You have both tasks assigned the same priority, which is not a bad thing, you just need to understand more about it is all. Essentially, both tasks will be given equal priority to run on the cpu. When you don't add a delay in each task you never tell the RTOS "hey I am done here for a bit, take a breath and see if anyone else needs some CPU time. "
So whats winds up happening is its basically spending most of its time in Task1code.

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 1:54 pm
by spyder0069
"So whats winds up happening is its basically spending most of its time in Task1code."

Why? Each task is assigned a different core. Both tasks should be running independently shouldn't they? Since they are on seperate cores I don't actually need anything in the loop correct?

Doe priority matter between my two tasks at that point since the tasks should not be competing against each other? I assumed it was only against what was also set for each core which for core1 which I thought has nothing else running and core0 the wifi and background tasks?

My project is using core1 to check a pin which is handling zero crossing of the AC mains. This needs to be uninterrupted but also get settings from my program running in core0. Core0 has all the interruptions from the wifi and other things happening in the background but the code running there is ok with that.

I

Re: Variable doesn't update between cores

Posted: Mon Apr 01, 2019 1:56 pm
by spyder0069
"create a binary semaphore for task synchronization"

Doe this need to occur even though both tasks are running on separate cores? Shouldn't they both be able to just freely run?

Re: Variable doesn't update between cores

Posted: Tue Apr 02, 2019 9:09 am
by markkuk
Threads can run freely as long as they don't try to access shared variables. When threads need to communicate with each other it's best to use the methods provided by the operating system (FreeRTOS/ESP-IDF in this case) instead of trying to re-invent the necessary synchronization and locking routines through trial and error.

Re: Variable doesn't update between cores

Posted: Tue Apr 02, 2019 10:45 am
by username
Why? Each task is assigned a different core. Both tasks should be running independently shouldn't they? Since they are on seperate cores I don't actually need anything in the loop correct?
That would be true if you had 2 clock sources with one for each core. Think of it like you PC. you have multiple cores there. Yet if you overtask one of your cores, all other applications you have running will get get bogged down.

Loop is a task as well, having no delay in there is going to bog other tasks as well.