Search code examples
coperating-systemtaskfreertos

Why can I pass an integer as a task parameter but can't pass a struct variable?


I was trying to pass a set of parameters to a task. So I created a struct and passed it to my task, like this:

my_type_t parameters_set;

//... assigning values to parameters_set

xTaskCreate( vMyTask, "MyTask", STACK_SIZE, (void*)parameters_set, 2,
 &xHandle);

Inside my task I tried to retrieve the struct values doing the following:

my_type_t received_parameters = (my_type_t) pvParameters;

The task creation line triggers the following error while compiling: "cannot convert to a pointer type" and the struct retrieving line triggers the "Conversion to non-scalar type requested" error. I know if I use a pointer instead of the variable itself it will compile, but I can't do this because the function that creates the task will die and the task will have a reference to a variable that does not exist anymore. In the end I'll use a global struct variable.

But what I really would like to understand is why do tasks accept int values (not by reference), and don't accept a typedef struct? For example, the following snippet builds and works without problem:

//Inside the function that creates the task
int x = 0;

xTaskCreate( vMyTask, "MyTask", STACK_SIZE, (void*)x, 2,
 &xHandle);

//Inside the Task
int received_parameter = (int) pvParameters;

Thanks in advance!


Solution

  • The code you show is not taking an int value as a parameter. You pass the parameter using (void*)x, which is an expression that converts the int x to a pointer.

    The function xTaskCreate accepts a pointer. You have given it a pointer, so the compiler does not complain. However, the pointer you have given it is not a pointer to x (which would be written as &x) but is a pointer converted from the value of x. Although the compiler does not complain, this is generally not the right thing to pass to xTaskCreate.

    The reason this is not working with a structure is that (void*)parameters_set is not a proper expression when parameters_set is a structure. This is because C provides for integers to be converted to pointers but not for structures to be converted to pointers. Generally, there is a natural correspondence between integers and pointers: In a “flat” address space, every byte in memory has an address, and those addresses are essentially counts of bytes from the “start” of the memory address space. So an integer can serve as an address and vice-versa. (In other address spaces, the correspondence may be more complicated, but C still allows the conversions, with some rules.) Thus, when you write (void*)x, the compiler converts the integer value in x to a pointer.

    There is no such correspondence between structures and pointers, so the C standard does not define any conversion from structures to pointers, and the compiler complains when you write (void*)parameters_set.

    What you should be passing for this parameter is the address of some data to be given to the task. If you want the task to have the data in x, you should pass &x. If you want the task to have the data in parameters_set, you should pass &parameters_set. The & operator takes the address of its operand, which is different from using the (void*) cast, which attempts to convert its operand to a pointer.

    According to the RTOS documentation for xTaskCreate, you should not pass the address of a “stack variable,” by which it effectively means, for C, an object with automatic storage duration. In other words, you should not pass an x or parameters_set that is defined within a function without static or (possibly, depending on arrangements made by RTOS and the C implementation; I am unfamiliar with RTOS) _Thread_local. Alternatively, you can allocate space for the parameters using malloc (or, per comment below, pvPortMalloc for RTOS) and pass that to xTaskCreate.