Why am I getting a wrong parameter from a FreeRTOS task in class

150 views Asked by At

My problem:

I want to hand over parameters to a FreeRTOS task in a class. I am using the ESP32 board with the Arduino IDE. I get 0.00 as output at trying this. Here is a code sample:

class testClass {
  public:
    testClass(/*parameters*/){
      //Do some stuff...
    }
  private:
    TaskHandle_t testTask;

    static void testTaskFunction (void * pvParameters) {
      float *number = (float *) pvParameters; 

      String stringifiedNumber;
      stringifiedNumber = String(*number);

      Serial.println(stringifiedNumber); // Output 2
      Serial.println(*number); // Output 3

      vTaskDelete(NULL); // Must be there, otherwise there will be an error because the function is finished but the task still exists. Here the task is deleted and the function is aborted.
    }

  public:
    void testFunction (float number) {
      Serial.println(number); // Output 1

      xTaskCreatePinnedToCore(
        testTaskFunction, // Function to implement the task 
        "testTask", // Name of the task
        10000,  // Stack size in words
        (void *) &number,  // Task input parameter
        2,  // Priority of the task
        &testTask,  // Task handle.
        0); // Core where the task should run
    }
};

testClass testInstance1;
testClass testInstance2;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:  
  for (float i = -20; i < 30; i += 0.1) {
    testInstance1.testFunction(i);
    delay(1000);
    testInstance2.testFunction(i + 21);
    delay(1000);
  }
}

The Output (without comments):

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1416
load:0x40078000,len:14804
load:0x40080400,len:4
load:0x40080404,len:3356
entry 0x4008059c
-20.00 // Output 1 (testInstance1)
0.00 //   Output 2 (testInstance1)
0.00 //   Output 3 (testInstance1)
1.00 //   Output 1 (testInstance2)
0.00 //   Output 2 (testInstance2)
0.00 //   Output 3 (testInstance2)
-19.90 // ...
0.00
0.00
1.10
0.00
0.00
-19.80
0.00
0.00
1.20
0.00
0.00
-19.70
0.00
0.00
1.30
0.00
0.00
-19.60
0.00
0.00
1.40
0.00
0.00
-19.50
0.00
0.00
1.50
0.00
0.00
-19.40
0.00
0.00
1.60
0.00
0.00
-19.30
0.00
0.00
1.70
0.00
0.00

What I've tried:

I've removed the other instance of the class and voilĂ , it works. But that is no possible solution for me. I've also tried to change the duration of the delay, but that did not work.

Can you say what I'm doing wrong? Please help me.

2

There are 2 answers

1
Pr77Pr77 On BEST ANSWER

Thanks to @B. Pantalone. He gave me the information, why I'm getting 0.00. The right solution for me is the following:

class testClass {
  public:
    testClass(/*parameters*/){
      //Do some stuff...
    }
  private:
    TaskHandle_t testTask;

    static void testTaskFunction (void * pvParameters) {
      float *number = (float *) pvParameters; 

      String stringifiedNumber;
      stringifiedNumber = String(*number);

      Serial.println(stringifiedNumber);
      Serial.println(*number);

      vTaskDelete(NULL); // Must be there, otherwise there will be an error because the function is finished but the task still exists. Here the task is deleted and the function is aborted.
    }

    float numberInClass;
  public:
    void testFunction (float number) {
      numberInClass = number;
      Serial.println(numberInClass);
      xTaskCreatePinnedToCore(
        testTaskFunction, // Function to implement the task 
        "testTask", // Name of the task
        10000,  // Stack size in words
        (void *) &numberInClass,  // Task input parameter
        2,  // Priority of the task
        &testTask,  // Task handle.
        0); // Core where the task should run
    }
};

testClass testInstance1;
testClass testInstance2;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:  
  for (float i = -20; i < 30; i += 0.1) {
    testInstance1.testFunction(i);
    delay(2000);
    testInstance2.testFunction(i + 21);
    delay(2000);
  }
}

I am saving the number in a variable inside the class (numberInClass).

Please note, that this is not the perfect solution for every use because if the class gets destructed right after creating the task, there would be the same problem.

1
B. Pantalone On

In testFunction you pass the address of number as your task input parameter, but number resides on the stack. When your task executes, that value on the stack is long gone. Try passing number by value.