stm32duino/STM32FreeRTOS

Parameters at task startup

nopnop2002 opened this issue · 5 comments

My envronment

I'm using STM32duino FreeRTOS for Platform IO.
stm32duino/STM32duino FreeRTOS@^10.2.1
https://registry.platformio.org/libraries/stm32duino/STM32duino%20FreeRTOS

Content of the problem

The xTaskCreate function allows you to specify parameters for the task.
The same address(=0x2001FFDC) is passed to the task.
However, the contents of the structure are not displayed correctly on the task side.

serial (same as 4)
*****
param address is 0x2001FFDC
Start Scheduler.....
task_parameter address is 0x2001FFDC
task_parameter->ivalue is -3
task_parameter->cvalue is []
task is running
task is running

My code:

#include <Arduino.h>
#include <STM32FreeRTOS.h>

#define BAUDRATE 115200

struct PARAMETER_t{
  int ivalue;
  char cvalue[16];
};

void task(void *pvParameters)
{
  PARAMETER_t *task_parameter = (PARAMETER_t *)pvParameters;
  Serial.print ("task_parameter address is 0x");
  Serial.println ((unsigned int)task_parameter, HEX);
  Serial.print ("task_parameter->ivalue is ");
  Serial.println(task_parameter->ivalue);
  Serial.print ("task_parameter->cvalue is [");
  Serial.print(task_parameter->cvalue);
  Serial.println("]");

  while(1) {
    Serial.println("task is running");
    delay(1000);
  }
}

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("serial (same as 4)");
  Serial.println("*****");

  PARAMETER_t param;
  param.ivalue = 6;
  strcpy(param.cvalue, "serail 6");
  Serial.print("param address is 0x");
  Serial.println ((unsigned int)&param, HEX);
  portBASE_TYPE xTask = xTaskCreate(task, "TASK", configMINIMAL_STACK_SIZE, (void *)&param, 2, NULL);
  configASSERT( xTask );

  // start scheduler
  Serial.println("Start Scheduler.....");
  vTaskStartScheduler();

  Serial.println("Insufficient RAM");
  while(1);
}

void loop() {

}

(EDIT1)
If it is not a structure, it works correctly.

#include <STM32FreeRTOS.h>

#define BAUDRATE 115200

void task(void *pvParameters)
{
  int index = (int)pvParameters;
  Serial.print ("task_parameter is ");
  Serial.println(index);
  char * task = pcTaskGetName(NULL);

  while(1) {
    Serial.print(task);
    Serial.print(" is running:index is ");
    Serial.print(index);
    Serial.println();
    delay(1000);
  }
}

void setup() {
  Serial.begin(BAUDRATE);
  Serial.println("serial (same as 4)");
  Serial.println("*****");

  int index;
  index = 0;
  portBASE_TYPE xTask0 = xTaskCreate(task, "TASK0", configMINIMAL_STACK_SIZE, (void*)index, 2, NULL);
  configASSERT( xTask0 );

  index = 1;
  portBASE_TYPE xTask1 = xTaskCreate(task, "TASK1", configMINIMAL_STACK_SIZE, (void*)index, 2, NULL);
  configASSERT( xTask1 );

  // start scheduler
  Serial.println("Start Scheduler.....");
  vTaskStartScheduler();

  Serial.println("Insufficient RAM");
  while(1);
}

void loop() {
  // Empty. Things are done in Tasks.
}

Hi @nopnop2002,
Problem is not the structure, but the fact that your structure is a local variable.
If you define PARAMETER_t param;
as a global variable, it will work properly.

If it is not a struct, even local variables will work correctly.

  int index;
  index = 0;
  portBASE_TYPE xTask0 = xTaskCreate(task, "TASK0", configMINIMAL_STACK_SIZE, (void*)index, 2, NULL);
  configASSERT( xTask0 );

  index = 1;
  portBASE_TYPE xTask1 = xTaskCreate(task, "TASK1", configMINIMAL_STACK_SIZE, (void*)index, 2, NULL);
  configASSERT( xTask1 );

Why should it be a global variable only for structs?

I don't said to use global variable only for struct, but rather to use global variable in all cases.
From my point of view it is by chance that it works with index local variable.
My understanding: when you use a local variable, this variable is put in stack.
But as soon as this local variable is no more used (it means after the return from xTaskCreate()) , the compiler have the ability to overwrite it for any stack usage.
So there is no warranty on the content of the vairable when executing task() which run after xTaskCreate() (after calling vTaskStartScheduler())

It is perfectly explained by the documentation:
https://www.freertos.org/a00125.html

pvParameters A value that is passed as the paramater to the created task.
If pvParameters is set to the address of a variable then the variable must still exist when the created task
executes - so it is not valid to pass the address of a stack variable.

so it is not valid to pass the address of a stack variable.

I understood.