Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

Send a struct through Queue

Posted by xico2004 on August 18, 2015

Hi there

I am new to this forum and I am already bring some problems that I have been facing while exploring FreeRTOS on my STM32F4:

I want to pass a simple structure from one task to anoder. Actually am I followyig by the book (I think....) what is told on FreeRTOS API suport: This is shortest example fo what I am doing:

	#define WHEEL_PERIMETER    100

    struct ENCODER_Motion 
	{
		float    Current_Speed;
		float    Current_Direction;
	} ENCODER_MOTION_Read;

    QueueHandle_t     xQueueENCODER_Readings;

    int main (void)
	{
		... Initiate system configuration ...

		xQueueENCODER_Readings  = xQueueCreate( 10  , sizeof( struct ENCODER_Motion* ) );

		if ( xQueueENCODER_Readings == 0)
			... flags with a flashing led;

        ... creates Task_A and Task_B and lauches scheduler....

		while (1);
    }

    void Task:A ( void *pvParameters ) 
	{
        struct		ENCODER_Motion   *ENCODER_MOTION_NOW;

        float RPM ;
        float DIRECTION ;

        while (1)
        {
            ... Reads Encoder to RPM and DIRECTION ...

            ENCODER_MOTION_Read.Current_Speed = RPM * WHEEL_PERIMETER;
            ENCODER_MOTION_Read.Current_Direction = DIRECTION;

            if ( xQueueENCODER_Readings != 0 ) 
            {
                ENCODER_MOTION_NOW = &ENCODER_MOTION_Read;	
                xQueueSend ( xQueueENCODER_Readings , (void *) &ENCODER_MOTION_NOW , 
                                         (TickType) 10 );
            }

        }

    void Task:B ( void *pvParameters ) 
	{
        struct		ENCODER_Motion   *ENCODER_Received;
        float SPEED_RECEIVED;
        float DIRCTION_RECEIVED;

        while (1)
        {
            if ( xQueueENCODER_Readings )
                {
                    if ( uxQueueMessagesWaiting ( xQueueENCODER_Readings ) )	
                    {
                        if (xQueueReceive ( xQueueENCODER_Readings , &(ENCODER_Received) , 
                                                        QUEUE_TIME_TO_WAIT_10 ) );
                        {
                            SPEED_RECEIVED = ENCODER_Received->Current_Speed;
                            DIRCTION_RECEIVED = ENCODER_Received->Current_Direction;
                        }

				}
			}
        }

My problems that; passing the struck though the queue or not (not calling the xQueueSend on TaskA) I still receive on TASKB the information saved at this point of may code

            ENCODER_MOTION_Read.Current_Speed = RPM * WHEEL_PERIMETER;
            ENCODER_MOTION_Read.Current_Direction = DIRECTION;

It seems I am saving the data on a Global variable (structure) and not sending a pointer to a strcuture - one of the 10 that was created when I called xQueueCreat.

I tryed not using pointer on the TASK_B but it receives trash.

Any help will be highly appreciated Thanks


Send a struct through Queue

Posted by rtel on August 18, 2015

In your code you are only creating one structure, then sending pointers to that one structure through the queue. All the pointers will be pointing to the same structure, and reading anything out from the structure will result in whatever value was last written to the structure by any task (all tasks are accessing the same one). Is this correct?

If the structure is small you might be better of sending the structure itself, so each time you send the structure to the queue you send a copy of a strcture, rather than a pointer to a single structure. So the queue would be created as:

// The * has been removed xQueueENCODERReadings = xQueueCreate( 10 , sizeof( struct ENCODERMotion) );

Then Task a can do this to send a copy of its local variable, rather than a pointer to it, to the queue

void Task:A ( void *pvParameters ) 
{
    struct      ENCODER_Motion   ENCODER_MOTION_NOW;
    
    for( ;; )
    {
        ENCODER_MOTION_NOW.Current_Speed = // whatever
        ENCODER_MOTION_NOW.Current_Direction = // whatever
    
        // Send a copy of the queue to the other task.
        xQueueSend ( xQueueENCODER_Readings , 
                    (void *) &ENCODER_MOTION_NOW , 
                    (TickType) 10 );
        
        // Reset of code follows

And Task B can receive a copy into its own local variable, as follows:

void Task:B ( void *pvParameters ) 
{
struct      ENCODER_Motion   ENCODER_Received;

    while (1)
    {
        if (xQueueReceive ( xQueueENCODER_Readings , 
                           &(ENCODER_Received) , 
                           QUEUE_TIME_TO_WAIT_10 ) );
                           
        // Reset of code follows

I think if you wanted to queue pointers, maybe for efficiency reasons, then you would have to have a set of structures available that could be pointed to, so no two tasks point to the same structure at the same time - or perhaps dynamically allocate a structure then send a pointer to the dynamically allocated structure, and have the receiving task free the dynamically allocated structure again after it has received it.

Regards.


Send a struct through Queue

Posted by xico2004 on August 19, 2015

Thank you so much for your reply. Your solution worked perfectly! Thank you again.

Indeed I was intending to use pointers due to efficiency issues. Actually the example above was the smallest and maybe the simpliest situation.

This is the first time I saw this kind of buggy behaviour - accessing globaly to the same structure through those pointers which were indeed pointing precisely to the same strucutre.

In my aplication I need to pass arge structures from TASKA, TASKB and TASKC to TASKD and this last one will gather all information and process it.

I was trying to use a single Queue, common to all tasks A, B and C, which will be used to send the data to task D.

The strucutre has a sort of task ID to identify from where that information came.

So please confirm if I undertood it right: it is recomended to create several structures associated to each task A, B and C. Then send each pointer through the same queue to task D.

Thank you once again for your important support Regards


Send a struct through Queue

Posted by edwards3 on August 19, 2015

If you want to send pointers to structures then you can create a pool of structures, and tag each structure as available or in use

define MAX_STRUCTS 5

// The pool of structs ENCODERMOTIONRead mystructs[ MAXSTRUCTS ];

// Available flags bool isinuse[ MAX_STRUCTS ] = { false };

ENCODERMOTIONRead *get_struct(void){ int i;

// Find the next free struct
for(i=0; i<MAX_STRUCTS; i++){
    if(is_in_use[i]==false){
	   // Mark struct in use and return it
	   is_in_use[i]=true;
	   return &my_structs[i];
	}
}

// All in use
return NULL;

}

void freestruct(ENCODERMOTIONRead *torelease){ int i;

// Find the struct being freed
for(i=0; i<MAX_STRUCTS; i++){
    if(to_release==&my_structs[i]){
	   // Mark struct not in use
	   is_in_use[i]=false;
	   return;
	}
}

}

To send a pointer to a structure, call get_struct to get a struct from the pool, fill the struct with data, then send a pointer to the struct to the queue.

At the other end of the queue, read out the data from the struct, then call free_struct() to return the stuct to the pool.

This implementation is very crude but ok if MAX_STRUCTS is small.


Send a struct through Queue

Posted by richard_damon on August 19, 2015

If each task is sending the same sort of data, there is no need for multiple queues, and in fact multiple queues can make you life harder. My general rules as each source of asyncronous data should have a single task dedicated to it.

Whether to send a structure or a pointer is largely dependent on how much data is in the structure. Two floats isn't bad. Sending structures is simpler in that you normally don't need to deal with life management of the data structures. Passing pointers may be quicker if there is much data in the structure, OR if the structure deals with pointers to itself or other data buffers.

(And when dealing wth pointers to buffers, I find the simplest way to keep track of the free buffers is to put the pointers into another queue, that you take from to get a buffer and put to in order to free a buffer)


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists