Passing struct as parameter to FreeRTOS task

I have a simple single task FreeRTOS application which can turn the built in LED on and off. This works perfectly if the values of the pin number and the on/off period are hard coded with the task.

I now want to use multiple instances of a single task to control multiple digital outputs and so I am passing a pin number and on/off period as a strut input to the task. The struct is defined as below:

struct beacon_params {
TickType_t cycleTime;
uint8_t pinNumber;
};

When the task method is called, the first member of the struct has the correct value, the second does not have the correct value. If I swap the order of the elements of the struct, then what is now the first parameter is correct.

The issue is the same on Micro, Uno and Mega 2560 and whether I use Visual Studio with VMicro extension or the Arduino UI.

The issue is something to do with alignment of the struct elements but I can't seem to get any pragmas or compiler options to get both parameters into the beacon task function with the correct value.

Any help / suggestions would be very much apreciated.

The complete sketch is attached and the required and actual value are written to the serial port during sketch exection.

struct-issue.ino (1.69 KB)

See the freeRTOS api for more information FreeRTOS API categories

QueueHandle_t xQ_Posit;
struct stuPosit
{
  float Lat = 0.0;
  float Lon = 0.0;
  float Alti = 0.0;
  float MPH = 0.0;
  float KPH = 0.0;
  float Hdg = 0.0;
} xPosit;

Notice the creation of a Queue handle above the structure declaration.
In setup()

 xQ_Posit = xQueueCreate ( 1, sizeof(stuPosit) );

That line creates a queue bound to the structure through a name, sized to your structure, and will be a copy passed, not the original, to the task. This works on one core or multi cores. The '1' represents how many queues will be in use at any one time.

Here you will see the structure being received.

void fGPS_Log ( void *pvParameters )
{
  struct stuPosit pxPosit;
  int iBit = 1;
  for ( ;; )
  {
    xEventGroupWaitBits (eg, evtGPS_Log, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( xSemaphoreTake( sema_GPS_Log, xTicksToWait0 ) == pdTRUE ) // grab semaphore no wait
    {
      iBit = iBit << 1;
      if ( iBit < 0 )
      {
        //        fMakeTimeStamp ( localBuffer );
        xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait );
        xQueueReceive ( xQ_Posit, &pxPosit, QueueReceiveDelayTime ) ;
        xSemaphoreGive( sema_Posit );

Here, in another task, on the other core, the structure, declared in the decelration section, is filled, and a copy is sent away.

 if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
          {
            xQueueOverwrite( xQ_Posit, (void *) &xPosit );
            xSemaphoreGive( sema_Posit );
          }

Take care here, because I only have one queue and if the previous queue is not in use, then overwrite the single queue. If more then one queue do not use the overwrite.

Thanks for your response. All working now :slight_smile:

I had made a couple of silly mistakes when compared to your code setting up the parameters and converting them to "void *". Most notably the position of the * (it's ages since I did any C pointers, let alone C++) and also having a type and a variable with the same name confused things.